<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Feed for Fight With Tools - Aram's Dev Blog</title>
	<atom:link href="https://fightwithtools.dev/rss/" rel="self" type="application/rss+xml" />
	<link>https://fightwithtools.dev/</link>
	<description>Notes on various projects</description>
	<lastBuildDate>Mon, 16 Feb 2026 18:33:11 GMT</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>https://11ty.dev/</generator>
	<managingEditor>
		aramdevblog@aramzs.me (Aram Zucker-Scharff)
	</managingEditor>
	
	<item>
		<title>XYZ Site - Day 19 - Setting up the tools for writing to ATProto</title>
		<link>https://fightwithtools.dev/posts/projects/aramzsxyz/day-19-setting-up-tools-for-atproto-sync/?source=rss</link>
		<pubDate>Sun, 15 Feb 2026 15:01:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/projects/aramzsxyz/day-19-setting-up-tools-for-atproto-sync/</guid>
		<description>Getting my blog posts set up in the atmosphere</description>
		<content:encoded><![CDATA[<h2 id="project-scope-and-todos" tabindex="-1">Project Scope and ToDos</h2>
<ol>
<li>Create a versatile blog site</li>
<li>Create a framework that makes it easy to add external data to the site</li>
</ol>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Give the site the capacity to replicate the logging and rating I do on Serialized and Letterboxd.</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Be able to pull down RSS feeds from other sites and create forward links to my other sites</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Create forward links to sites I want to post about.</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Create a way to pull in my Goodreads data and display it on the site</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Create a way to automate pulls from other data sources</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Combine easy inputs like text lists and JSON data files with markdown files that I can build on top of.</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Add a TMDB credit to footer in base.njk</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Make sure tags do not repeat in the displayed tag list.</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Get my Kindle Quotes into the site</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> YouTube Channel Recommendations</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Minify HTML via Netlify plugin.</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Log played games</li>
</ul>
<h2 id="day-19" tabindex="-1">Day 19</h2>
<p>Ok, so I'm going to start setting up the unit tests now to build up to the functionality I want.</p>
<p>Here's the first two, initiating my connection and getting posts:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/aramzsxyz/day-19-setting-up-tools-for-atproto-sync/#code-skip-day-19-setting-up-tools-for-atproto-sync-8" id="skip-to-code-skip-day-19-setting-up-tools-for-atproto-sync-8" class="skip-link">Skip code block ▼</a></p>
<pre class="language-js"><code class="language-js"><span class="token function">test</span><span class="token punctuation">(</span><span class="token string">'checkPDSForPosts returns the correct number of posts'</span><span class="token punctuation">,</span> <span class="token keyword">async</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />	<span class="token keyword">let</span> connectionManager <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token function">getConnection</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token boolean">false</span> <span class="token operator">==</span> connectionManager<span class="token punctuation">)</span> <span class="token punctuation">{</span><br />		<span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">Error</span><span class="token punctuation">(</span><span class="token string">"connection manager failed"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br />	<span class="token punctuation">}</span><br />	<span class="token keyword">const</span> posts <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token function">checkPDSForPosts</span><span class="token punctuation">(</span><span class="token number">10</span><span class="token punctuation">,</span> <span class="token string">'app.bsky.feed.post'</span><span class="token punctuation">,</span> connectionManager<span class="token punctuation">.</span>rpc<span class="token punctuation">,</span> connectionManager<span class="token punctuation">.</span>manager<span class="token punctuation">,</span> connectionManager<span class="token punctuation">.</span>config<span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token function">expect</span><span class="token punctuation">(</span>posts<span class="token punctuation">.</span>length<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toBe</span><span class="token punctuation">(</span><span class="token number">10</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span><span class="token punctuation">)</span><br /><br /><span class="token function">test</span><span class="token punctuation">(</span><span class="token string">'Can get a specific post with getSpecificRecord'</span><span class="token punctuation">,</span> <span class="token keyword">async</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />	<span class="token keyword">let</span> connectionManager <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token function">getConnection</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token boolean">false</span> <span class="token operator">==</span> connectionManager<span class="token punctuation">)</span> <span class="token punctuation">{</span><br />		<span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">Error</span><span class="token punctuation">(</span><span class="token string">"connection manager failed"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token punctuation">}</span><br />	<span class="token keyword">const</span> <span class="token punctuation">{</span> rpc<span class="token punctuation">,</span> manager<span class="token punctuation">,</span> config <span class="token punctuation">}</span> <span class="token operator">=</span> connectionManager<span class="token punctuation">;</span><br />	<span class="token keyword">const</span> rkey <span class="token operator">=</span> <span class="token string">'3kulbtuuixs27'</span><span class="token punctuation">;</span> <span class="token comment">// Replace with a valid rkey</span><br />	<span class="token keyword">const</span> post <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token function">getSpecificRecord</span><span class="token punctuation">(</span>rkey<span class="token punctuation">,</span> rpc<span class="token punctuation">,</span> config<span class="token punctuation">.</span>handle<span class="token punctuation">,</span> <span class="token string">'app.bsky.feed.post'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token function">expect</span><span class="token punctuation">(</span>post<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toBeDefined</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token function">expect</span><span class="token punctuation">(</span>post<span class="token punctuation">.</span>value<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toBeDefined</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />	console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>post<span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token function">expect</span><span class="token punctuation">(</span>post<span class="token punctuation">.</span>value<span class="token punctuation">.</span>createdAt<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toBe</span><span class="token punctuation">(</span><span class="token string">"2024-06-10T14:27:41.118Z"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p id="code-skip-day-19-setting-up-tools-for-atproto-sync-8">This all works well, so we've got the basics.</p>
<p>The next step is to look at function <code>pushOrUpsertPost</code> and get that working.</p>
<p>I was hoping there would be some sort of search function in the PDS, and I'm <a href="https://github.com/bluesky-social/atproto/discussions/2565" target="_blank">not the only one</a>. <a href="https://mozzius.dev/post/3ljlqmchv2b2a" target="_blank">There's a good walkthrough of the basics for the ATmosphere here</a> that is a place to start up, as is <a href="https://atproto.com/specs/data-model" target="_blank">the data model</a>. The protocol does seem to indicate <a href="https://atproto.com/guides/overview#algorithmic-choice" target="_blank">there is no standard for search that exists at the protocol level</a>. There's a <a href="https://lexidex.bsky.dev/" target="_blank">listener</a> for Lexicons. But <a href="https://atproto-browser.vercel.app/" target="_blank">most</a> things are looking for specific posts.</p>
<p>I guess no real option for that other than building my own index, which is not the way to go for this project. I'll have to make sure I save rkey values into the files that they are mapped to.</p>
<p>I'll need to generate TIDs consistently, that should be its own function too, that will let me configure it more effectively.</p>
<p>Let's cover that with tests too:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/aramzsxyz/day-19-setting-up-tools-for-atproto-sync/#code-skip-day-19-setting-up-tools-for-atproto-sync-7" id="skip-to-code-skip-day-19-setting-up-tools-for-atproto-sync-7" class="skip-link">Skip code block ▼</a></p>
<pre class="language-js"><code class="language-js"><span class="token function">test</span><span class="token punctuation">(</span><span class="token string">'can generate a TID consistently with a record'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />	<span class="token keyword">const</span> record <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token literal-property property">date</span><span class="token operator">:</span> <span class="token string">"2024-06-10T14:27:41.118Z"</span> <span class="token punctuation">}</span><span class="token punctuation">;</span><br />	<span class="token keyword">const</span> tid <span class="token operator">=</span> <span class="token function">generateTID</span><span class="token punctuation">(</span>record<span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token function">expect</span><span class="token punctuation">(</span>tid<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toBeDefined</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token keyword">const</span> tid2 <span class="token operator">=</span> <span class="token function">generateTID</span><span class="token punctuation">(</span>record<span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token function">expect</span><span class="token punctuation">(</span>tid<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toBe</span><span class="token punctuation">(</span>tid2<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br /><span class="token function">test</span><span class="token punctuation">(</span><span class="token string">'can generate TIDs without a record'</span><span class="token punctuation">,</span> <span class="token keyword">async</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />	<span class="token keyword">const</span> tid <span class="token operator">=</span> <span class="token function">generateTID</span><span class="token punctuation">(</span><span class="token keyword">null</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token function">expect</span><span class="token punctuation">(</span>tid<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toBeDefined</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token keyword">await</span> <span class="token keyword">new</span> <span class="token class-name">Promise</span><span class="token punctuation">(</span><span class="token parameter">resolve</span> <span class="token operator">=></span> <span class="token function">setTimeout</span><span class="token punctuation">(</span>resolve<span class="token punctuation">,</span> <span class="token number">1000</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token keyword">const</span> tid2 <span class="token operator">=</span> <span class="token function">generateTID</span><span class="token punctuation">(</span><span class="token keyword">null</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token function">expect</span><span class="token punctuation">(</span>tid<span class="token punctuation">)</span><span class="token punctuation">.</span>not<span class="token punctuation">.</span><span class="token function">toBe</span><span class="token punctuation">(</span>tid2<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<h3 id="let's-do-the-insert!" tabindex="-1">Let's do the insert!</h3>
<p id="code-skip-day-19-setting-up-tools-for-atproto-sync-7">Let's run a test to insert the first record:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/aramzsxyz/day-19-setting-up-tools-for-atproto-sync/#code-skip-day-19-setting-up-tools-for-atproto-sync-6" id="skip-to-code-skip-day-19-setting-up-tools-for-atproto-sync-6" class="skip-link">Skip code block ▼</a></p>
<pre class="language-js"><code class="language-js"><span class="token function">test</span><span class="token punctuation">(</span><span class="token string">'update a post with pushOrUpsertPost'</span><span class="token punctuation">,</span> <span class="token keyword">async</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />	<span class="token keyword">let</span> connectionManager <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token function">getConnection</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token boolean">false</span> <span class="token operator">==</span> connectionManager<span class="token punctuation">)</span> <span class="token punctuation">{</span><br />		<span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">Error</span><span class="token punctuation">(</span><span class="token string">"connection manager failed"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token punctuation">}</span><br />	<span class="token keyword">const</span> <span class="token punctuation">{</span> rpc<span class="token punctuation">,</span> manager<span class="token punctuation">,</span> config <span class="token punctuation">}</span> <span class="token operator">=</span> connectionManager<span class="token punctuation">;</span><br />	<span class="token keyword">const</span> lex <span class="token operator">=</span> <span class="token string">'test.record.activity'</span><span class="token punctuation">;</span><br /><br />	<span class="token keyword">const</span> record <span class="token operator">=</span> <span class="token punctuation">{</span><br />		<span class="token literal-property property">$type</span><span class="token operator">:</span> lex<span class="token punctuation">,</span><br />		<span class="token literal-property property">type</span><span class="token operator">:</span> <span class="token string">'test'</span><span class="token punctuation">,</span><br />		<span class="token literal-property property">date</span><span class="token operator">:</span> <span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br />		<span class="token literal-property property">testProject</span><span class="token operator">:</span> <span class="token string">'marksky-pub'</span><span class="token punctuation">,</span><br />		<span class="token literal-property property">testContext</span><span class="token operator">:</span> <span class="token string">'ts-vitest'</span><span class="token punctuation">,</span><br />		<span class="token literal-property property">testOwner</span><span class="token operator">:</span> <span class="token string">'AramZS'</span><br />	<span class="token punctuation">}</span><br /><br />	<span class="token keyword">let</span> result <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token function">pushOrUpsertPost</span><span class="token punctuation">(</span><span class="token boolean">false</span><span class="token punctuation">,</span> rpc<span class="token punctuation">,</span> config<span class="token punctuation">.</span>handle<span class="token punctuation">,</span> lex<span class="token punctuation">,</span> record<span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token function">expect</span><span class="token punctuation">(</span>result<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toBeDefined</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token function">expect</span><span class="token punctuation">(</span>result<span class="token punctuation">.</span>rKey<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toBeDefined</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token function">expect</span><span class="token punctuation">(</span>result<span class="token punctuation">.</span>resultRecord<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toBeDefined</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br /><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p id="code-skip-day-19-setting-up-tools-for-atproto-sync-6">That <a href="https://pdsls.dev/at://did:plc:t5xmf33p5kqgkbznx22p7d7g/test.record.activity/3mewhxxahis3h" target="_blank">worked</a>! We can take the rkey <code>3mewhxxahis3h</code> and pull it in so this gets upsert (hopefully).</p>
<h3 id="let's-do-the-update" tabindex="-1">Let's do the update</h3>
<p>Update the test to:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/aramzsxyz/day-19-setting-up-tools-for-atproto-sync/#code-skip-day-19-setting-up-tools-for-atproto-sync-5" id="skip-to-code-skip-day-19-setting-up-tools-for-atproto-sync-5" class="skip-link">Skip code block ▼</a></p>
<pre class="language-js"><code class="language-js"><span class="token function">test</span><span class="token punctuation">(</span><span class="token string">'update a post with pushOrUpsertPost'</span><span class="token punctuation">,</span> <span class="token keyword">async</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />	<span class="token keyword">let</span> connectionManager <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token function">getConnection</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token boolean">false</span> <span class="token operator">==</span> connectionManager<span class="token punctuation">)</span> <span class="token punctuation">{</span><br />		<span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">Error</span><span class="token punctuation">(</span><span class="token string">"connection manager failed"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token punctuation">}</span><br />	<span class="token keyword">const</span> <span class="token punctuation">{</span> rpc<span class="token punctuation">,</span> manager<span class="token punctuation">,</span> config <span class="token punctuation">}</span> <span class="token operator">=</span> connectionManager<span class="token punctuation">;</span><br />	<span class="token keyword">const</span> lex <span class="token operator">=</span> <span class="token string">'test.record.activity'</span><span class="token punctuation">;</span><br /><br />	<span class="token keyword">const</span> record <span class="token operator">=</span> <span class="token punctuation">{</span><br />		<span class="token literal-property property">$type</span><span class="token operator">:</span> lex<span class="token punctuation">,</span><br />		<span class="token literal-property property">type</span><span class="token operator">:</span> <span class="token string">'test'</span><span class="token punctuation">,</span><br />		<span class="token literal-property property">date</span><span class="token operator">:</span> <span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br />		<span class="token literal-property property">testProject</span><span class="token operator">:</span> <span class="token string">'marksky-pub'</span><span class="token punctuation">,</span><br />		<span class="token literal-property property">testContext</span><span class="token operator">:</span> <span class="token string">'ts-vitest'</span><span class="token punctuation">,</span><br />		<span class="token literal-property property">testOwner</span><span class="token operator">:</span> <span class="token string">'AramZS'</span><span class="token punctuation">,</span><br />		<span class="token literal-property property">insertStatus</span><span class="token operator">:</span> <span class="token string">'upsert'</span><br />	<span class="token punctuation">}</span><br /><br />	<span class="token keyword">let</span> result <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token function">pushOrUpsertPost</span><span class="token punctuation">(</span><span class="token string">'3mewhxxahis3h'</span><span class="token punctuation">,</span> rpc<span class="token punctuation">,</span> config<span class="token punctuation">.</span>handle<span class="token punctuation">,</span> lex<span class="token punctuation">,</span> record<span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token function">expect</span><span class="token punctuation">(</span>result<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toBeDefined</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token function">expect</span><span class="token punctuation">(</span>result<span class="token punctuation">.</span>rKey<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toBeDefined</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token function">expect</span><span class="token punctuation">(</span>result<span class="token punctuation">.</span>resultRecord<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toBeDefined</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br /><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p id="code-skip-day-19-setting-up-tools-for-atproto-sync-5">Looks like this uploaded!</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/aramzsxyz/day-19-setting-up-tools-for-atproto-sync/#code-skip-day-19-setting-up-tools-for-atproto-sync-4" id="skip-to-code-skip-day-19-setting-up-tools-for-atproto-sync-4" class="skip-link">Skip code block ▼</a></p>
<pre class="language-bash"><code class="language-bash">Uploaded activity with rkey: 3mewhxxahis3h <span class="token punctuation">{</span><br />  uri: <span class="token string">'at://did:plc:t5xmf33p5kqgkbznx22p7d7g/test.record.activity/3mewhxxahis3h'</span>,<br />  cid: <span class="token string">'bafyreifkiskhiuv6bf2jrskn2xkdpyi4yf2fq54k56z3gxcaczhkz6jqbu'</span>,<br />  value: <span class="token punctuation">{</span><br />    date: <span class="token string">'2026-02-15T21:25:55.735Z'</span>,<br />    type: <span class="token string">'test'</span>,<br />    <span class="token string">'$type'</span><span class="token builtin class-name">:</span> <span class="token string">'test.record.activity'</span>,<br />    testOwner: <span class="token string">'AramZS'</span>,<br />    testContext: <span class="token string">'ts-vitest'</span>,<br />    testProject: <span class="token string">'marksky-pub'</span><br />  <span class="token punctuation">}</span><br /><span class="token punctuation">}</span></code></pre>
<p id="code-skip-day-19-setting-up-tools-for-atproto-sync-4">But it isn't adding the additional property or changing the date value? It isn't <a href="https://lionsmane.us-east.host.bsky.network/xrpc/com.atproto.repo.getRecord?repo=did:plc:t5xmf33p5kqgkbznx22p7d7g&amp;collection=test.record.activity&amp;rkey=3mewhxxahis3h" target="_blank">on the raw record either</a>.</p>
<p>Hmmm. I had assumed it is possible, but is it not? I see that <a href="https://verdverm.com/blog/adding-record-editing-with-history-to-atprotocol" target="_blank">one coder verdverm created a flow that copies, deletes, and inserts a new version of the record</a>. Nothing in <a href="https://docs.bsky.app/docs/advanced-guides/posts" target="_blank">the posts examples for BlueSky</a>. I'll ask. But this is going well.</p>
<p>Next step will be being able to grab a Markdown file and manipulate it to pull from and push the rkey to. I'll need to handle when it is already there, maybe comparing the values and then only handling updates when the file is changed? After that we'll want to scan a specified directory for markdown files.</p>
<p>I think maybe I need to get the original record, pull the <code>cid</code> from a top-level object like</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/aramzsxyz/day-19-setting-up-tools-for-atproto-sync/#code-skip-day-19-setting-up-tools-for-atproto-sync-3" id="skip-to-code-skip-day-19-setting-up-tools-for-atproto-sync-3" class="skip-link">Skip code block ▼</a></p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span><br />  <span class="token property">"uri"</span><span class="token operator">:</span> <span class="token string">"at://did:plc:t5xmf33p5kqgkbznx22p7d7g/test.record.activity/3mewhxxahis3h"</span><span class="token punctuation">,</span><br />  <span class="token property">"cid"</span><span class="token operator">:</span> <span class="token string">"bafyreifkiskhiuv6bf2jrskn2xkdpyi4yf2fq54k56z3gxcaczhkz6jqbu"</span><span class="token punctuation">,</span><br />  <span class="token property">"value"</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />    <span class="token property">"date"</span><span class="token operator">:</span> <span class="token string">"2026-02-15T21:25:55.735Z"</span><span class="token punctuation">,</span><br />    <span class="token property">"type"</span><span class="token operator">:</span> <span class="token string">"test"</span><span class="token punctuation">,</span><br />    <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"test.record.activity"</span><span class="token punctuation">,</span><br />    <span class="token property">"testOwner"</span><span class="token operator">:</span> <span class="token string">"AramZS"</span><span class="token punctuation">,</span><br />    <span class="token property">"testContext"</span><span class="token operator">:</span> <span class="token string">"ts-vitest"</span><span class="token punctuation">,</span><br />    <span class="token property">"testProject"</span><span class="token operator">:</span> <span class="token string">"marksky-pub"</span><br />  <span class="token punctuation">}</span><br /><span class="token punctuation">}</span></code></pre>
<p id="code-skip-day-19-setting-up-tools-for-atproto-sync-3">and then pass it into a field on the record at <a href="https://docs.bsky.app/docs/api/com-atproto-repo-put-record" target="_blank">swapCommit</a>?</p>
<p>I think that's what I'm seeing in the verdverm example:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/aramzsxyz/day-19-setting-up-tools-for-atproto-sync/#code-skip-day-19-setting-up-tools-for-atproto-sync-2" id="skip-to-code-skip-day-19-setting-up-tools-for-atproto-sync-2" class="skip-link">Skip code block ▼</a></p>
<pre class="language-js"><code class="language-js">  <span class="token keyword">let</span> <span class="token literal-property property">i</span><span class="token operator">:</span> PutRecordInputSchema <span class="token operator">=</span> <span class="token punctuation">{</span><br />    repo<span class="token punctuation">,</span><br />    collection<span class="token punctuation">,</span><br />    rkey<span class="token punctuation">,</span><br />    record<span class="token punctuation">,</span><br />  <span class="token punctuation">}</span><br />  <span class="token keyword">if</span> <span class="token punctuation">(</span>swapCommit<span class="token punctuation">)</span> <span class="token punctuation">{</span><br />    i<span class="token punctuation">.</span>swapCommit <span class="token operator">=</span> swapCommit<br />  <span class="token punctuation">}</span><br />  <span class="token keyword">if</span> <span class="token punctuation">(</span>swapRecord<span class="token punctuation">)</span> <span class="token punctuation">{</span><br />    i<span class="token punctuation">.</span>swapRecord <span class="token operator">=</span> swapRecord<br />  <span class="token punctuation">}</span><br /><br />  <span class="token keyword">return</span> agent<span class="token punctuation">.</span>com<span class="token punctuation">.</span>atproto<span class="token punctuation">.</span>repo<span class="token punctuation">.</span><span class="token function">putRecord</span><span class="token punctuation">(</span>i<span class="token punctuation">)</span></code></pre>
<p id="code-skip-day-19-setting-up-tools-for-atproto-sync-2">Oh wait, my fkup here. Forgot to put the right flow in.</p>
<p>Ok, I now have a full update-record flow for atproto here:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/aramzsxyz/day-19-setting-up-tools-for-atproto-sync/#code-skip-day-19-setting-up-tools-for-atproto-sync-1" id="skip-to-code-skip-day-19-setting-up-tools-for-atproto-sync-1" class="skip-link">Skip code block ▼</a></p>
<pre class="language-js"><code class="language-js"><br /><span class="token keyword">export</span> <span class="token keyword">const</span> <span class="token function-variable function">generateTID</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter"><span class="token literal-property property">record</span><span class="token operator">:</span> any</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />	<span class="token keyword">let</span> <span class="token literal-property property">recordDate</span><span class="token operator">:</span> Date<span class="token punctuation">;</span><br />	<span class="token keyword">if</span> <span class="token punctuation">(</span>record<span class="token punctuation">)</span><span class="token punctuation">{</span><br />		recordDate <span class="token operator">=</span> record<span class="token punctuation">.</span>date <span class="token operator">?</span> <span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span>record<span class="token punctuation">.</span>date<span class="token punctuation">)</span> <span class="token operator">:</span> <span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span><br />		recordDate <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token punctuation">}</span><br />	<span class="token keyword">let</span> recordInMS <span class="token operator">=</span> recordDate<span class="token punctuation">.</span><span class="token function">getTime</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// This returns ms right?</span><br />	<span class="token comment">// needs to go from milliseconds to microseconds.</span><br />	<span class="token keyword">return</span> <span class="token constant">TID</span><span class="token punctuation">.</span><span class="token function">create</span><span class="token punctuation">(</span>recordInMS <span class="token operator">*</span> <span class="token number">1000</span><span class="token punctuation">,</span> <span class="token constant">CLOCK_ID</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span><br /><br /><span class="token keyword">export</span> <span class="token keyword">const</span> <span class="token function-variable function">putRecord</span> <span class="token operator">=</span> <span class="token keyword">async</span> <span class="token punctuation">(</span><span class="token parameter"><span class="token literal-property property">input</span><span class="token operator">:</span> any</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token keyword">await</span> <span class="token function">ok</span><span class="token punctuation">(</span>rpc<span class="token punctuation">.</span><span class="token function">post</span><span class="token punctuation">(</span><span class="token string">'com.atproto.repo.putRecord'</span> <span class="token keyword">as</span> any<span class="token punctuation">,</span> <span class="token punctuation">{</span><br />			input<br />		<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br /><span class="token keyword">export</span> <span class="token keyword">const</span> <span class="token function-variable function">pushOrUpsertPost</span> <span class="token operator">=</span> <span class="token keyword">async</span> <span class="token punctuation">(</span><span class="token parameter"><span class="token literal-property property">origRkey</span><span class="token operator">:</span> string <span class="token operator">|</span> <span class="token boolean">false</span><span class="token punctuation">,</span> <span class="token literal-property property">rpc</span><span class="token operator">:</span> Client<span class="token punctuation">,</span> <span class="token literal-property property">handle</span><span class="token operator">:</span> string<span class="token punctuation">,</span> <span class="token literal-property property">collection</span><span class="token operator">:</span> string<span class="token punctuation">,</span> <span class="token literal-property property">recordData</span><span class="token operator">:</span> any</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />	<span class="token comment">//Creates that unique key from the startTime of the activity so we don't have duplicates</span><br />	<span class="token keyword">let</span> rKey <span class="token operator">=</span> origRkey <span class="token operator">?</span> origRkey <span class="token operator">:</span> <span class="token function">generateTID</span><span class="token punctuation">(</span>recordData<span class="token punctuation">)</span><br />	<span class="token keyword">let</span> newRecord <span class="token operator">=</span> origRkey <span class="token operator">?</span> <span class="token boolean">false</span> <span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">;</span><br />	console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">Using rkey: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>rKey<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">. New status: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>newRecord<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token comment">//let resultRKey = rKey;</span><br />	<span class="token keyword">let</span> resultRecord<span class="token punctuation">;</span><br />	<span class="token keyword">let</span> inputObj <span class="token operator">=</span> <span class="token punctuation">{</span><br />				<span class="token literal-property property">repo</span><span class="token operator">:</span> handle<span class="token punctuation">,</span><br />				collection<span class="token punctuation">,</span><br />				<span class="token literal-property property">rkey</span><span class="token operator">:</span> rKey<span class="token punctuation">,</span><br />				<span class="token literal-property property">record</span><span class="token operator">:</span> recordData<span class="token punctuation">,</span><br />			<span class="token punctuation">}</span><br /><br />	<span class="token keyword">if</span><span class="token punctuation">(</span><span class="token operator">!</span>newRecord<span class="token punctuation">)</span><span class="token punctuation">{</span><br />		<span class="token comment">// resultRecord = await getSpecificRecord(rKey, rpc, handle, collection);</span><br />		console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'updating record'</span><span class="token punctuation">)</span><br />		resultRecord <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token function">putRecord</span><span class="token punctuation">(</span>inputObj<span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span><br />		resultRecord <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token function">putRecord</span><span class="token punctuation">(</span>inputObj<span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token punctuation">}</span><br />	console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">Uploaded activity with rkey: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>rKey<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span> resultRecord<span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token keyword">return</span> <span class="token punctuation">{</span>rKey<span class="token punctuation">,</span> resultRecord<span class="token punctuation">}</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
<p id="code-skip-day-19-setting-up-tools-for-atproto-sync-1">On the ATProto Touchers discord, user Nelind gave me the heads up on what swap is used for:</p>
<blockquote>
<p>swapRecord and swapCommit essentially say &quot;only perform this update if ...&quot; swapRecord being if the current value of the record is the value provided and swapCommit being if the current commit has the CID provided</p>
<p>basically you can say you only want to update if no other client has changed either the record you want to update or the repo as a whole since last you saw it</p>
<p>you use it to avoid overriding changes other sessions have made or write invalid data due to changes to other records that other sessions have made</p>
</blockquote>
<p>Useful and good to know. Maybe this is something I'll want to use if I want a more complex but foolproof updating flow.</p>
]]></content:encoded>
	</item>
	
	<item>
		<title>XYZ Site - Day 18 - What does an ATProto update look like.</title>
		<link>https://fightwithtools.dev/posts/projects/aramzsxyz/day-18-what-does-an-atproto-update-look-like/?source=rss</link>
		<pubDate>Fri, 30 Jan 2026 15:01:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/projects/aramzsxyz/day-18-what-does-an-atproto-update-look-like/</guid>
		<description>Getting my blog posts set up in the atmosphere</description>
		<content:encoded><![CDATA[<h2 id="project-scope-and-todos" tabindex="-1">Project Scope and ToDos</h2>
<ol>
<li>Create a versatile blog site</li>
<li>Create a framework that makes it easy to add external data to the site</li>
</ol>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Give the site the capacity to replicate the logging and rating I do on Serialized and Letterboxd.</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Be able to pull down RSS feeds from other sites and create forward links to my other sites</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Create forward links to sites I want to post about.</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Create a way to pull in my Goodreads data and display it on the site</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Create a way to automate pulls from other data sources</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Combine easy inputs like text lists and JSON data files with markdown files that I can build on top of.</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Add a TMDB credit to footer in base.njk</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Make sure tags do not repeat in the displayed tag list.</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Get my Kindle Quotes into the site</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> YouTube Channel Recommendations</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Minify HTML via Netlify plugin.</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Log played games</li>
</ul>
<h2 id="day-18" tabindex="-1">Day 18</h2>
<p>Ok, that worked, what does an article update look like?</p>
<p>I made an edit to my one post on Leaflet. Looks like it just adjusts the record in place, which is nice. Updates are pretty easy then.</p>
<p>Ok, so then how to integrate this with my publishing flow? Let's <a href="https://github.com/bluesky-social/cookbook/blob/main/ts-bot/index.ts" target="_blank">take a look at a basic authenticated flow from BlueSky</a>. Looks like <a href="https://tangled.org/mary.my.id/atcute/tree/trunk/packages/definitions/standard-site" target="_blank">there is also some ways to reference standard types for standard.site</a>. This uses <a href="https://tangled.org/mary.my.id/atcute/tree/trunk/packages/definitions/atproto" target="_blank">the atcute package</a>, which seems to be well respected.</p>
<p>There seems to be <a href="https://micahcantor.com/blog/bluesky-comment-section.html" target="_blank">an interesting example of comments out there</a>, but that doesn't post anything.</p>
<p>There's also <a href="https://marvins-guide.leaflet.pub/3mckm76mfws2h" target="_blank">an interesting exploration of upserting records</a>.</p>
<p>A <a href="https://tangled.org/baileytownsend.dev/upsert-example/blob/main/upsertFullExample.js" target="_blank">good basic example here as well</a>.</p>
<p>To make this flexible, we should make it as it's own extension for static sites. Let's try to make a basic version.</p>
<p>First, I want to get used to tangled, <a href="https://tangled.org/did:plc:t5xmf33p5kqgkbznx22p7d7g/marksky-pub" target="_blank">so I'll set the repo up on there</a>.</p>
<p>I'm pretty sure my PDS host would be <code>https://bsky.social</code> right?</p>
<p>I can start with the <a href="https://tangled.org/baileytownsend.dev/upsert-example/blob/main/upsertFullExample.js" target="_blank">example</a>. I'll reorg it a little into the pieces I need as a start.</p>
<p>Ok, a nice place to pick up later from.</p>
]]></content:encoded>
	</item>
	
	<item>
		<title>XYZ Site - Day 17 - Publish an image and article to ATProto.</title>
		<link>https://fightwithtools.dev/posts/projects/aramzsxyz/day-17-at-proto-article-and-image/?source=rss</link>
		<pubDate>Sun, 25 Jan 2026 18:01:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/projects/aramzsxyz/day-17-at-proto-article-and-image/</guid>
		<description>Put my blog posts in the atmosphere</description>
		<content:encoded><![CDATA[<h2 id="project-scope-and-todos" tabindex="-1">Project Scope and ToDos</h2>
<ol>
<li>Create a versatile blog site</li>
<li>Create a framework that makes it easy to add external data to the site</li>
</ol>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Give the site the capacity to replicate the logging and rating I do on Serialized and Letterboxd.</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Be able to pull down RSS feeds from other sites and create forward links to my other sites</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Create forward links to sites I want to post about.</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Create a way to pull in my Goodreads data and display it on the site</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Create a way to automate pulls from other data sources</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Combine easy inputs like text lists and JSON data files with markdown files that I can build on top of.</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Add a TMDB credit to footer in base.njk</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Make sure tags do not repeat in the displayed tag list.</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Get my Kindle Quotes into the site</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> YouTube Channel Recommendations</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Minify HTML via Netlify plugin.</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Log played games</li>
</ul>
<h2 id="day-17" tabindex="-1">Day 17</h2>
<p>Let's start today by uploading a <a href="https://atproto.com/specs/blob" target="_blank">blob</a> for the image.</p>
<p><code>goat blob upload public/img/posts/1443px-Typical-orb-web-photo.jpg</code></p>
<p>That seems to have uploaded it. I get back the response:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/aramzsxyz/day-17-at-proto-article-and-image/#code-skip-day-17-at-proto-article-and-image-7" id="skip-to-code-skip-day-17-at-proto-article-and-image-7" class="skip-link">Skip code block ▼</a></p>
<pre class="language-bash"><code class="language-bash"><span class="token punctuation">{</span><br />  <span class="token string">"<span class="token variable">$type</span>"</span><span class="token builtin class-name">:</span> <span class="token string">"blob"</span>,<br />  <span class="token string">"ref"</span><span class="token builtin class-name">:</span> <span class="token punctuation">{</span><br />    <span class="token string">"<span class="token variable">$link</span>"</span><span class="token builtin class-name">:</span> <span class="token string">"bafkreig2247wcpqjkqy2ukjh4gjyqhpl32kg3pva4x55npjmuh4joeware"</span><br />  <span class="token punctuation">}</span>,<br />  <span class="token string">"mimeType"</span><span class="token builtin class-name">:</span> <span class="token string">"image/jpeg"</span>,<br />  <span class="token string">"size"</span><span class="token builtin class-name">:</span> <span class="token number">347901</span><br /><span class="token punctuation">}</span></code></pre>
<p id="code-skip-day-17-at-proto-article-and-image-7">Ok, so here's the formed document so far:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/aramzsxyz/day-17-at-proto-article-and-image/#code-skip-day-17-at-proto-article-and-image-6" id="skip-to-code-skip-day-17-at-proto-article-and-image-6" class="skip-link">Skip code block ▼</a></p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span><br />	<span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"site.standard.document"</span><span class="token punctuation">,</span><br />	<span class="token property">"publishedAt"</span><span class="token operator">:</span> <span class="token string">"2024-06-08T10:00:00.000Z"</span><span class="token punctuation">,</span><br />	<span class="token property">"site"</span><span class="token operator">:</span> <span class="token string">"at://did:plc:t5xmf33p5kqgkbznx22p7d7g/site.standard.publication/3mbrgnnqzrr2q"</span><span class="token punctuation">,</span><br />	<span class="token property">"path"</span><span class="token operator">:</span> <span class="token string">"/essays/the-internet-is-a-series-of-webs/"</span><span class="token punctuation">,</span><br />	<span class="token property">"title"</span><span class="token operator">:</span> <span class="token string">"The Internet is a Series of Webs"</span><span class="token punctuation">,</span><br />	<span class="token property">"description"</span><span class="token operator">:</span> <span class="token string">"The fate of the open web is inextricable from the other ways our world is in crisis. What can we do about it?"</span><span class="token punctuation">,</span><br />	<span class="token property">"coverImage"</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />		<span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"blob"</span><span class="token punctuation">,</span><br />		<span class="token property">"ref"</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />			<span class="token property">"$link"</span><span class="token operator">:</span> <span class="token string">"bafkreig2247wcpqjkqy2ukjh4gjyqhpl32kg3pva4x55npjmuh4joeware"</span><br />		<span class="token punctuation">}</span><span class="token punctuation">,</span><br />		<span class="token property">"mimeType"</span><span class="token operator">:</span> <span class="token string">"image/jpeg"</span><span class="token punctuation">,</span><br />		<span class="token property">"size"</span><span class="token operator">:</span> <span class="token number">347901</span><br />  	<span class="token punctuation">}</span><span class="token punctuation">,</span><br />	<span class="token property">"textContent"</span><span class="token operator">:</span> <span class="token string">""</span><span class="token punctuation">,</span><br />	<span class="token property">"bskyPostRef"</span><span class="token operator">:</span> <span class="token string">"https://bsky.app/profile/chronotope.aramzs.xyz/post/3kulbtuuixs27"</span><span class="token punctuation">,</span><br />	<span class="token property">"tags"</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">"IndieWeb"</span><span class="token punctuation">,</span> <span class="token string">"Tech"</span><span class="token punctuation">,</span> <span class="token string">"The Long Next"</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br />	<span class="token property">"updatedAt"</span><span class="token operator">:</span><span class="token string">"2024-06-08T10:30:00.000Z"</span><br /><br /><span class="token punctuation">}</span></code></pre>
<p id="code-skip-day-17-at-proto-article-and-image-6">I think this is a full post now? I just add the full text content from here. Plaintext representation of the documents contents. Should not contain markdown or other formatting.</p>
<p><a href="https://ufos.microcosm.blue/collection/?nsid=site.standard.document" target="_blank">What is out there for site.standard.document</a>?</p>
<p>I see some folks are using a Markdown type, even if it doesn't have an NSID:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/aramzsxyz/day-17-at-proto-article-and-image/#code-skip-day-17-at-proto-article-and-image-5" id="skip-to-code-skip-day-17-at-proto-article-and-image-5" class="skip-link">Skip code block ▼</a></p>
<pre class="language-json"><code class="language-json"><span class="token property">"content"</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />    <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"site.standard.content.markdown"</span><span class="token punctuation">,</span><br />    <span class="token property">"text"</span><span class="token operator">:</span> <span class="token string">"&lt;markdown here>"</span><span class="token punctuation">,</span><br />    <span class="token property">"version"</span><span class="token operator">:</span> <span class="token string">"1.0"</span><br />  <span class="token punctuation">}</span><span class="token punctuation">,</span></code></pre>
<p id="code-skip-day-17-at-proto-article-and-image-5">I'm not sure that is the right hierarchy? Should it be <code>site.standard.document.content.markdown</code>? I see <a href="https://stevedylan.dev/posts/standard-site-the-publishing-gateway/" target="_blank">others are going that direction</a>. Well, might as well use what is out there.</p>
<p>I'll write a little script to pull the markdown into a single line:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/aramzsxyz/day-17-at-proto-article-and-image/#code-skip-day-17-at-proto-article-and-image-4" id="skip-to-code-skip-day-17-at-proto-article-and-image-4" class="skip-link">Skip code block ▼</a></p>
<pre class="language-bash"><code class="language-bash"><span class="token shebang important">#!/bin/bash</span><br /><br /><span class="token comment"># Check if file argument is provided</span><br /><span class="token keyword">if</span> <span class="token punctuation">[</span> <span class="token variable">$#</span> <span class="token parameter variable">-eq</span> <span class="token number">0</span> <span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token keyword">then</span><br />    <span class="token builtin class-name">echo</span> <span class="token string">"Usage: <span class="token variable">$0</span> &lt;markdown-file>"</span><br />    <span class="token builtin class-name">exit</span> <span class="token number">1</span><br /><span class="token keyword">fi</span><br /><br /><span class="token comment"># Check if file exists</span><br /><span class="token keyword">if</span> <span class="token punctuation">[</span> <span class="token operator">!</span> <span class="token parameter variable">-f</span> <span class="token string">"<span class="token variable">$1</span>"</span> <span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token keyword">then</span><br />    <span class="token builtin class-name">echo</span> <span class="token string">"Error: File '<span class="token variable">$1</span>' not found"</span><br />    <span class="token builtin class-name">exit</span> <span class="token number">1</span><br /><span class="token keyword">fi</span><br /><br /><span class="token comment"># Convert markdown to single line with \n for linebreaks and escape double-quotes</span><br /><span class="token function">awk</span> <span class="token string">'{gsub(/"/, "\\\""); printf "%s\\n", $0}'</span> <span class="token string">"<span class="token variable">$1</span>"</span> <span class="token operator">|</span> <span class="token function">sed</span> <span class="token string">'s/\\n$//'</span></code></pre>
<p id="code-skip-day-17-at-proto-article-and-image-4">Final document is:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/aramzsxyz/day-17-at-proto-article-and-image/#code-skip-day-17-at-proto-article-and-image-3" id="skip-to-code-skip-day-17-at-proto-article-and-image-3" class="skip-link">Skip code block ▼</a></p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span><br />	<span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"site.standard.document"</span><span class="token punctuation">,</span><br />	<span class="token property">"publishedAt"</span><span class="token operator">:</span> <span class="token string">"2024-06-08T10:00:00.000Z"</span><span class="token punctuation">,</span><br />	<span class="token property">"site"</span><span class="token operator">:</span> <span class="token string">"at://did:plc:t5xmf33p5kqgkbznx22p7d7g/site.standard.publication/3mbrgnnqzrr2q"</span><span class="token punctuation">,</span><br />	<span class="token property">"path"</span><span class="token operator">:</span> <span class="token string">"/essays/the-internet-is-a-series-of-webs/"</span><span class="token punctuation">,</span><br />	<span class="token property">"title"</span><span class="token operator">:</span> <span class="token string">"The Internet is a Series of Webs"</span><span class="token punctuation">,</span><br />	<span class="token property">"description"</span><span class="token operator">:</span> <span class="token string">"The fate of the open web is inextricable from the other ways our world is in crisis. What can we do about it?"</span><span class="token punctuation">,</span><br />	<span class="token property">"coverImage"</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />		<span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"blob"</span><span class="token punctuation">,</span><br />		<span class="token property">"ref"</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />			<span class="token property">"$link"</span><span class="token operator">:</span> <span class="token string">"bafkreig2247wcpqjkqy2ukjh4gjyqhpl32kg3pva4x55npjmuh4joeware"</span><br />		<span class="token punctuation">}</span><span class="token punctuation">,</span><br />		<span class="token property">"mimeType"</span><span class="token operator">:</span> <span class="token string">"image/jpeg"</span><span class="token punctuation">,</span><br />		<span class="token property">"size"</span><span class="token operator">:</span> <span class="token number">347901</span><br />  	<span class="token punctuation">}</span><span class="token punctuation">,</span><br />	<span class="token property">"textContent"</span><span class="token operator">:</span> <span class="token string">"&lt;textContent>"</span><span class="token punctuation">,</span><br />	<span class="token property">"content"</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />		<span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"site.standard.content.markdown"</span><span class="token punctuation">,</span><br />		<span class="token property">"text"</span><span class="token operator">:</span> <span class="token string">"&lt;markdown here>"</span><span class="token punctuation">,</span><br />		<span class="token property">"version"</span><span class="token operator">:</span> <span class="token string">"1.0"</span><br />	<span class="token punctuation">}</span><span class="token punctuation">,</span><br />	<span class="token property">"bskyPostRef"</span><span class="token operator">:</span> <span class="token string">"https://bsky.app/profile/chronotope.aramzs.xyz/post/3kulbtuuixs27"</span><span class="token punctuation">,</span><br />	<span class="token property">"tags"</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">"IndieWeb"</span><span class="token punctuation">,</span> <span class="token string">"Tech"</span><span class="token punctuation">,</span> <span class="token string">"The Long Next"</span><span class="token punctuation">,</span> <span class="token string">"series:The Wild Web"</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br />	<span class="token property">"updatedAt"</span><span class="token operator">:</span><span class="token string">"2024-06-08T10:30:00.000Z"</span><br /><br /><span class="token punctuation">}</span></code></pre>
<p id="code-skip-day-17-at-proto-article-and-image-3"><code>bskyPostRef</code> can't be a string apparently as the post did not validate in goat. I was able to find a reason using <a href="https://atproto.tools/lexicons" target="_blank">atproto.tools</a>. So now I know <a href="https://github.com/bluesky-social/atproto/blob/main/lexicons/com/atproto/repo/strongRef.json" target="_blank">from the definition</a> that I need:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/aramzsxyz/day-17-at-proto-article-and-image/#code-skip-day-17-at-proto-article-and-image-2" id="skip-to-code-skip-day-17-at-proto-article-and-image-2" class="skip-link">Skip code block ▼</a></p>
<pre class="language-json"><code class="language-json"><span class="token property">"bskyPostRef"</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />		<span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"com.atproto.repo.strongRef"</span><span class="token punctuation">,</span><br />		<span class="token property">"uri"</span><span class="token operator">:</span> <span class="token string">"at://did:plc:t5xmf33p5kqgkbznx22p7d7g/app.bsky.feed.post/3kulbtuuixs27"</span><span class="token punctuation">,</span><br />		<span class="token property">"cid"</span><span class="token operator">:</span> <span class="token string">"bafyreigh7yods3ndrmqeq55cjisda6wi34swt7s6kkduwcotkgq5g5y2oe"</span><br />	<span class="token punctuation">}</span></code></pre>
<p id="code-skip-day-17-at-proto-article-and-image-2">Since this will be my first document record, I have to push without the validation.</p>
<p><code>goat record create fightwithtools-publication.json --no-validate</code></p>
<p>and I get back:</p>
<p><code>at://did:plc:t5xmf33p5kqgkbznx22p7d7g/site.standard.document/3mdbvp5q2kz2l	bafyreiedky4yjivfcm5df5ygqy7vkt3q3qdvzppcg7mcq4osyefjaizyd4</code></p>
<p>And hey, <a href="https://pdsls.dev/at://did:plc:t5xmf33p5kqgkbznx22p7d7g/site.standard.document/3mdbvp5q2kz2l" target="_blank">looks like it worked</a>!</p>
<p>For the curious my final json doc was:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/aramzsxyz/day-17-at-proto-article-and-image/#code-skip-day-17-at-proto-article-and-image-1" id="skip-to-code-skip-day-17-at-proto-article-and-image-1" class="skip-link">Skip code block ▼</a></p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span><br />	<span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"site.standard.document"</span><span class="token punctuation">,</span><br />	<span class="token property">"publishedAt"</span><span class="token operator">:</span> <span class="token string">"2024-06-08T10:00:00.000Z"</span><span class="token punctuation">,</span><br />	<span class="token property">"site"</span><span class="token operator">:</span> <span class="token string">"at://did:plc:t5xmf33p5kqgkbznx22p7d7g/site.standard.publication/3mbrgnnqzrr2q"</span><span class="token punctuation">,</span><br />	<span class="token property">"path"</span><span class="token operator">:</span> <span class="token string">"/essays/the-internet-is-a-series-of-webs/"</span><span class="token punctuation">,</span><br />	<span class="token property">"title"</span><span class="token operator">:</span> <span class="token string">"The Internet is a Series of Webs"</span><span class="token punctuation">,</span><br />	<span class="token property">"description"</span><span class="token operator">:</span> <span class="token string">"The fate of the open web is inextricable from the other ways our world is in crisis. What can we do about it?"</span><span class="token punctuation">,</span><br />	<span class="token property">"coverImage"</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />		<span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"blob"</span><span class="token punctuation">,</span><br />		<span class="token property">"ref"</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />			<span class="token property">"$link"</span><span class="token operator">:</span> <span class="token string">"bafkreig2247wcpqjkqy2ukjh4gjyqhpl32kg3pva4x55npjmuh4joeware"</span><br />		<span class="token punctuation">}</span><span class="token punctuation">,</span><br />		<span class="token property">"mimeType"</span><span class="token operator">:</span> <span class="token string">"image/jpeg"</span><span class="token punctuation">,</span><br />		<span class="token property">"size"</span><span class="token operator">:</span> <span class="token number">347901</span><br />  	<span class="token punctuation">}</span><span class="token punctuation">,</span><br />	<span class="token property">"textContent"</span><span class="token operator">:</span> <span class="token string">"&lt;textContent>"</span><span class="token punctuation">,</span><br />	<span class="token property">"content"</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />		<span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"site.standard.content.markdown"</span><span class="token punctuation">,</span><br />		<span class="token property">"text"</span><span class="token operator">:</span> <span class="token string">"&lt;markdown here>"</span><span class="token punctuation">,</span><br />		<span class="token property">"version"</span><span class="token operator">:</span> <span class="token string">"1.0"</span><br />	<span class="token punctuation">}</span><span class="token punctuation">,</span><br />	<span class="token property">"bskyPostRef"</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />		<span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"com.atproto.repo.strongRef"</span><span class="token punctuation">,</span><br />		<span class="token property">"uri"</span><span class="token operator">:</span> <span class="token string">"at://did:plc:t5xmf33p5kqgkbznx22p7d7g/app.bsky.feed.post/3kulbtuuixs27"</span><span class="token punctuation">,</span><br />		<span class="token property">"cid"</span><span class="token operator">:</span> <span class="token string">"bafyreigh7yods3ndrmqeq55cjisda6wi34swt7s6kkduwcotkgq5g5y2oe"</span><br />	<span class="token punctuation">}</span><span class="token punctuation">,</span><br />	<span class="token property">"tags"</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">"IndieWeb"</span><span class="token punctuation">,</span> <span class="token string">"Tech"</span><span class="token punctuation">,</span> <span class="token string">"The Long Next"</span><span class="token punctuation">,</span> <span class="token string">"series:The Wild Web"</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br />	<span class="token property">"updatedAt"</span><span class="token operator">:</span><span class="token string">"2024-06-08T10:30:00.000Z"</span><br /><br /><span class="token punctuation">}</span></code></pre>
]]></content:encoded>
	</item>
	
	<item>
		<title>XYZ Site - Day 16 - Publish an article to ATProto.</title>
		<link>https://fightwithtools.dev/posts/projects/aramzsxyz/day-16-at-proto-article-publish/?source=rss</link>
		<pubDate>Mon, 19 Jan 2026 03:01:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/projects/aramzsxyz/day-16-at-proto-article-publish/</guid>
		<description>Put my blog posts in the atmosphere</description>
		<content:encoded><![CDATA[<h2 id="project-scope-and-todos" tabindex="-1">Project Scope and ToDos</h2>
<ol>
<li>Create a versatile blog site</li>
<li>Create a framework that makes it easy to add external data to the site</li>
</ol>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Give the site the capacity to replicate the logging and rating I do on Serialized and Letterboxd.</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Be able to pull down RSS feeds from other sites and create forward links to my other sites</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Create forward links to sites I want to post about.</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Create a way to pull in my Goodreads data and display it on the site</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Create a way to automate pulls from other data sources</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Combine easy inputs like text lists and JSON data files with markdown files that I can build on top of.</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Add a TMDB credit to footer in base.njk</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Make sure tags do not repeat in the displayed tag list.</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Get my Kindle Quotes into the site</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> YouTube Channel Recommendations</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Minify HTML via Netlify plugin.</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Log played games</li>
</ul>
<h2 id="day-16" tabindex="-1">Day 16</h2>
<p>Ok, I was able to get the site information published!</p>
<p>Next up is pushing a blog post with the format.</p>
<p><code>goat account login -u chronotope.aramzs.xyz -p &lt;app password&gt;</code></p>
<p>So now we craft a JSON in the correct format for a post. We'll start with <a href="https://aramzs.xyz/essays/the-internet-is-a-series-of-webs/" target="_blank">one of my essays</a>.</p>
<p>If I want to link <a href="https://bsky.app/profile/chronotope.aramzs.xyz/post/3kulbtuuixs27" target="_blank">my main BlueSky post</a>, I need to use a <code>com.atproto.repo.strongRef</code> apparently. This is <a href="https://github.com/bluesky-social/atproto/blob/main/lexicons/com/atproto/repo/strongRef.json" target="_blank">a standard lexicon</a> type.</p>
<p>I can pull it down with <code>goat lex pull com.atproto.repo.strongRef</code>.</p>
<p>There doesn't <a href="https://ufos.microcosm.blue/collection/?nsid=store.lexicon.com.atproto.repo.strongRef" target="_blank">seem to be a an example of that</a>? I guess that makes sense if it isn't an actual object. But <a href="https://atp.readthedocs.io/en/latest/atproto/atproto_client.models.com.atproto.repo.strong_ref.html" target="_blank">the docs</a> indicate it can just be a string of either a URI or a CID. I could use the URL to the post, but let's do the CID? How does one get the CID? I see it in the metadata on <a href="https://pdsls.dev/at://did:plc:t5xmf33p5kqgkbznx22p7d7g/app.bsky.feed.post/3kulbtuuixs27#record" target="_blank">PDSL</a>. But it isn't in the document or on the goat data. What is a CID anyway? Well <a href="https://atproto.wiki/en/wiki/reference/identifiers/cid" target="_blank">I guess I'll look it up</a>. Not so useful. Looks <a href="https://github.com/multiformats/cid" target="_blank">like there is a spec though</a>.</p>
<p>Seems complicated. I'll just do the URL for now.</p>
<p>Interesting that <code>accept: [image/*]</code> is the value for <code>coverImage</code>. I don't know what that means? Let's see if we can find some examples. Let's see if we can <a href="https://ufos.microcosm.blue/collection/?nsid=site.standard.document" target="_blank">find</a> some examples. <a href="https://pdsls.dev/at://did:plc:v46ojbiop5ebs5h7gaomixcc/site.standard.document/3mcqr6f5jdg23" target="_blank">Here's a fully formatted one</a>.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/aramzsxyz/day-16-at-proto-article-publish/#code-skip-day-16-at-proto-article-publish-3" id="skip-to-code-skip-day-16-at-proto-article-publish-3" class="skip-link">Skip code block ▼</a></p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span><br />  <span class="token property">"path"</span><span class="token operator">:</span> <span class="token string">"/a/3mcqr6f5jdg23-hi-from-brookie"</span><span class="token punctuation">,</span><br />  <span class="token property">"site"</span><span class="token operator">:</span> <span class="token string">"at://did:plc:v46ojbiop5ebs5h7gaomixcc/site.standard.publication/3mcqr4rrb7x22"</span><span class="token punctuation">,</span><br />  <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"site.standard.document"</span><span class="token punctuation">,</span><br />  <span class="token property">"title"</span><span class="token operator">:</span> <span class="token string">"Hi from Brookie"</span><span class="token punctuation">,</span><br />  <span class="token property">"content"</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />    <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"app.offprint.content"</span><span class="token punctuation">,</span><br />    <span class="token property">"items"</span><span class="token operator">:</span> <span class="token punctuation">[</span><br />      <span class="token punctuation">{</span><br />        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"app.offprint.block.imageGrid"</span><span class="token punctuation">,</span><br />        <span class="token property">"images"</span><span class="token operator">:</span> <span class="token punctuation">[</span><br />          <span class="token punctuation">{</span><br />            <span class="token property">"image"</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />              <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"blob"</span><span class="token punctuation">,</span><br />              <span class="token property">"ref"</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />                <span class="token property">"$link"</span><span class="token operator">:</span> <span class="token string">"bafkreihub3ikzctbstjy5e34g4hw2ux7tbryd7cpcqg7fbosaxlicapggu"</span><br />              <span class="token punctuation">}</span><span class="token punctuation">,</span><br />              <span class="token property">"mimeType"</span><span class="token operator">:</span> <span class="token string">"image/png"</span><span class="token punctuation">,</span><br />              <span class="token property">"size"</span><span class="token operator">:</span> <span class="token number">13270</span><br />            <span class="token punctuation">}</span><span class="token punctuation">,</span><br />            <span class="token property">"aspectRatio"</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />              <span class="token property">"width"</span><span class="token operator">:</span> <span class="token number">480</span><span class="token punctuation">,</span><br />              <span class="token property">"height"</span><span class="token operator">:</span> <span class="token number">480</span><br />            <span class="token punctuation">}</span><br />          <span class="token punctuation">}</span><span class="token punctuation">,</span><br />          <span class="token punctuation">{</span><br />            <span class="token property">"image"</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />              <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"blob"</span><span class="token punctuation">,</span><br />              <span class="token property">"ref"</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />                <span class="token property">"$link"</span><span class="token operator">:</span> <span class="token string">"bafkreib5zrxr33anmw6gxjr5232uo3y324xpizzv7c7433jugllobvulxu"</span><br />              <span class="token punctuation">}</span><span class="token punctuation">,</span><br />              <span class="token property">"mimeType"</span><span class="token operator">:</span> <span class="token string">"image/png"</span><span class="token punctuation">,</span><br />              <span class="token property">"size"</span><span class="token operator">:</span> <span class="token number">13325</span><br />            <span class="token punctuation">}</span><span class="token punctuation">,</span><br />            <span class="token property">"aspectRatio"</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />              <span class="token property">"width"</span><span class="token operator">:</span> <span class="token number">480</span><span class="token punctuation">,</span><br />              <span class="token property">"height"</span><span class="token operator">:</span> <span class="token number">480</span><br />            <span class="token punctuation">}</span><br />          <span class="token punctuation">}</span><span class="token punctuation">,</span><br />          <span class="token punctuation">{</span><br />            <span class="token property">"image"</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />              <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"blob"</span><span class="token punctuation">,</span><br />              <span class="token property">"ref"</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />                <span class="token property">"$link"</span><span class="token operator">:</span> <span class="token string">"bafkreifyqhedylyfocp3wmn4kcv4fe6b2n7cdpmfs2x2ljvdby64gvirjm"</span><br />              <span class="token punctuation">}</span><span class="token punctuation">,</span><br />              <span class="token property">"mimeType"</span><span class="token operator">:</span> <span class="token string">"image/png"</span><span class="token punctuation">,</span><br />              <span class="token property">"size"</span><span class="token operator">:</span> <span class="token number">13358</span><br />            <span class="token punctuation">}</span><span class="token punctuation">,</span><br />            <span class="token property">"aspectRatio"</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />              <span class="token property">"width"</span><span class="token operator">:</span> <span class="token number">480</span><span class="token punctuation">,</span><br />              <span class="token property">"height"</span><span class="token operator">:</span> <span class="token number">480</span><br />            <span class="token punctuation">}</span><br />          <span class="token punctuation">}</span><span class="token punctuation">,</span><br />          <span class="token punctuation">{</span><br />            <span class="token property">"image"</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />              <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"blob"</span><span class="token punctuation">,</span><br />              <span class="token property">"ref"</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />                <span class="token property">"$link"</span><span class="token operator">:</span> <span class="token string">"bafkreig2xm6piu7lzclljzyiahowvflajsylasqjtnl26m4mqz7gpwqgwu"</span><br />              <span class="token punctuation">}</span><span class="token punctuation">,</span><br />              <span class="token property">"mimeType"</span><span class="token operator">:</span> <span class="token string">"image/png"</span><span class="token punctuation">,</span><br />              <span class="token property">"size"</span><span class="token operator">:</span> <span class="token number">13322</span><br />            <span class="token punctuation">}</span><span class="token punctuation">,</span><br />            <span class="token property">"aspectRatio"</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />              <span class="token property">"width"</span><span class="token operator">:</span> <span class="token number">480</span><span class="token punctuation">,</span><br />              <span class="token property">"height"</span><span class="token operator">:</span> <span class="token number">480</span><br />            <span class="token punctuation">}</span><br />          <span class="token punctuation">}</span><br />        <span class="token punctuation">]</span><span class="token punctuation">,</span><br />        <span class="token property">"gridRows"</span><span class="token operator">:</span> <span class="token number">2</span><span class="token punctuation">,</span><br />        <span class="token property">"aspectRatio"</span><span class="token operator">:</span> <span class="token string">"mosaic"</span><br />      <span class="token punctuation">}</span><span class="token punctuation">,</span><br />      <span class="token punctuation">{</span><br />        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"app.offprint.block.imageDiff"</span><span class="token punctuation">,</span><br />        <span class="token property">"images"</span><span class="token operator">:</span> <span class="token punctuation">[</span><br />          <span class="token punctuation">{</span><br />            <span class="token property">"image"</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />              <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"blob"</span><span class="token punctuation">,</span><br />              <span class="token property">"ref"</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />                <span class="token property">"$link"</span><span class="token operator">:</span> <span class="token string">"bafkreihub3ikzctbstjy5e34g4hw2ux7tbryd7cpcqg7fbosaxlicapggu"</span><br />              <span class="token punctuation">}</span><span class="token punctuation">,</span><br />              <span class="token property">"mimeType"</span><span class="token operator">:</span> <span class="token string">"image/png"</span><span class="token punctuation">,</span><br />              <span class="token property">"size"</span><span class="token operator">:</span> <span class="token number">13270</span><br />            <span class="token punctuation">}</span><span class="token punctuation">,</span><br />            <span class="token property">"aspectRatio"</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />              <span class="token property">"width"</span><span class="token operator">:</span> <span class="token number">480</span><span class="token punctuation">,</span><br />              <span class="token property">"height"</span><span class="token operator">:</span> <span class="token number">480</span><br />            <span class="token punctuation">}</span><br />          <span class="token punctuation">}</span><span class="token punctuation">,</span><br />          <span class="token punctuation">{</span><br />            <span class="token property">"image"</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />              <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"blob"</span><span class="token punctuation">,</span><br />              <span class="token property">"ref"</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />                <span class="token property">"$link"</span><span class="token operator">:</span> <span class="token string">"bafkreifyqhedylyfocp3wmn4kcv4fe6b2n7cdpmfs2x2ljvdby64gvirjm"</span><br />              <span class="token punctuation">}</span><span class="token punctuation">,</span><br />              <span class="token property">"mimeType"</span><span class="token operator">:</span> <span class="token string">"image/png"</span><span class="token punctuation">,</span><br />              <span class="token property">"size"</span><span class="token operator">:</span> <span class="token number">13358</span><br />            <span class="token punctuation">}</span><span class="token punctuation">,</span><br />            <span class="token property">"aspectRatio"</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />              <span class="token property">"width"</span><span class="token operator">:</span> <span class="token number">480</span><span class="token punctuation">,</span><br />              <span class="token property">"height"</span><span class="token operator">:</span> <span class="token number">480</span><br />            <span class="token punctuation">}</span><br />          <span class="token punctuation">}</span><br />        <span class="token punctuation">]</span><span class="token punctuation">,</span><br />        <span class="token property">"labels"</span><span class="token operator">:</span> <span class="token punctuation">[</span><br />          <span class="token string">"Before"</span><span class="token punctuation">,</span><br />          <span class="token string">"After"</span><br />        <span class="token punctuation">]</span><span class="token punctuation">,</span><br />        <span class="token property">"alignment"</span><span class="token operator">:</span> <span class="token string">"center"</span><br />      <span class="token punctuation">}</span><span class="token punctuation">,</span><br />      <span class="token punctuation">{</span><br />        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"app.offprint.block.imageCarousel"</span><span class="token punctuation">,</span><br />        <span class="token property">"images"</span><span class="token operator">:</span> <span class="token punctuation">[</span><br />          <span class="token punctuation">{</span><br />            <span class="token property">"image"</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />              <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"blob"</span><span class="token punctuation">,</span><br />              <span class="token property">"ref"</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />                <span class="token property">"$link"</span><span class="token operator">:</span> <span class="token string">"bafkreihub3ikzctbstjy5e34g4hw2ux7tbryd7cpcqg7fbosaxlicapggu"</span><br />              <span class="token punctuation">}</span><span class="token punctuation">,</span><br />              <span class="token property">"mimeType"</span><span class="token operator">:</span> <span class="token string">"image/png"</span><span class="token punctuation">,</span><br />              <span class="token property">"size"</span><span class="token operator">:</span> <span class="token number">13270</span><br />            <span class="token punctuation">}</span><span class="token punctuation">,</span><br />            <span class="token property">"aspectRatio"</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />              <span class="token property">"width"</span><span class="token operator">:</span> <span class="token number">480</span><span class="token punctuation">,</span><br />              <span class="token property">"height"</span><span class="token operator">:</span> <span class="token number">480</span><br />            <span class="token punctuation">}</span><br />          <span class="token punctuation">}</span><span class="token punctuation">,</span><br />          <span class="token punctuation">{</span><br />            <span class="token property">"image"</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />              <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"blob"</span><span class="token punctuation">,</span><br />              <span class="token property">"ref"</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />                <span class="token property">"$link"</span><span class="token operator">:</span> <span class="token string">"bafkreib5zrxr33anmw6gxjr5232uo3y324xpizzv7c7433jugllobvulxu"</span><br />              <span class="token punctuation">}</span><span class="token punctuation">,</span><br />              <span class="token property">"mimeType"</span><span class="token operator">:</span> <span class="token string">"image/png"</span><span class="token punctuation">,</span><br />              <span class="token property">"size"</span><span class="token operator">:</span> <span class="token number">13325</span><br />            <span class="token punctuation">}</span><span class="token punctuation">,</span><br />            <span class="token property">"aspectRatio"</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />              <span class="token property">"width"</span><span class="token operator">:</span> <span class="token number">480</span><span class="token punctuation">,</span><br />              <span class="token property">"height"</span><span class="token operator">:</span> <span class="token number">480</span><br />            <span class="token punctuation">}</span><br />          <span class="token punctuation">}</span><span class="token punctuation">,</span><br />          <span class="token punctuation">{</span><br />            <span class="token property">"image"</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />              <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"blob"</span><span class="token punctuation">,</span><br />              <span class="token property">"ref"</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />                <span class="token property">"$link"</span><span class="token operator">:</span> <span class="token string">"bafkreifyqhedylyfocp3wmn4kcv4fe6b2n7cdpmfs2x2ljvdby64gvirjm"</span><br />              <span class="token punctuation">}</span><span class="token punctuation">,</span><br />              <span class="token property">"mimeType"</span><span class="token operator">:</span> <span class="token string">"image/png"</span><span class="token punctuation">,</span><br />              <span class="token property">"size"</span><span class="token operator">:</span> <span class="token number">13358</span><br />            <span class="token punctuation">}</span><span class="token punctuation">,</span><br />            <span class="token property">"aspectRatio"</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />              <span class="token property">"width"</span><span class="token operator">:</span> <span class="token number">480</span><span class="token punctuation">,</span><br />              <span class="token property">"height"</span><span class="token operator">:</span> <span class="token number">480</span><br />            <span class="token punctuation">}</span><br />          <span class="token punctuation">}</span><span class="token punctuation">,</span><br />          <span class="token punctuation">{</span><br />            <span class="token property">"image"</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />              <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"blob"</span><span class="token punctuation">,</span><br />              <span class="token property">"ref"</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />                <span class="token property">"$link"</span><span class="token operator">:</span> <span class="token string">"bafkreig2xm6piu7lzclljzyiahowvflajsylasqjtnl26m4mqz7gpwqgwu"</span><br />              <span class="token punctuation">}</span><span class="token punctuation">,</span><br />              <span class="token property">"mimeType"</span><span class="token operator">:</span> <span class="token string">"image/png"</span><span class="token punctuation">,</span><br />              <span class="token property">"size"</span><span class="token operator">:</span> <span class="token number">13322</span><br />            <span class="token punctuation">}</span><span class="token punctuation">,</span><br />            <span class="token property">"aspectRatio"</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />              <span class="token property">"width"</span><span class="token operator">:</span> <span class="token number">480</span><span class="token punctuation">,</span><br />              <span class="token property">"height"</span><span class="token operator">:</span> <span class="token number">480</span><br />            <span class="token punctuation">}</span><br />          <span class="token punctuation">}</span><br />        <span class="token punctuation">]</span><span class="token punctuation">,</span><br />        <span class="token property">"autoplay"</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span><br />        <span class="token property">"interval"</span><span class="token operator">:</span> <span class="token number">3000</span><br />      <span class="token punctuation">}</span><span class="token punctuation">,</span><br />      <span class="token punctuation">{</span><br />        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"app.offprint.block.text"</span><span class="token punctuation">,</span><br />        <span class="token property">"plaintext"</span><span class="token operator">:</span> <span class="token string">"I really like all the image things :) "</span><br />      <span class="token punctuation">}</span><span class="token punctuation">,</span><br />      <span class="token punctuation">{</span><br />        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"app.offprint.block.text"</span><span class="token punctuation">,</span><br />        <span class="token property">"facets"</span><span class="token operator">:</span> <span class="token punctuation">[</span><br />          <span class="token punctuation">{</span><br />            <span class="token property">"index"</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />              <span class="token property">"byteEnd"</span><span class="token operator">:</span> <span class="token number">8</span><span class="token punctuation">,</span><br />              <span class="token property">"byteStart"</span><span class="token operator">:</span> <span class="token number">0</span><br />            <span class="token punctuation">}</span><span class="token punctuation">,</span><br />            <span class="token property">"features"</span><span class="token operator">:</span> <span class="token punctuation">[</span><br />              <span class="token punctuation">{</span><br />                <span class="token property">"did"</span><span class="token operator">:</span> <span class="token string">"did:plc:eob75vcjtmbaef2tn4evc4sl"</span><span class="token punctuation">,</span><br />                <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"app.offprint.richtext.facet#mention"</span><span class="token punctuation">,</span><br />                <span class="token property">"handle"</span><span class="token operator">:</span> <span class="token string">"aka.dad"</span><br />              <span class="token punctuation">}</span><br />            <span class="token punctuation">]</span><br />          <span class="token punctuation">}</span><span class="token punctuation">,</span><br />          <span class="token punctuation">{</span><br />            <span class="token property">"index"</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />              <span class="token property">"byteEnd"</span><span class="token operator">:</span> <span class="token number">22</span><span class="token punctuation">,</span><br />              <span class="token property">"byteStart"</span><span class="token operator">:</span> <span class="token number">9</span><br />            <span class="token punctuation">}</span><span class="token punctuation">,</span><br />            <span class="token property">"features"</span><span class="token operator">:</span> <span class="token punctuation">[</span><br />              <span class="token punctuation">{</span><br />                <span class="token property">"did"</span><span class="token operator">:</span> <span class="token string">"did:plc:pgjkomf37an4czloay5zeth6"</span><span class="token punctuation">,</span><br />                <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"app.offprint.richtext.facet#mention"</span><span class="token punctuation">,</span><br />                <span class="token property">"handle"</span><span class="token operator">:</span> <span class="token string">"offprint.app"</span><br />              <span class="token punctuation">}</span><br />            <span class="token punctuation">]</span><br />          <span class="token punctuation">}</span><span class="token punctuation">,</span><br />          <span class="token punctuation">{</span><br />            <span class="token property">"index"</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />              <span class="token property">"byteEnd"</span><span class="token operator">:</span> <span class="token number">36</span><span class="token punctuation">,</span><br />              <span class="token property">"byteStart"</span><span class="token operator">:</span> <span class="token number">23</span><br />            <span class="token punctuation">}</span><span class="token punctuation">,</span><br />            <span class="token property">"features"</span><span class="token operator">:</span> <span class="token punctuation">[</span><br />              <span class="token punctuation">{</span><br />                <span class="token property">"did"</span><span class="token operator">:</span> <span class="token string">"did:plc:v46ojbiop5ebs5h7gaomixcc"</span><span class="token punctuation">,</span><br />                <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"app.offprint.richtext.facet#mention"</span><span class="token punctuation">,</span><br />                <span class="token property">"handle"</span><span class="token operator">:</span> <span class="token string">"brookie.blog"</span><br />              <span class="token punctuation">}</span><br />            <span class="token punctuation">]</span><br />          <span class="token punctuation">}</span><span class="token punctuation">,</span><br />          <span class="token punctuation">{</span><br />            <span class="token property">"index"</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />              <span class="token property">"byteEnd"</span><span class="token operator">:</span> <span class="token number">47</span><span class="token punctuation">,</span><br />              <span class="token property">"byteStart"</span><span class="token operator">:</span> <span class="token number">37</span><br />            <span class="token punctuation">}</span><span class="token punctuation">,</span><br />            <span class="token property">"features"</span><span class="token operator">:</span> <span class="token punctuation">[</span><br />              <span class="token punctuation">{</span><br />                <span class="token property">"did"</span><span class="token operator">:</span> <span class="token string">"did:plc:revjuqmkvrw6fnkxppqtszpv"</span><span class="token punctuation">,</span><br />                <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"app.offprint.richtext.facet#mention"</span><span class="token punctuation">,</span><br />                <span class="token property">"handle"</span><span class="token operator">:</span> <span class="token string">"pckt.blog"</span><br />              <span class="token punctuation">}</span><br />            <span class="token punctuation">]</span><br />          <span class="token punctuation">}</span><br />        <span class="token punctuation">]</span><span class="token punctuation">,</span><br />        <span class="token property">"plaintext"</span><span class="token operator">:</span> <span class="token string">"@aka.dad @offprint.app @brookie.blog @pckt.blog "</span><br />      <span class="token punctuation">}</span><span class="token punctuation">,</span><br />      <span class="token punctuation">{</span><br />        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"app.offprint.block.text"</span><span class="token punctuation">,</span><br />        <span class="token property">"plaintext"</span><span class="token operator">:</span> <span class="token string">""</span><br />      <span class="token punctuation">}</span><span class="token punctuation">,</span><br />      <span class="token punctuation">{</span><br />        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"app.offprint.block.callout"</span><span class="token punctuation">,</span><br />        <span class="token property">"emoji"</span><span class="token operator">:</span> <span class="token string">"💡"</span><span class="token punctuation">,</span><br />        <span class="token property">"plaintext"</span><span class="token operator">:</span> <span class="token string">"Good Job Miguel ! "</span><br />      <span class="token punctuation">}</span><span class="token punctuation">,</span><br />      <span class="token punctuation">{</span><br />        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"app.offprint.block.text"</span><span class="token punctuation">,</span><br />        <span class="token property">"plaintext"</span><span class="token operator">:</span> <span class="token string">""</span><br />      <span class="token punctuation">}</span><span class="token punctuation">,</span><br />      <span class="token punctuation">{</span><br />        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"app.offprint.block.text"</span><span class="token punctuation">,</span><br />        <span class="token property">"plaintext"</span><span class="token operator">:</span> <span class="token string">""</span><br />      <span class="token punctuation">}</span><br />    <span class="token punctuation">]</span><br />  <span class="token punctuation">}</span><span class="token punctuation">,</span><br />  <span class="token property">"coverImage"</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />    <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"blob"</span><span class="token punctuation">,</span><br />    <span class="token property">"ref"</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />      <span class="token property">"$link"</span><span class="token operator">:</span> <span class="token string">"bafkreif6sve2kjuioifion3apv277sggym4jxhlgrkuyqqxdck7cy7x6c4"</span><br />    <span class="token punctuation">}</span><span class="token punctuation">,</span><br />    <span class="token property">"mimeType"</span><span class="token operator">:</span> <span class="token string">"image/png"</span><span class="token punctuation">,</span><br />    <span class="token property">"size"</span><span class="token operator">:</span> <span class="token number">8455</span><br />  <span class="token punctuation">}</span><span class="token punctuation">,</span><br />  <span class="token property">"description"</span><span class="token operator">:</span> <span class="token string">"brookie from pckt"</span><span class="token punctuation">,</span><br />  <span class="token property">"publishedAt"</span><span class="token operator">:</span> <span class="token string">"2026-01-18T21:08:15-07:00"</span><span class="token punctuation">,</span><br />  <span class="token property">"textContent"</span><span class="token operator">:</span> <span class="token string">"I really like all the image things :) \n@aka.dad @offprint.app @brookie.blog @pckt.blog \n\n💡 Good Job Miguel !"</span><br /><span class="token punctuation">}</span></code></pre>
<p id="code-skip-day-16-at-proto-article-publish-3">It looks like the intended format for that field is:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/aramzsxyz/day-16-at-proto-article-publish/#code-skip-day-16-at-proto-article-publish-2" id="skip-to-code-skip-day-16-at-proto-article-publish-2" class="skip-link">Skip code block ▼</a></p>
<pre class="language-json"><code class="language-json">  <span class="token property">"coverImage"</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />    <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"blob"</span><span class="token punctuation">,</span><br />    <span class="token property">"ref"</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />      <span class="token property">"$link"</span><span class="token operator">:</span> <span class="token string">"bafkreif6sve2kjuioifion3apv277sggym4jxhlgrkuyqqxdck7cy7x6c4"</span><br />    <span class="token punctuation">}</span><span class="token punctuation">,</span><br />    <span class="token property">"mimeType"</span><span class="token operator">:</span> <span class="token string">"image/png"</span><span class="token punctuation">,</span><br />    <span class="token property">"size"</span><span class="token operator">:</span> <span class="token number">8455</span><br />  <span class="token punctuation">}</span><span class="token punctuation">,</span></code></pre>
<p id="code-skip-day-16-at-proto-article-publish-2">The indication here is that you'd push a blob of image data to the PDS it looks like? Let's <a href="https://atproto.com/specs/blob" target="_blank">find the documentation</a>. Ok, interesting. Something to figure out later, it is getting late now.</p>
<p>Ok, so here's the formed document so far:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/aramzsxyz/day-16-at-proto-article-publish/#code-skip-day-16-at-proto-article-publish-1" id="skip-to-code-skip-day-16-at-proto-article-publish-1" class="skip-link">Skip code block ▼</a></p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span><br />	<span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"site.standard.document"</span><span class="token punctuation">,</span><br />	<span class="token property">"publishedAt"</span><span class="token operator">:</span> <span class="token string">"2024-06-08T10:00:00.000Z"</span><span class="token punctuation">,</span><br />	<span class="token property">"site"</span><span class="token operator">:</span> <span class="token string">"at://did:plc:t5xmf33p5kqgkbznx22p7d7g/site.standard.publication/3mbrgnnqzrr2q"</span><span class="token punctuation">,</span><br />	<span class="token property">"path"</span><span class="token operator">:</span> <span class="token string">"/essays/the-internet-is-a-series-of-webs/"</span><span class="token punctuation">,</span><br />	<span class="token property">"title"</span><span class="token operator">:</span> <span class="token string">"The Internet is a Series of Webs"</span><span class="token punctuation">,</span><br />	<span class="token property">"description"</span><span class="token operator">:</span> <span class="token string">"The fate of the open web is inextricable from the other ways our world is in crisis. What can we do about it?"</span><span class="token punctuation">,</span><br />	<span class="token property">"textContent"</span><span class="token operator">:</span> <span class="token string">""</span><span class="token punctuation">,</span><br />	<span class="token property">"bskyPostRef"</span><span class="token operator">:</span> <span class="token string">"https://bsky.app/profile/chronotope.aramzs.xyz/post/3kulbtuuixs27"</span><span class="token punctuation">,</span><br />	<span class="token property">"tags"</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">"IndieWeb"</span><span class="token punctuation">,</span> <span class="token string">"Tech"</span><span class="token punctuation">,</span> <span class="token string">"The Long Next"</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br />	<span class="token property">"updatedAt"</span><span class="token operator">:</span><span class="token string">"2024-06-08T10:30:00.000Z"</span><br /><br /><span class="token punctuation">}</span></code></pre>
<p id="code-skip-day-16-at-proto-article-publish-1">Getting there!</p>
]]></content:encoded>
	</item>
	
	<item>
		<title>XYZ Site - Day 15 - Publish to ATProto.</title>
		<link>https://fightwithtools.dev/posts/projects/aramzsxyz/day-15-publish-to-ATproto/?source=rss</link>
		<pubDate>Thu, 08 Jan 2026 21:59:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/projects/aramzsxyz/day-15-publish-to-ATproto/</guid>
		<description>Put my blog posts in the atmosphere</description>
		<content:encoded><![CDATA[<h2 id="project-scope-and-todos" tabindex="-1">Project Scope and ToDos</h2>
<ol>
<li>Create a versatile blog site</li>
<li>Create a framework that makes it easy to add external data to the site</li>
</ol>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Give the site the capacity to replicate the logging and rating I do on Serialized and Letterboxd.</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Be able to pull down RSS feeds from other sites and create forward links to my other sites</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Create forward links to sites I want to post about.</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Create a way to pull in my Goodreads data and display it on the site</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Create a way to automate pulls from other data sources</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Combine easy inputs like text lists and JSON data files with markdown files that I can build on top of.</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Add a TMDB credit to footer in base.njk</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Make sure tags do not repeat in the displayed tag list.</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Get my Kindle Quotes into the site</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> YouTube Channel Recommendations</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Minify HTML via Netlify plugin.</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Log played games</li>
</ul>
<h2 id="day-15" tabindex="-1">Day 15</h2>
<p><a href="https://octet-stream.net/b/scb/2026-01-05-this-blog-is-on-atproto.html?__readwiseLocation=" target="_blank">Looks cool</a>. Let's <a href="https://ufos.microcosm.blue/collection/?nsid=site.standard.document" target="_blank">try it like some others have</a>. Going to try to post blog entries to my PDS.</p>
<p>1 - let's do some testing.</p>
<p><code>brew install goat</code></p>
<p><code>goat account login -u chronotope.aramzs.xyz -p &lt;app password here&gt;</code></p>
<p>Verify resolution:</p>
<p><code>goat resolve wyden.senate.gov</code> works.</p>
<p><code>goat bsky post &quot;A quick test&quot;</code> works. I get back:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/aramzsxyz/day-15-publish-to-ATproto/#code-skip-day-15-publish-to-ATproto-10" id="skip-to-code-skip-day-15-publish-to-ATproto-10" class="skip-link">Skip code block ▼</a></p>
<pre class="language-bash"><code class="language-bash">at://did:plc:t5xmf33p5kqgkbznx22p7d7g/app.bsky.feed.post/3mbpifihvqm2q	bafyreih7zufh4rezvg6h766djnptbaizm2thiuxx4chkzql7wmvdcskcwm<br />view post at: https://bsky.app/profile/did:plc:t5xmf33p5kqgkbznx22p7d7g/post/3mbpifihvqm2q</code></pre>
<p id="code-skip-day-15-publish-to-ATproto-10">Can I then retrieve it?</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/aramzsxyz/day-15-publish-to-ATproto/#code-skip-day-15-publish-to-ATproto-9" id="skip-to-code-skip-day-15-publish-to-ATproto-9" class="skip-link">Skip code block ▼</a></p>
<pre class="language-bash"><code class="language-bash">goat get at://did:plc:t5xmf33p5kqgkbznx22p7d7g/app.bsky.feed.post/3mbpifihvqm2q<br /><span class="token punctuation">{</span><br />  <span class="token string">"<span class="token variable">$type</span>"</span><span class="token builtin class-name">:</span> <span class="token string">"app.bsky.feed.post"</span>,<br />  <span class="token string">"createdAt"</span><span class="token builtin class-name">:</span> <span class="token string">"2026-01-05T22:29:16.86Z"</span>,<br />  <span class="token string">"text"</span><span class="token builtin class-name">:</span> <span class="token string">"A quick test"</span><br /><span class="token punctuation">}</span></code></pre>
<p id="code-skip-day-15-publish-to-ATproto-9">Yup!</p>
<p>Let's <a href="https://chronotope.leaflet.pub/3mbpjrfwqm22y" target="_blank">publish a test on Leaflet.pub</a> to see <a href="https://pdsls.dev/at://did:plc:t5xmf33p5kqgkbznx22p7d7g/pub.leaflet.document/3mbpjrfwqm22y#record" target="_blank">what it looks like on my PDS</a>:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/aramzsxyz/day-15-publish-to-ATproto/#code-skip-day-15-publish-to-ATproto-8" id="skip-to-code-skip-day-15-publish-to-ATproto-8" class="skip-link">Skip code block ▼</a></p>
<pre class="language-yaml"><code class="language-yaml"><span class="token key atrule">tags</span><span class="token punctuation">:</span> <span class="token string">"test"</span><br /><span class="token key atrule">$type</span><span class="token punctuation">:</span> <span class="token string">"pub.leaflet.document"</span><br /><span class="token key atrule">pages</span><span class="token punctuation">:</span><br />  <span class="token punctuation">-</span> <span class="token key atrule">id</span><span class="token punctuation">:</span> <span class="token string">"019b729c-2664-7ddb-9229-31341239825f"</span><br />    <span class="token key atrule">$type</span><span class="token punctuation">:</span> <span class="token string">"pub.leaflet.pages.linearDocument"</span><br />	<span class="token key atrule">blocks</span><span class="token punctuation">:</span><br />	  <span class="token punctuation">-</span> <span class="token key atrule">$type</span><span class="token punctuation">:</span> <span class="token string">"pub.leaflet.pages.linearDocument#block"</span><br />		<span class="token key atrule">block</span><span class="token punctuation">:</span><br />		  <span class="token key atrule">$type</span><span class="token punctuation">:</span> <span class="token string">"pub.leaflet.blocks.text"</span><br />		  <span class="token key atrule">facets</span><span class="token punctuation">:</span><br />		  <span class="token key atrule">plaintext</span><span class="token punctuation">:</span> <span class="token string">"This is a test on Leaflet to see how the record looks. "</span><br /><span class="token key atrule">title</span><span class="token punctuation">:</span> <span class="token string">"A quick test post on Leaflet"</span><br /><span class="token key atrule">author</span><span class="token punctuation">:</span> <span class="token string">"did:plc:t5xmf33p5kqgkbznx22p7d7g"</span><br /><span class="token key atrule">postRef</span><span class="token punctuation">:</span><br />  <span class="token key atrule">cid</span><span class="token punctuation">:</span> <span class="token string">"bafyreic44p5jnfa2eq2zdq6pwnrdi2e4nzhiv3ebd2lhmbo2oxcdszm364"</span><br />  <span class="token key atrule">uri</span><span class="token punctuation">:</span> <span class="token string">"at://did:plc:t5xmf33p5kqgkbznx22p7d7g/app.bsky.feed.post/3mbpjrkknys2y"</span><br />  <span class="token key atrule">commit</span><span class="token punctuation">:</span><br />	<span class="token key atrule">cid</span><span class="token punctuation">:</span> <span class="token string">"bafyreif3xtgrmgqrdoizotxpyo2ryiqfqwwak6c2lm2jxwrx3xz4icmajy"</span><br />	<span class="token key atrule">rev</span><span class="token punctuation">:</span> <span class="token string">"3mbpjrknvxl26"</span><br />  <span class="token key atrule">validationStatus</span><span class="token punctuation">:</span> <span class="token string">"valid"</span><br /><span class="token key atrule">description</span><span class="token punctuation">:</span> <span class="token string">"Giving this a try"</span><br /><span class="token key atrule">publication</span><span class="token punctuation">:</span> <span class="token string">"at://did:plc:t5xmf33p5kqgkbznx22p7d7g/pub.leaflet.publication/3makguj34cs2t"</span><br /><span class="token key atrule">publishedAt</span><span class="token punctuation">:</span> <span class="token string">"2026-01-05T22:53:50.696Z"</span></code></pre>
<p id="code-skip-day-15-publish-to-ATproto-8">or in JSON</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/aramzsxyz/day-15-publish-to-ATproto/#code-skip-day-15-publish-to-ATproto-7" id="skip-to-code-skip-day-15-publish-to-ATproto-7" class="skip-link">Skip code block ▼</a></p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span><br />  <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"app.bsky.feed.post"</span><span class="token punctuation">,</span><br />  <span class="token property">"createdAt"</span><span class="token operator">:</span> <span class="token string">"2026-01-05T22:53:55.543Z"</span><span class="token punctuation">,</span><br />  <span class="token property">"embed"</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />    <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"app.bsky.embed.external"</span><span class="token punctuation">,</span><br />    <span class="token property">"external"</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />      <span class="token property">"description"</span><span class="token operator">:</span> <span class="token string">"Giving this a try"</span><span class="token punctuation">,</span><br />      <span class="token property">"thumb"</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"blob"</span><span class="token punctuation">,</span><br />        <span class="token property">"ref"</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />          <span class="token property">"$link"</span><span class="token operator">:</span> <span class="token string">"bafkreiblxmhoozultlvi5lx6j3lcvcyfqfiructung6fnkrl4yklacqg5e"</span><br />        <span class="token punctuation">}</span><span class="token punctuation">,</span><br />        <span class="token property">"mimeType"</span><span class="token operator">:</span> <span class="token string">"image/webp"</span><span class="token punctuation">,</span><br />        <span class="token property">"size"</span><span class="token operator">:</span> <span class="token number">19322</span><br />      <span class="token punctuation">}</span><span class="token punctuation">,</span><br />      <span class="token property">"title"</span><span class="token operator">:</span> <span class="token string">"A quick test post on Leaflet"</span><span class="token punctuation">,</span><br />      <span class="token property">"uri"</span><span class="token operator">:</span> <span class="token string">"https://chronotope.leaflet.pub/3mbpjrfwqm22y"</span><br />    <span class="token punctuation">}</span><br />  <span class="token punctuation">}</span><span class="token punctuation">,</span><br />  <span class="token property">"facets"</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br />  <span class="token property">"text"</span><span class="token operator">:</span> <span class="token string">""</span><br /><span class="token punctuation">}</span></code></pre>
<p id="code-skip-day-15-publish-to-ATproto-7">Looks like it hasn't been implimented in leaflet yet? Ok, let's try <a href="https://pdsls.dev/at://did:plc:txurc6ueald5d7462bpvzdby/site.standard.document/3mbnqpz3ziw2v#record" target="_blank">Thomas's top blog example</a>:</p>
<p><code>goat record get at://did:plc:txurc6ueald5d7462bpvzdby/site.standard.publication/3mbnlfyowxg2v</code></p>
<p>and we get a response that describes the publication:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/aramzsxyz/day-15-publish-to-ATproto/#code-skip-day-15-publish-to-ATproto-6" id="skip-to-code-skip-day-15-publish-to-ATproto-6" class="skip-link">Skip code block ▼</a></p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span><br />  <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"site.standard.publication"</span><span class="token punctuation">,</span><br />  <span class="token property">"description"</span><span class="token operator">:</span> <span class="token string">"Keeping up appearances as a professional software developer who has meaningful things to say about computers, programming, and the industry."</span><span class="token punctuation">,</span><br />  <span class="token property">"name"</span><span class="token operator">:</span> <span class="token string">"Serious Computer Business"</span><span class="token punctuation">,</span><br />  <span class="token property">"url"</span><span class="token operator">:</span> <span class="token string">"https://octet-stream.net/b/scb"</span><br /><span class="token punctuation">}</span></code></pre>
<p id="code-skip-day-15-publish-to-ATproto-6">And a post: <code>goat record get at://did:plc:txurc6ueald5d7462bpvzdby/site.standard.document/3mbnqpz3ziw2v</code></p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/aramzsxyz/day-15-publish-to-ATproto/#code-skip-day-15-publish-to-ATproto-5" id="skip-to-code-skip-day-15-publish-to-ATproto-5" class="skip-link">Skip code block ▼</a></p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span><br />  <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"site.standard.document"</span><span class="token punctuation">,</span><br />  <span class="token property">"path"</span><span class="token operator">:</span> <span class="token string">"/2026-01-03-including-rust-in-an-xcode-project-with-pointer-auth-arm64e.html"</span><span class="token punctuation">,</span><br />  <span class="token property">"publishedAt"</span><span class="token operator">:</span> <span class="token string">"2026-01-03T06:46:21Z"</span><span class="token punctuation">,</span><br />  <span class="token property">"site"</span><span class="token operator">:</span> <span class="token string">"at://did:plc:txurc6ueald5d7462bpvzdby/site.standard.publication/3mbnlfyowxg2v"</span><span class="token punctuation">,</span><br />  <span class="token property">"title"</span><span class="token operator">:</span> <span class="token string">"Including Rust in an Xcode project with Pointer Authentication (arm64e)"</span><br /><span class="token punctuation">}</span></code></pre>
<p id="code-skip-day-15-publish-to-ATproto-5">Ok, let's try to make one for this publication? First we'll make a JSON file.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/aramzsxyz/day-15-publish-to-ATproto/#code-skip-day-15-publish-to-ATproto-4" id="skip-to-code-skip-day-15-publish-to-ATproto-4" class="skip-link">Skip code block ▼</a></p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span><br />	<span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"site.standard.publication"</span><span class="token punctuation">,</span><br />	<span class="token property">"description"</span><span class="token operator">:</span> <span class="token string">"This is my outpost for documenting and live blogging my work on various side projects. Occasionally it is also the place I write about stuff I learned or useful information. Sometimes it can also be a place for rough writing that is dev-adjacent but doesn't really make sense for my main blog. \n\nTechnology won't save the world, but you can."</span><span class="token punctuation">,</span><br />	<span class="token property">"name"</span><span class="token operator">:</span> <span class="token string">"Fight With Tools: A Dev Blog"</span><span class="token punctuation">,</span><br />	<span class="token property">"url"</span><span class="token operator">:</span> <span class="token string">"https://fightwithtools.dev"</span><br /><span class="token punctuation">}</span></code></pre>
<p id="code-skip-day-15-publish-to-ATproto-4">Huh. How do I do a linebreak? <code>\n\n</code> according to BlueSky.</p>
<p>Huh.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/aramzsxyz/day-15-publish-to-ATproto/#code-skip-day-15-publish-to-ATproto-3" id="skip-to-code-skip-day-15-publish-to-ATproto-3" class="skip-link">Skip code block ▼</a></p>
<pre class="language-bash"><code class="language-bash">goat record create fightwithtools-publication.json<br />error: API request failed <span class="token punctuation">(</span>HTTP <span class="token number">400</span><span class="token punctuation">)</span>: InvalidRequest: Lexicon not found: lex:site.standard.publication</code></pre>
<p id="code-skip-day-15-publish-to-ATproto-3">Let's get the Lexicons</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/aramzsxyz/day-15-publish-to-ATproto/#code-skip-day-15-publish-to-ATproto-2" id="skip-to-code-skip-day-15-publish-to-ATproto-2" class="skip-link">Skip code block ▼</a></p>
<pre class="language-bash"><code class="language-bash">goat lex pull site.standard.publication<br />goat lex pull site.standard.document</code></pre>
<p id="code-skip-day-15-publish-to-ATproto-2">Ooops they seem to fail lint:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/aramzsxyz/day-15-publish-to-ATproto/#code-skip-day-15-publish-to-ATproto-1" id="skip-to-code-skip-day-15-publish-to-ATproto-1" class="skip-link">Skip code block ▼</a></p>
<pre class="language-bash"><code class="language-bash">goat lex lint<br /> 🟡 lexicons/site/standard/document.json<br />    <span class="token punctuation">[</span>missing-primary-description<span class="token punctuation">]</span>: primary <span class="token builtin class-name">type</span> missing a description<br />    <span class="token punctuation">[</span>unlimited-string<span class="token punctuation">]</span>: no max length<br />    <span class="token punctuation">[</span>unlimited-string<span class="token punctuation">]</span>: no max length<br /> 🟡 lexicons/site/standard/publication.json<br />    <span class="token punctuation">[</span>missing-primary-description<span class="token punctuation">]</span>: primary <span class="token builtin class-name">type</span> missing a description<br />error: linting issues detected</code></pre>
<p id="code-skip-day-15-publish-to-ATproto-1">It seems this is blocking me from publishing.</p>
<p>Ah, <a href="https://bsky.app/profile/brookie.blog/post/3mbpw3wzu7k2o" target="_blank">I got some advice</a>, and it turns out for the first entry of a lexicon on my PDS I have to not verify the Lexicon.</p>
<p><code>goat record create fightwithtools-publication.json --no-validate</code></p>
]]></content:encoded>
	</item>
	
	<item>
		<title>XYZ Site - Day 14 - Setting up a share button as an eleventy plugin.</title>
		<link>https://fightwithtools.dev/posts/projects/aramzsxyz/day-14-share-button-work/?source=rss</link>
		<pubDate>Sun, 10 Aug 2025 21:59:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/projects/aramzsxyz/day-14-share-button-work/</guid>
		<description>Make it easier to share my content online</description>
		<content:encoded><![CDATA[<h2 id="project-scope-and-todos" tabindex="-1">Project Scope and ToDos</h2>
<ol>
<li>Create a versatile blog site</li>
<li>Create a framework that makes it easy to add external data to the site</li>
</ol>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Give the site the capacity to replicate the logging and rating I do on Serialized and Letterboxd.</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Be able to pull down RSS feeds from other sites and create forward links to my other sites</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Create forward links to sites I want to post about.</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Create a way to pull in my Goodreads data and display it on the site</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Create a way to automate pulls from other data sources</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Combine easy inputs like text lists and JSON data files with markdown files that I can build on top of.</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Add a TMDB credit to footer in base.njk</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Make sure tags do not repeat in the displayed tag list.</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Get my Kindle Quotes into the site</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> YouTube Channel Recommendations</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Minify HTML via Netlify plugin.</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Log played games</li>
</ul>
<h2 id="day-14" tabindex="-1">Day 14</h2>
<p>Ok, let's get back at the share button.</p>
<p>The only thing left is to style it. I've got some basic stuff in here but do I want to add an additional button? I think I want to have a <a href="https://shareopenly.org/add/" target="_blank">Share Openly</a> button.</p>
<p>Easy enough to add the button and the logic, ShareOpenly is very easy to use:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/aramzsxyz/day-14-share-button-work/#code-skip-day-14-share-button-work-2" id="skip-to-code-skip-day-14-share-button-work-2" class="skip-link">Skip code block ▼</a></p>
<pre class="language-js"><code class="language-js"><span class="token function">triggerShareOpenly</span><span class="token punctuation">(</span><span class="token parameter">context</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />	<span class="token keyword">const</span> shareUrl <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>url<span class="token punctuation">;</span><br />	<span class="token keyword">const</span> shareTitle <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>shareText <span class="token operator">||</span> <span class="token keyword">this</span><span class="token punctuation">.</span>title<span class="token punctuation">;</span><br /><br />	<span class="token keyword">const</span> shareLink <span class="token operator">=</span> <span class="token string">'https://shareopenly.org/share/?url='</span><span class="token operator">+</span><span class="token function">encodeURIComponent</span><span class="token punctuation">(</span>shareUrl<span class="token punctuation">)</span><span class="token operator">+</span><span class="token string">"&amp;text="</span><span class="token operator">+</span><span class="token function">encodeURIComponent</span><span class="token punctuation">(</span>shareTitle<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br />	<span class="token comment">// Open the share dialog with the specified URL and text</span><br />	window<span class="token punctuation">.</span><span class="token function">open</span><span class="token punctuation">(</span>shareLink<span class="token punctuation">,</span> <span class="token string">'_blank'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span></code></pre>
<p id="code-skip-day-14-share-button-work-2">We'll add the actual styles that lay it out not in the plugin but in my site CSS, that's how I would expect it to be adopted by others.</p>
<p>I'll re-layout the buttons as a flex layout.</p>
<p>I want to make the share area background just a little bit darker, but I don't want to add another color. I think I can handle an opacity shift with CSS?</p>
<p>Yeah, looks like <a href="https://stackoverflow.com/a/44515149" target="_blank">there's a way to do this</a> in a straightforward way! I'm not super familiar with this technique, but it does work without me declaring another theme color. Pretty nice.</p>
<p>I made it just slightly darker, to give the whole footer area a gradient style by using the css:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/aramzsxyz/day-14-share-button-work/#code-skip-day-14-share-button-work-1" id="skip-to-code-skip-day-14-share-button-work-1" class="skip-link">Skip code block ▼</a></p>
<pre class="language-css"><code class="language-css">    <span class="token property">background-color</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--background-muted<span class="token punctuation">)</span><span class="token punctuation">;</span><br />    <span class="token property">background-image</span><span class="token punctuation">:</span> <span class="token function">linear-gradient</span><span class="token punctuation">(</span><span class="token function">hsla</span><span class="token punctuation">(</span>0<span class="token punctuation">,</span>0%<span class="token punctuation">,</span>0%<span class="token punctuation">,</span>.3<span class="token punctuation">)</span> 100%<span class="token punctuation">,</span>transparent 100%<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p id="code-skip-day-14-share-button-work-1">Buttons are looking better now but the share dialog on the desktop opens in a pretty random place. I'd love to reposition it. I'm not seeing a way though.</p>
<p>This is enough to make it live though! I'll have to figure out the share dialogue positioning later. I'll also add some classes to <a href="https://plausible.io/docs/custom-event-goals" target="_blank">make it trackable in Plausible</a>.</p>
<p><a target="_blank" href="https://github.com/AramZS/aramzs.xyz/commit/3d96353e957aef6f9d57efef31d0542aba72594e" class="git-commit-link"><code>git commit -am &quot;Get share buttons production ready and add shareopenly&quot;</code></a></p>
]]></content:encoded>
	</item>
	
	<item>
		<title>XYZ Site - Day 13 - Setting up a share button as an eleventy plugin.</title>
		<link>https://fightwithtools.dev/posts/projects/aramzsxyz/day-13-sharing-buttons-plugin/?source=rss</link>
		<pubDate>Sun, 15 Jun 2025 21:59:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/projects/aramzsxyz/day-13-sharing-buttons-plugin/</guid>
		<description>Make it easier to share my content online</description>
		<content:encoded><![CDATA[<h2 id="project-scope-and-todos" tabindex="-1">Project Scope and ToDos</h2>
<ol>
<li>Create a versatile blog site</li>
<li>Create a framework that makes it easy to add external data to the site</li>
</ol>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Give the site the capacity to replicate the logging and rating I do on Serialized and Letterboxd.</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Be able to pull down RSS feeds from other sites and create forward links to my other sites</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Create forward links to sites I want to post about.</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Create a way to pull in my Goodreads data and display it on the site</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Create a way to automate pulls from other data sources</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Combine easy inputs like text lists and JSON data files with markdown files that I can build on top of.</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Add a TMDB credit to footer in base.njk</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Make sure tags do not repeat in the displayed tag list.</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Get my Kindle Quotes into the site</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> YouTube Channel Recommendations</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Minify HTML via Netlify plugin.</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Log played games</li>
</ul>
<h2 id="day-13" tabindex="-1">Day 13</h2>
<p>After thinking about it some more I'm realizing the easiest thing is to turn this into a Eleventy plugin. So I'm going to restructure it that way.</p>
<p data-wordfix="true">Let's start with <a href="https://www.11ty.dev/docs/create-plugin/" target="_blank">a quick template</a> for the <code>eleventy.config.js</code> file:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/aramzsxyz/day-13-sharing-buttons-plugin/#code-skip-day-13-sharing-buttons-plugin-2" id="skip-to-code-skip-day-13-sharing-buttons-plugin-2" class="skip-link">Skip code block ▼</a></p>
<pre class="language-js"><code class="language-js"><span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">eleventyConfig<span class="token punctuation">,</span> options <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />	<span class="token keyword">let</span> options <span class="token operator">=</span> Object<span class="token punctuation">.</span><span class="token function">assign</span><span class="token punctuation">(</span><span class="token punctuation">{</span><br />		<span class="token literal-property property">defaultUtms</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><br />	<span class="token punctuation">}</span><span class="token punctuation">,</span> options<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br />	eleventyConfig<span class="token punctuation">.</span><span class="token function">addPlugin</span><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">eleventyConfig</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />		<span class="token comment">// I am a plugin!</span><br />	<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
<p id="code-skip-day-13-sharing-buttons-plugin-2">Oh right, I'm in CJS, I gotta restructure:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/aramzsxyz/day-13-sharing-buttons-plugin/#code-skip-day-13-sharing-buttons-plugin-1" id="skip-to-code-skip-day-13-sharing-buttons-plugin-1" class="skip-link">Skip code block ▼</a></p>
<pre class="language-js"><code class="language-js"><span class="token keyword">const</span> <span class="token punctuation">{</span> activateShortcodes <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">"./lib/shortcodes"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br />module<span class="token punctuation">.</span>exports <span class="token operator">=</span> <span class="token punctuation">{</span><br />  <span class="token function-variable function">configFunction</span><span class="token operator">:</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">eleventyConfig<span class="token punctuation">,</span> options <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />    options <span class="token operator">=</span> Object<span class="token punctuation">.</span><span class="token function">assign</span><span class="token punctuation">(</span><span class="token punctuation">{</span><br />      <span class="token literal-property property">defaultUtms</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">defaultShareText</span><span class="token operator">:</span> <span class="token string">"Share this post"</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">domain</span><span class="token operator">:</span> <span class="token string">""</span><br />    <span class="token punctuation">}</span><span class="token punctuation">,</span> options<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br />    eleventyConfig<span class="token punctuation">.</span><span class="token function">addPlugin</span><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">eleventyConfig</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />      <span class="token comment">// I am a plugin!</span><br />      <span class="token function">activateShortcodes</span><span class="token punctuation">(</span>eleventyConfig<span class="token punctuation">,</span> options<span class="token punctuation">)</span><span class="token punctuation">;</span><br />    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />  <span class="token punctuation">}</span><span class="token punctuation">,</span><br /><span class="token punctuation">}</span></code></pre>
<p id="code-skip-day-13-sharing-buttons-plugin-1">The button will need styles. For now I'm going to embed that together with the button supplied by the shortcode.</p>
<p><a target="_blank" href="https://github.com/AramZS/aramzs.xyz/commit/17c7d32130e4916af5a33481fbe6b2a4819812a9" class="git-commit-link"><code>git commit -am &quot;Set up share button, still needs styling&quot;</code></a></p>
]]></content:encoded>
	</item>
	
	<item>
		<title>XYZ Site - Day 12 - Setting up a share button.</title>
		<link>https://fightwithtools.dev/posts/projects/aramzsxyz/day-12-sharing-buttons/?source=rss</link>
		<pubDate>Sat, 05 Apr 2025 21:59:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/projects/aramzsxyz/day-12-sharing-buttons/</guid>
		<description>Make it easier to share my content online</description>
		<content:encoded><![CDATA[<h2 id="project-scope-and-todos" tabindex="-1">Project Scope and ToDos</h2>
<ol>
<li>Create a versatile blog site</li>
<li>Create a framework that makes it easy to add external data to the site</li>
</ol>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Give the site the capacity to replicate the logging and rating I do on Serialized and Letterboxd.</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Be able to pull down RSS feeds from other sites and create forward links to my other sites</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Create forward links to sites I want to post about.</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Create a way to pull in my Goodreads data and display it on the site</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Create a way to automate pulls from other data sources</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Combine easy inputs like text lists and JSON data files with markdown files that I can build on top of.</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Add a TMDB credit to footer in base.njk</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Make sure tags do not repeat in the displayed tag list.</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Get my Kindle Quotes into the site</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> YouTube Channel Recommendations</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Minify HTML via Netlify plugin.</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Log played games</li>
</ul>
<h2 id="day-12" tabindex="-1">Day 12</h2>
<p>Now that the Web Share API is pretty much available everywhere I really have wanted to take some time to figure out how to use it. <a href="https://piccalil.li/blog/simplify-sharing-with-built-in-apis-and-progressive-enhancement/" target="_blank">An article on setting up sharing with HTML/JS</a> popped up on my feed reader and I figured this is the excuse to give it a try.</p>
<p>One thing I really want to do here is avoid having more network requests for script files. This has been an issue that has come up at work and the tactic I thought about there is one I want to try for myself here, which is to pull the script out of a JS file and into the HTML file for inline script tags.</p>
<p>There might be more than one script I want to handle this way, but I think they all belong in a single script tag? The potential problem here is that this could cause problems with how JS pointers bubble up, giving it a broad scope.</p>
<p>Actually... now that I've typed it out... I don't want it to be in a single script tag. Let's not do that.</p>
<p>Ok, so I need a block in the template:</p>
<p>``</p>
<p>I need to make it safe because it is HTML and I don't want it escaped.</p>
<p data-wordfix="true">This is a <code>build</code> Eleventy data object in the <code>_data</code> folder. In there I have an object now:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/aramzsxyz/day-12-sharing-buttons/#code-skip-day-12-sharing-buttons-1" id="skip-to-code-skip-day-12-sharing-buttons-1" class="skip-link">Skip code block ▼</a></p>
<pre class="language-js"><code class="language-js"><span class="token keyword">const</span> shareActions <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">"../../plugins/share-actions"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br />module<span class="token punctuation">.</span>exports <span class="token operator">=</span> <span class="token punctuation">{</span><br />	<span class="token literal-property property">env</span><span class="token operator">:</span> process<span class="token punctuation">.</span>env<span class="token punctuation">.</span><span class="token constant">ELEVENTY_ENV</span><span class="token punctuation">,</span><br />	<span class="token literal-property property">timestamp</span><span class="token operator">:</span> <span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br />	<span class="token literal-property property">bookwyrm</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />		<span class="token literal-property property">username</span><span class="token operator">:</span> <span class="token string">"aramzs"</span><span class="token punctuation">,</span><br />		<span class="token literal-property property">instance</span><span class="token operator">:</span> <span class="token string">"bookwyrm.tilde.zone"</span><span class="token punctuation">,</span><br />	<span class="token punctuation">}</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">footerInlineScript</span><span class="token operator">:</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">&lt;script></span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>shareActions<span class="token punctuation">.</span><span class="token function">js</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">&lt;/script></span><span class="token template-punctuation string">`</span></span><br /><span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
<p id="code-skip-day-12-sharing-buttons-1">With the <code>share-actions</code> file going to be my home for building this process. I can then build it like normal JS files in there and export it out from the <code>index.js</code> in the <code>share-actions</code> folder.</p>
<p>Now I'm free to build in <code>.js</code> files easily.</p>
<p>The other thing I may want to add to this process is minification, but I'll worry about that later.</p>
<p>I will want my custom HTML as well, and I can export that from my index also. I might not be able to get the per-page <code>data</code> context with the URL that way, but let's see what we can do.</p>
<p>Ok yeah, the data from the page build just doesn't seem accessible in the global data? At least not with the Nunjucks rendering process. I guess I'll have to define a Nunjucks template and import it into my template.</p>
<p data-wordfix="true">I'm putting it in the plugin's folder for now. That's not great because it doesn't trigger rebuild but hopefully it has full access to the page context?</p>
]]></content:encoded>
	</item>
	
	<item>
		<title>XYZ Site - Day 11 - Improvements to the Contrasts page.</title>
		<link>https://fightwithtools.dev/posts/projects/aramzsxyz/day-11-contrasts-page-v2/?source=rss</link>
		<pubDate>Thu, 23 Jan 2025 21:59:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/projects/aramzsxyz/day-11-contrasts-page-v2/</guid>
		<description>Making it more interesting, useful and interactive.</description>
		<content:encoded><![CDATA[<h2 id="project-scope-and-todos" tabindex="-1">Project Scope and ToDos</h2>
<ol>
<li>Create a versatile blog site</li>
<li>Create a framework that makes it easy to add external data to the site</li>
</ol>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Give the site the capacity to replicate the logging and rating I do on Serialized and Letterboxd.</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Be able to pull down RSS feeds from other sites and create forward links to my other sites</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Create forward links to sites I want to post about.</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Create a way to pull in my Goodreads data and display it on the site</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Create a way to automate pulls from other data sources</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Combine easy inputs like text lists and JSON data files with markdown files that I can build on top of.</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Add a TMDB credit to footer in base.njk</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Make sure tags do not repeat in the displayed tag list.</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Get my Kindle Quotes into the site</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> YouTube Channel Recommendations</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Minify HTML via Netlify plugin.</li>
</ul>
<h2 id="day-11" tabindex="-1">Day 11</h2>
<p>Still working on my page for collecting interesting color contrasts, a fun little feature on my site. Thanks to suggestions from <a href="https://www.linkedin.com/in/michaelgrossman/" target="_blank">Michael Grossman</a> I've added features citing color sources and making it easier to access the rgb codes for each swatch and background. <a href="https://aramzs.xyz/" target="_blank">https://aramzs.xyz/</a></p>
]]></content:encoded>
	</item>
	
	<item>
		<title>Dealing with Foursquare checkins that don't have an API response</title>
		<link>https://fightwithtools.dev/posts/projects/foursquare-location-data-site/day-5-scraping-data-from-foursquare-urls/?source=rss</link>
		<pubDate>Sun, 05 Jan 2025 15:59:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/projects/foursquare-location-data-site/day-5-scraping-data-from-foursquare-urls/</guid>
		<description>If it doesn't make money it apparently isn't in the Foursquare API</description>
		<content:encoded><![CDATA[<h2 id="project-scope-and-todos" tabindex="-1">Project Scope and ToDos</h2>
<ol>
<li>Create a new site</li>
<li>Process the Foursquare data to a set of locations with additional data</li>
<li>Set the data up so it can be put on a map (it needs lat and long)</li>
</ol>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Can be searched</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Can show travel paths throughout a day</li>
</ul>
<h2 id="day-5" tabindex="-1">Day 5</h2>
<p>I want to crawl Foursquare URLs for pages I do not have data in the API for. Here's <a href="https://foursquare.com/v/north-philadelphia/4e9ae7244901d3b0b7190bde" target="_blank">an example page</a>: <code>https://foursquare.com/v/north-philadelphia/4e9ae7244901d3b0b7190bde</code></p>
<p>This is one of the pages that are there on the web (though who knows for how long) but are not in the Foursquare Places API. So let's figure out how to determine location data from a URL like that by starting in a Jupyter Notebook.</p>
<p>I'll use <code>requests</code> here as well to get the HTML pages. Then I can use the classic <code>BeautifulSoup</code> package to parse what I need out of it.</p>
<p>Ok, it turns out that there are two types of pages, ones like the one above, which have lat and long in the metadata, but no additional place/address location data. Then there are ones like <a href="https://foursquare.com/v/baruch-college--william-and-anita-newman-vertical-campus/4a494ce4f964a5202cab1fe3" target="_blank">Baruch College's Vertical Campus</a> which are locations with place data but are, I guess, not business enough to be in the Places API.</p>
<p>So I can always get lat and long, but I'll need to check if the address block exists:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/foursquare-location-data-site/day-5-scraping-data-from-foursquare-urls/#code-skip-day-5-scraping-data-from-foursquare-urls-3" id="skip-to-code-skip-day-5-scraping-data-from-foursquare-urls-3" class="skip-link">Skip code block ▼</a></p>
<pre class="language-python"><code class="language-python">htmlLatitude <span class="token operator">=</span> soup<span class="token punctuation">.</span>find<span class="token punctuation">(</span><span class="token string">"meta"</span><span class="token punctuation">,</span> <span class="token builtin">property</span><span class="token operator">=</span><span class="token string">"playfoursquare:location:latitude"</span><span class="token punctuation">)</span><br /><span class="token keyword">print</span><span class="token punctuation">(</span>htmlLatitude<span class="token punctuation">)</span><br /><span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string-interpolation"><span class="token string">f"Latitude is </span><span class="token interpolation"><span class="token punctuation">{</span>htmlLatitude<span class="token punctuation">[</span><span class="token string">'content'</span><span class="token punctuation">]</span><span class="token punctuation">}</span></span><span class="token string">"</span></span><span class="token punctuation">)</span><br />locationDataDict<span class="token punctuation">[</span><span class="token string">"latitude"</span><span class="token punctuation">]</span> <span class="token operator">=</span> htmlLatitude<span class="token punctuation">[</span><span class="token string">'content'</span><span class="token punctuation">]</span><span class="token punctuation">;</span><br /><br />htmlLongitude <span class="token operator">=</span> soup<span class="token punctuation">.</span>find<span class="token punctuation">(</span><span class="token string">"meta"</span><span class="token punctuation">,</span> <span class="token builtin">property</span><span class="token operator">=</span><span class="token string">"playfoursquare:location:longitude"</span><span class="token punctuation">)</span><br /><span class="token keyword">print</span><span class="token punctuation">(</span>htmlLongitude<span class="token punctuation">)</span><br /><span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string-interpolation"><span class="token string">f"Latitude is </span><span class="token interpolation"><span class="token punctuation">{</span>htmlLongitude<span class="token punctuation">[</span><span class="token string">'content'</span><span class="token punctuation">]</span><span class="token punctuation">}</span></span><span class="token string">"</span></span><span class="token punctuation">)</span><br />locationDataDict<span class="token punctuation">[</span><span class="token string">"longitude"</span><span class="token punctuation">]</span> <span class="token operator">=</span> htmlLongitude<span class="token punctuation">[</span><span class="token string">'content'</span><span class="token punctuation">]</span><span class="token punctuation">;</span><br /><br />htmlAddressBlock <span class="token operator">=</span> soup<span class="token punctuation">.</span>find<span class="token punctuation">(</span><span class="token string">"div"</span><span class="token punctuation">,</span> itemprop<span class="token operator">=</span><span class="token string">"address"</span><span class="token punctuation">)</span><br /><span class="token keyword">if</span> htmlAddressBlock <span class="token keyword">is</span> <span class="token boolean">None</span><span class="token punctuation">:</span><br />	<span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string">"No address block found"</span><span class="token punctuation">)</span><br /><span class="token keyword">else</span><span class="token punctuation">:</span><br />	htmlStreetAddress <span class="token operator">=</span> soup<span class="token punctuation">.</span>find<span class="token punctuation">(</span><span class="token string">"span"</span><span class="token punctuation">,</span> itemprop<span class="token operator">=</span><span class="token string">"streetAddress"</span><span class="token punctuation">)</span><br />	<span class="token keyword">print</span><span class="token punctuation">(</span>htmlStreetAddress<span class="token punctuation">)</span><br />	<span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string-interpolation"><span class="token string">f"address is </span><span class="token interpolation"><span class="token punctuation">{</span>htmlStreetAddress<span class="token punctuation">.</span>string<span class="token punctuation">}</span></span><span class="token string">"</span></span><span class="token punctuation">)</span><br />	locationDataDict<span class="token punctuation">[</span><span class="token string">"address"</span><span class="token punctuation">]</span> <span class="token operator">=</span> htmlStreetAddress<span class="token punctuation">.</span>string<span class="token punctuation">;</span></code></pre>
<p id="code-skip-day-5-scraping-data-from-foursquare-urls-3">It looks like <a href="https://docs.foursquare.com/data-products/docs/places-api" target="_blank">the Places API</a> that Foursquare open sourced <em>is</em> the API I'm using, so yeah, better crawl the pages I want before they're gone.</p>
<p>Weirdly, this does not appear to have &quot;country&quot; in the HTML. But there is another place to pull it from, the mess of Javascript that gets pushed on to the page. I suppose I could pull this from lat and long, but I'm trying to avoid grabbing a ton of data from external APIs.</p>
<p>I guess someetimes you just need to Do A Regex lol.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/foursquare-location-data-site/day-5-scraping-data-from-foursquare-urls/#code-skip-day-5-scraping-data-from-foursquare-urls-2" id="skip-to-code-skip-day-5-scraping-data-from-foursquare-urls-2" class="skip-link">Skip code block ▼</a></p>
<pre class="language-python"><code class="language-python"><span class="token comment"># Country pull</span><br />pattern <span class="token operator">=</span> <span class="token string">r'","country":"([^"]+)","'</span><br /><span class="token keyword">match</span> <span class="token operator">=</span> re<span class="token punctuation">.</span>search<span class="token punctuation">(</span>pattern<span class="token punctuation">,</span> <span class="token builtin">str</span><span class="token punctuation">(</span>htmlContent<span class="token punctuation">)</span><span class="token punctuation">)</span><br /><span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string">"country match"</span><span class="token punctuation">)</span><br /><span class="token keyword">print</span><span class="token punctuation">(</span><span class="token keyword">match</span><span class="token punctuation">.</span>groups<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">)</span></code></pre>
<p id="code-skip-day-5-scraping-data-from-foursquare-urls-2">Also, it seems not every page has all the address fields, so I'll have to allow some of those to null out.</p>
<p><a target="_blank" href="https://github.com/AramZS/locations/commit/6d4f692f5b1c7d7eb558e3c39dcd81020f7346c7" class="git-commit-link"><code>git commit -am &quot;Crawl HTML as a fallback to foursquare API 404&quot;</code></a></p>
<p>Ok, I tried writing all of these rows to JSON:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/foursquare-location-data-site/day-5-scraping-data-from-foursquare-urls/#code-skip-day-5-scraping-data-from-foursquare-urls-1" id="skip-to-code-skip-day-5-scraping-data-from-foursquare-urls-1" class="skip-link">Skip code block ▼</a></p>
<pre class="language-python"><code class="language-python"><span class="token keyword">for</span> i <span class="token keyword">in</span> dataFrames<span class="token punctuation">[</span><span class="token string">"venues"</span><span class="token punctuation">]</span><span class="token punctuation">.</span>index<span class="token punctuation">:</span><br />    idString <span class="token operator">=</span> dataFrames<span class="token punctuation">[</span><span class="token string">"venues"</span><span class="token punctuation">]</span><span class="token punctuation">.</span>iloc<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">.</span>get<span class="token punctuation">(</span><span class="token string">'id'</span><span class="token punctuation">)</span><br />    dataFrames<span class="token punctuation">[</span><span class="token string">"venues"</span><span class="token punctuation">]</span><span class="token punctuation">.</span>loc<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">.</span>to_json<span class="token punctuation">(</span><span class="token string">"../datasets/venues/{}.json"</span><span class="token punctuation">.</span><span class="token builtin">format</span><span class="token punctuation">(</span>idString<span class="token punctuation">)</span><span class="token punctuation">)</span><br /><br /><span class="token keyword">for</span> i <span class="token keyword">in</span> dataFrames<span class="token punctuation">[</span><span class="token string">"photos"</span><span class="token punctuation">]</span><span class="token punctuation">.</span>index<span class="token punctuation">:</span><br />    idString <span class="token operator">=</span> dataFrames<span class="token punctuation">[</span><span class="token string">"photos"</span><span class="token punctuation">]</span><span class="token punctuation">.</span>iloc<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">.</span>get<span class="token punctuation">(</span><span class="token string">'id'</span><span class="token punctuation">)</span><br />    dataFrames<span class="token punctuation">[</span><span class="token string">"venues"</span><span class="token punctuation">]</span><span class="token punctuation">.</span>loc<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">.</span>to_json<span class="token punctuation">(</span><span class="token string">"../datasets/photos/{}.json"</span><span class="token punctuation">.</span><span class="token builtin">format</span><span class="token punctuation">(</span>idString<span class="token punctuation">)</span><span class="token punctuation">)</span><br /><br /><span class="token keyword">for</span> i <span class="token keyword">in</span> dataFrames<span class="token punctuation">[</span><span class="token string">"checkins"</span><span class="token punctuation">]</span><span class="token punctuation">.</span>index<span class="token punctuation">:</span><br />    idString <span class="token operator">=</span> dataFrames<span class="token punctuation">[</span><span class="token string">"checkins"</span><span class="token punctuation">]</span><span class="token punctuation">.</span>iloc<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">.</span>get<span class="token punctuation">(</span><span class="token string">'id'</span><span class="token punctuation">)</span><br />    dataFrames<span class="token punctuation">[</span><span class="token string">"checkins"</span><span class="token punctuation">]</span><span class="token punctuation">.</span>loc<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">.</span>to_json<span class="token punctuation">(</span><span class="token string">"../datasets/checkins/{}.json"</span><span class="token punctuation">.</span><span class="token builtin">format</span><span class="token punctuation">(</span>idString<span class="token punctuation">)</span><span class="token punctuation">)</span></code></pre>
<p id="code-skip-day-5-scraping-data-from-foursquare-urls-1">and took a quick skim through it and it looks like everything looks good, plus I have a full archive of all the data I need.</p>
]]></content:encoded>
	</item>
	
	<item>
		<title>Dynamic DNS, getting it working - Day 5</title>
		<link>https://fightwithtools.dev/posts/projects/raspberrypi/day-5-dynamic-dns/?source=rss</link>
		<pubDate>Sat, 04 Jan 2025 22:59:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/projects/raspberrypi/day-5-dynamic-dns/</guid>
		<description>Mapping out my dynamic DNS process</description>
		<content:encoded><![CDATA[<h2 id="project-scope-and-todos" tabindex="-1">Project Scope and ToDos</h2>
<ol>
<li>Be able to host a server</li>
<li>Be able to build node projects</li>
<li>Be able to handle larger projects</li>
</ol>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Be able to run continually</li>
</ul>
<h2 id="day-4" tabindex="-1">Day 4</h2>
<p>Ok, I had to reset the device's OS to a 64-bit version because I want to do some applications that require it.</p>
<p>Now I want to use it as a web host, but that means a Dynamic DNS mapping.</p>
<p>I took a look at options and I think I can use the new registrar I've been trying out, Porkbun, directly. I use GoDaddy for most of my domains (yes I know) but their API doesn't seem to allow for you to create keys with restricted access to particular domains, it is all or nothing. <a href="https://porkbun.com/" target="_blank">Porkbun</a> apparently allows you to limit access to particular domains. So let's try that.</p>
<p>Everything I've read seems to indicate that <a href="https://github.com/ddclient/ddclient" target="_blank">DDClient</a> is the way to go, but thus far I haven't gotten it to work. Let's see what the deal is.</p>
<p>I can find the <a href="https://porkbun.com/account/api" target="_blank">Porkbun API</a> down in the footer.</p>
<p>That lets me create the key and secret for the API. Now I can see <a href="https://porkbun.com/api/json/v3/documentation" target="_blank">the API docs</a>.</p>
<p>So I'm going to test out the API to make sure my keys work:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/raspberrypi/day-5-dynamic-dns/#code-skip-day-5-dynamic-dns-9" id="skip-to-code-skip-day-5-dynamic-dns-9" class="skip-link">Skip code block ▼</a></p>
<pre class="language-bash"><code class="language-bash"><span class="token function">curl</span> <span class="token parameter variable">--request</span> GET <span class="token punctuation">\</span><br />  <span class="token parameter variable">--url</span> https://api.porkbun.com/api/json/v3/ping <span class="token punctuation">\</span><br />  <span class="token parameter variable">--header</span> <span class="token string">'Content-Type: application/json'</span> <span class="token punctuation">\</span><br />  <span class="token parameter variable">--header</span> <span class="token string">'User-Agent: insomnia/10.3.0'</span> <span class="token punctuation">\</span><br />  <span class="token parameter variable">--cookie</span> <span class="token assign-left variable">BUNSESSION2</span><span class="token operator">=</span>xxxx <span class="token punctuation">\</span><br />  <span class="token parameter variable">--data</span> <span class="token string">'{<br />	"secretapikey": "xxxxx",<br />	"apikey": "xxxxxx"<br />}<br />'</span></code></pre>
<p id="code-skip-day-5-dynamic-dns-9">Ok, that worked! I got back:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/raspberrypi/day-5-dynamic-dns/#code-skip-day-5-dynamic-dns-8" id="skip-to-code-skip-day-5-dynamic-dns-8" class="skip-link">Skip code block ▼</a></p>
<pre class="language-bash"><code class="language-bash"><span class="token punctuation">{</span><br />	<span class="token string">"status"</span><span class="token builtin class-name">:</span> <span class="token string">"SUCCESS"</span>,<br />	<span class="token string">"yourIp"</span><span class="token builtin class-name">:</span> <span class="token string">"xxxx"</span>,<br />	<span class="token string">"xForwardedFor"</span><span class="token builtin class-name">:</span> <span class="token string">"xxxx"</span><br /><span class="token punctuation">}</span></code></pre>
<p id="code-skip-day-5-dynamic-dns-8">So I know my keys work!</p>
<p>I wasn't able to get this working with GoDaddy, but that means I configured it incorrectly. So I need to know how to re-configure the config file with <code>whereis ddclient</code>.</p>
<p>Ok, that wasn't where it was, but running it did give me an error that told me where the file was. Going to try to alter the file via <code>sudo nano /etc/ddclient.conf</code> .</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/raspberrypi/day-5-dynamic-dns/#code-skip-day-5-dynamic-dns-7" id="skip-to-code-skip-day-5-dynamic-dns-7" class="skip-link">Skip code block ▼</a></p>
<pre class="language-bash"><code class="language-bash"><span class="token comment"># Configuration file for ddclient generated by debconf</span><br /><span class="token comment">#</span><br /><span class="token comment"># /etc/ddclient.conf</span><br /><br /><span class="token assign-left variable">protocol</span><span class="token operator">=</span>porkbun <span class="token punctuation">\</span><br /><span class="token assign-left variable">use</span><span class="token operator">=</span>web, <span class="token assign-left variable">web</span><span class="token operator">=</span>ipify-ipv4 <span class="token punctuation">\</span><br /><span class="token assign-left variable">login</span><span class="token operator">=</span><span class="token string">'xxxx'</span> <span class="token punctuation">\</span><br /><span class="token assign-left variable">password</span><span class="token operator">=</span><span class="token string">'xxxx'</span> <span class="token punctuation">\</span></code></pre>
<p id="code-skip-day-5-dynamic-dns-7">Huh, Porkbun isn't a protocol. Let's look and see how I activate it.</p>
<p>Ah, well it needs a different configuration:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/raspberrypi/day-5-dynamic-dns/#code-skip-day-5-dynamic-dns-6" id="skip-to-code-skip-day-5-dynamic-dns-6" class="skip-link">Skip code block ▼</a></p>
<pre class="language-bash"><code class="language-bash"><span class="token comment">##</span><br /><span class="token comment">## Porkbun (https://porkbun.com/)</span><br /><span class="token comment">##</span><br /><span class="token comment"># protocol=porkbun</span><br /><span class="token comment"># apikey=APIKey</span><br /><span class="token comment"># secretapikey=SecretAPIKey</span><br /><span class="token comment"># root-domain=example.com</span><br /><span class="token comment"># host.example.com,host2.sub.example.com</span><br /><span class="token comment"># example.com,sub.example.com</span></code></pre>
<p id="code-skip-day-5-dynamic-dns-6">Oh, apparently the package manager version is not up to date. I checked:</p>
<p><code>ddclient ---</code></p>
<p>and it is 3.10.0.</p>
<p>Looks like <a href="https://www.reddit.com/r/HomeNetworking/comments/12ytj8m/question_ddclient_with_porkbun_domain_and_their/" target="_blank">I'm not the only one with this problem</a>.</p>
<p>Let's remove the package from apt-get <code>sudo apt-get remove ddclient</code>.</p>
<p>I found something useful, <a href="https://www.youtube.com/watch?v=B2y3vT35sSE" target="_blank">Porkbun has their own walkthrough</a>! But wait... it points at depreciated tech. Ok, so build DDClient locally instead I guess!</p>
<p>I will get <a href="https://github.com/ddclient/ddclient/releases" target="_blank">the latest from the GitHub tags</a>.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/raspberrypi/day-5-dynamic-dns/#code-skip-day-5-dynamic-dns-5" id="skip-to-code-skip-day-5-dynamic-dns-5" class="skip-link">Skip code block ▼</a></p>
<pre class="language-bash"><code class="language-bash"><span class="token function">wget</span> https://github.com/ddclient/ddclient/archive/refs/tags/v3.11.2.tar.gz<br /><br /><span class="token function">tar</span> xvfa v3.11.2.tar.gz<br /><br /><span class="token builtin class-name">cd</span> ddclient-3.11.2/<br /><br /><span class="token function">sudo</span> <span class="token function">mkdir</span> /etc/ddclient<br /><br /><span class="token function">sudo</span> <span class="token function">touch</span> /etc/ddclient/ddclient.conf</code></pre>
<p id="code-skip-day-5-dynamic-dns-5">Ok, stuff isn't working. Let's try and pull it from GitHub. It says first you have to configure the project, but I don't have the needed package to run <code>autoreconf</code> so</p>
<p><code>sudo apt-get install autoconf</code></p>
<p>Ok! So now: <code>sudo ./autogen</code></p>
<p>Now I can run this?</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/raspberrypi/day-5-dynamic-dns/#code-skip-day-5-dynamic-dns-4" id="skip-to-code-skip-day-5-dynamic-dns-4" class="skip-link">Skip code block ▼</a></p>
<pre class="language-bash"><code class="language-bash">./configure <span class="token punctuation">\</span><br />    <span class="token parameter variable">--prefix</span><span class="token operator">=</span>/usr <span class="token punctuation">\</span><br />    <span class="token parameter variable">--sysconfdir</span><span class="token operator">=</span>/etc/ddclient <span class="token punctuation">\</span><br />    <span class="token parameter variable">--localstatedir</span><span class="token operator">=</span>/var</code></pre>
<p id="code-skip-day-5-dynamic-dns-4">Yes!</p>
<p>Then these commands from the ReadMe:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/raspberrypi/day-5-dynamic-dns/#code-skip-day-5-dynamic-dns-3" id="skip-to-code-skip-day-5-dynamic-dns-3" class="skip-link">Skip code block ▼</a></p>
<pre class="language-bash"><code class="language-bash"><span class="token function">make</span><br /><span class="token function">make</span> <span class="token assign-left variable">VERBOSE</span><span class="token operator">=</span><span class="token number">1</span> check<br /><span class="token function">sudo</span> <span class="token function">make</span> <span class="token function">install</span></code></pre>
<p id="code-skip-day-5-dynamic-dns-3">Now I can configure <code>sudo nano /etc/ddclient/ddclient.conf</code>.</p>
<p>Then down the readme we go!</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/raspberrypi/day-5-dynamic-dns/#code-skip-day-5-dynamic-dns-2" id="skip-to-code-skip-day-5-dynamic-dns-2" class="skip-link">Skip code block ▼</a></p>
<pre class="language-bash"><code class="language-bash"><span class="token function">cp</span> sample-etc_systemd.service /etc/systemd/system/ddclient.service<br />systemctl <span class="token builtin class-name">enable</span> ddclient.service<br />systemctl start ddclient.service</code></pre>
<p id="code-skip-day-5-dynamic-dns-2">Then I can <code>sudo</code> run the service manually to determine what is going on!</p>
<p><code>sudo ddclient -daemon=0 -debug -verbose -noquiet</code></p>
<p>Hmm, it sure is taking a while to get to <a href="https://checkip.dyndns.org/" target="_blank">https://checkip.dyndns.org/</a> :/</p>
<p>Doesn't look like it works? Not great! Let's investigate the options for the reading the data out of the router. Looks like it won't work for my router.</p>
<p>Instead let's <a href="https://github.com/ddclient/ddclient/blob/0a687d505b491e6f1c462cbe7a49e1dc60724c9a/ddclient.in#L275" target="_blank">look at other protocols</a>.</p>
<p>We can change the config to try to use a different protocol, now:</p>
<p><code>use=web, web=ipify-ipv4                                 # via web</code></p>
<p>Ok, that is finding the IP properly! But it isn't setting it into the domain.</p>
<p>Looks like I need to delete the <code>ALIAS</code> record set into the domain by default in Porkbun and replace it with an <code>A</code> record. Then the system can use that. I can also map the IP to subdomains.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/raspberrypi/day-5-dynamic-dns/#code-skip-day-5-dynamic-dns-1" id="skip-to-code-skip-day-5-dynamic-dns-1" class="skip-link">Skip code block ▼</a></p>
<pre class="language-bash"><code class="language-bash"><span class="token assign-left variable">protocol</span><span class="token operator">=</span>porkbun<br /><span class="token assign-left variable">apikey</span><span class="token operator">=</span>xxxx<br /><span class="token assign-left variable">secretapikey</span><span class="token operator">=</span>xxxx<br />www.my.domain<br />on-root-domain<span class="token operator">=</span>yes my.domain</code></pre>
<p id="code-skip-day-5-dynamic-dns-1">And hey, that brings me to my home router &gt;.&lt;</p>
<p>I can, however, access the service on the port it is running on via the domain <a href="https://portforward.com/" target="_blank">once I've set up port forwarding for that port</a>, so I'm getting close!</p>
<p><a href="https://community.verizon.com/t5/Fios-Internet-and-High-Speed/Internet-ports-80-and-443/m-p/1462542" target="_blank">It looks like my particular Verizon router may just not allow me to open port 80</a>. Ok, let's try to go on with setting up the task that will keep the static IP up to date for now. At some point in the future I <a href="https://pimylifeup.com/raspberry-pi-ssl-lets-encrypt/" target="_blank">may want to figure out an HTTPS cert</a> as well, once I got everything mapped.</p>
<p>Ok, no, the setup instructions do activate the daemon on the server for ddclient and set it up to come back online when the system restarts. That's good, it should keep my Raspberry Pi connected to the domain.</p>
<p>I think this is a good place to stop, nifty to get this work!</p>
]]></content:encoded>
	</item>
	
	<item>
		<title>Dealing with Foursquare checkins that don't have an API response</title>
		<link>https://fightwithtools.dev/posts/projects/foursquare-location-data-site/day-4-dealing-with-404-locations/?source=rss</link>
		<pubDate>Sat, 04 Jan 2025 15:59:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/projects/foursquare-location-data-site/day-4-dealing-with-404-locations/</guid>
		<description>If it doesn't make money it apparently isn't in the Foursquare API</description>
		<content:encoded><![CDATA[<h2 id="project-scope-and-todos" tabindex="-1">Project Scope and ToDos</h2>
<ol>
<li>Create a new site</li>
<li>Process the Foursquare data to a set of locations with additional data</li>
<li>Set the data up so it can be put on a map (it needs lat and long)</li>
</ol>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Can be searched</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Can show travel paths throughout a day</li>
</ul>
<h2 id="day-4" tabindex="-1">Day 4</h2>
<p>Ok, I've got the whole setup for retrieving from the API done. Places that 200 are being integrated into the dataframe successfully and also being written to local JSON files.</p>
<p>There's only one problem, check-in locations that don't correspond to a business aren't in <a href="https://docs.foursquare.com/developer/reference/place-details" target="_blank">the API</a> and I have a ton of them.</p>
<p>I'm going to write them all to files, this allows me to debug them a little easier.</p>
<p><a target="_blank" href="https://github.com/AramZS/locations/commit/90cffeaa25c962e9ff60482947bf88e0339ca60f" class="git-commit-link"><code>git commit -am &quot;Adding more processing for Foursquare's API to get the data I need.&quot;</code></a></p>
<p>I think I'm going to have to crawl the pages, which are still up for now. That will hopefully get me the data I need.</p>
<p>Every page has this data in the HEAD, it looks like!</p>
<p>We can see lat and long in:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/foursquare-location-data-site/day-4-dealing-with-404-locations/#code-skip-day-4-dealing-with-404-locations-2" id="skip-to-code-skip-day-4-dealing-with-404-locations-2" class="skip-link">Skip code block ▼</a></p>
<pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>meta</span> <span class="token attr-name">content</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>40.73920556687168<span class="token punctuation">"</span></span> <span class="token attr-name">property</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>playfoursquare:location:latitude<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><br /><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>meta</span> <span class="token attr-name">content</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>-73.95259827375412<span class="token punctuation">"</span></span> <span class="token attr-name">property</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>playfoursquare:location:longitude<span class="token punctuation">"</span></span><span class="token punctuation">></span></span></code></pre>
<p id="code-skip-day-4-dealing-with-404-locations-2">That is likely all I need, but I can also get the address info it looks like, that's on the page in structured HTML:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/foursquare-location-data-site/day-4-dealing-with-404-locations/#code-skip-day-4-dealing-with-404-locations-1" id="skip-to-code-skip-day-4-dealing-with-404-locations-1" class="skip-link">Skip code block ▼</a></p>
<pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>venueAddress<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><br />	<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>adr<span class="token punctuation">"</span></span> <span class="token attr-name">itemprop</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>address<span class="token punctuation">"</span></span> <span class="token attr-name">itemscope</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span><span class="token punctuation">"</span></span> <span class="token attr-name">itemtype</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>http://schema.org/PostalAddress<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><br />		<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">itemprop</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>streetAddress<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Pulaski Bridge<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">></span></span> (at Newtown Creek)<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>br</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">itemprop</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>addressLocality<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Brooklyn<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">></span></span>, <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">itemprop</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>addressRegion<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>NY<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">itemprop</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>postalCode<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>11211<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">></span></span><br />	<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span><br /><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span></code></pre>
<p id="code-skip-day-4-dealing-with-404-locations-1">I'll need to add a function to access the <code>url</code> from the dataframe and crawl that page, and do it quickly before this stuff goes offline, assuming it still will. I can then pull that data into my dataframe.</p>
<p>I'll likely have to use <a href="https://beautiful-soup-4.readthedocs.io/en/latest/" target="_blank">beautifulsoup</a>.</p>
<p>I also should investigate if <a href="https://location.foursquare.com/resources/blog/products/foursquare-open-source-places-a-new-foundational-dataset-for-the-geospatial-community/" target="_blank">the new Places data set</a> that was open sourced might have this data and, if so, how I can access it.</p>
]]></content:encoded>
	</item>
	
	<item>
		<title>Moving the python for processing Foursquare data into more manageable functions</title>
		<link>https://fightwithtools.dev/posts/projects/foursquare-location-data-site/day-3-functions-processing/?source=rss</link>
		<pubDate>Mon, 30 Dec 2024 14:59:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/projects/foursquare-location-data-site/day-3-functions-processing/</guid>
		<description>Maybe I might make this a module later?</description>
		<content:encoded><![CDATA[<h2 id="project-scope-and-todos" tabindex="-1">Project Scope and ToDos</h2>
<ol>
<li>Create a new site</li>
<li>Process the Foursquare data to a set of locations with additional data</li>
<li>Set the data up so it can be put on a map (it needs lat and long)</li>
</ol>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Can be searched</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Can show travel paths throughout a day</li>
</ul>
<h2 id="day-3" tabindex="-1">Day 3</h2>
<p>Moving my work from the Jupyter Notebook into some more useful functions that make it easier to understand what is going on took some adjustments. I want to make the flow simpler and take less code as well. Some accidents along the way, but I think I have it working.</p>
<p>I wanted to flatten the items files as well as use the loop more simply to create a base object that is generic for multiple data files. This means changing some of the downstream functions as well.</p>
<p>I also want to make the whole project as flat as possible while providing some logical divisions for the files based on what needs to be imported and what the functions do.</p>
<p>I also took a look at what to do with the <strong>init</strong> file:</p>
<ul>
<li><a href="https://stackoverflow.com/questions/448271/what-is-init-py-for" target="_blank">python - What is __init__.py for? - Stack Overflow</a></li>
<li><a href="https://www.reddit.com/r/Python/comments/1bbbwk/whats_your_opinion_on_what_to_include_in_init_py/" target="_blank">What's your opinion on what to include in __init__.py ? : r/Python</a></li>
<li><a href="https://docs.python-guide.org/writing/structure/" target="_blank">Structuring Your Project — The Hitchhiker's Guide to Python</a></li>
<li><a href="https://stackoverflow.com/questions/1801878/the-pythonic-way-of-organizing-modules-and-packages" target="_blank">python - The Pythonic way of organizing modules and packages - Stack Overflow</a></li>
<li><a href="https://stackoverflow.com/questions/1944569/how-do-i-write-good-correct-package-init-py-files" target="_blank">python - How do I write good/correct package __init__.py files - Stack Overflow</a></li>
<li><a href="https://stackoverflow.com/questions/2360724/what-exactly-does-import-import" target="_blank">python - What exactly does &quot;import *&quot; import? - Stack Overflow</a></li>
</ul>
<p>I ended up using it to refine the exposed API like so:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/foursquare-location-data-site/day-3-functions-processing/#code-skip-day-3-functions-processing-1" id="skip-to-code-skip-day-3-functions-processing-1" class="skip-link">Skip code block ▼</a></p>
<pre class="language-python"><code class="language-python"><span class="token keyword">from</span> <span class="token punctuation">.</span>process_to_dfs <span class="token keyword">import</span> process_to_dfs<span class="token punctuation">,</span> get_place_details<br /><span class="token keyword">from</span> <span class="token punctuation">.</span>pull_in_data_files <span class="token keyword">import</span> pull_in_data_files</code></pre>
<p id="code-skip-day-3-functions-processing-1">Ok, got the data retrieval and the processing into dataframes working now!</p>
<p><a target="_blank" href="https://github.com/AramZS/locations/commit/665a78e870ee7fa93a97b5164ad96338f3a17aa7" class="git-commit-link"><code>git commit -am &quot;Process data files into data frames&quot;</code></a></p>
]]></content:encoded>
	</item>
	
	<item>
		<title>Handling photos and getting the actual locations for Foursquare location data from an export</title>
		<link>https://fightwithtools.dev/posts/projects/foursquare-location-data-site/day-2-process-photos/?source=rss</link>
		<pubDate>Thu, 26 Dec 2024 14:59:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/projects/foursquare-location-data-site/day-2-process-photos/</guid>
		<description>Foursquare export files with venues and checkins somehow don't have the actual lat and long data I need.</description>
		<content:encoded><![CDATA[<h2 id="project-scope-and-todos" tabindex="-1">Project Scope and ToDos</h2>
<ol>
<li>Create a new site</li>
<li>Process the Foursquare data to a set of locations with additional data</li>
<li>Set the data up so it can be put on a map (it needs lat and long)</li>
</ol>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Can be searched</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Can show travel paths throughout a day</li>
</ul>
<h2 id="day-2" tabindex="-1">Day 2</h2>
<p>I think I got it writing photos effectively, but I think I made a mistake trying to put them in the venue dataframe. I need a photo table.</p>
<p><a target="_blank" href="https://github.com/AramZS/locations/commit/5df3d3aabbce8b5d47117f11e8e3ccb132b9b70d" class="git-commit-link"><code>git commit -am &quot;Setting up a dataframe for individual photos&quot;</code></a></p>
<p>Ok, I can see how to do it, but the sequence is getting complicated. I want to actually set up some functions and call them into the notebook I'm working on. Then I need to do the next thing, which is resolve venues to have lat and long values.</p>
<p><a target="_blank" href="https://github.com/AramZS/locations/commit/8f8077b04a281fe5242727e5e72a9737e9c448a9" class="git-commit-link"><code>git commit -am &quot;Processing sequence of files into dataframes now in functions&quot;</code></a></p>
<p>Oh, I know some photos exist without a checkin, which means no venue entry. I'll have to add that.</p>
<p><a target="_blank" href="https://github.com/AramZS/locations/commit/3920cd3566c5e74417921963021a376794ebd7c6" class="git-commit-link"><code>git commit -am &quot;Photos should always have venues associated with them.&quot;</code></a></p>
<p>Ok, so now we gotta look at hitting the Foursquare API to get the correct lat and long data.</p>
<h2 id="using-the-foursquare-api" tabindex="-1">Using the Foursquare API</h2>
<p>Ok, I tried out the <a href="https://docs.foursquare.com/developer/reference/place-details" target="_blank">place details endpoint in the FourSquare API Explorer</a>.</p>
<p>It returns an object like this:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/foursquare-location-data-site/day-2-process-photos/#code-skip-day-2-process-photos-2" id="skip-to-code-skip-day-2-process-photos-2" class="skip-link">Skip code block ▼</a></p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span><br />  <span class="token property">"fsq_id"</span><span class="token operator">:</span> <span class="token string">"59e63da08c35dc3e57ab5520"</span><span class="token punctuation">,</span><br />  <span class="token property">"categories"</span><span class="token operator">:</span> <span class="token punctuation">[</span><br />    <span class="token punctuation">{</span><br />      <span class="token property">"id"</span><span class="token operator">:</span> <span class="token number">10032</span><span class="token punctuation">,</span><br />      <span class="token property">"name"</span><span class="token operator">:</span> <span class="token string">"Night Club"</span><span class="token punctuation">,</span><br />      <span class="token property">"short_name"</span><span class="token operator">:</span> <span class="token string">"Night Club"</span><span class="token punctuation">,</span><br />      <span class="token property">"plural_name"</span><span class="token operator">:</span> <span class="token string">"Night Clubs"</span><span class="token punctuation">,</span><br />      <span class="token property">"icon"</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />        <span class="token property">"prefix"</span><span class="token operator">:</span> <span class="token string">"https://ss3.4sqi.net/img/categories_v2/nightlife/nightclub_"</span><span class="token punctuation">,</span><br />        <span class="token property">"suffix"</span><span class="token operator">:</span> <span class="token string">".png"</span><br />      <span class="token punctuation">}</span><br />    <span class="token punctuation">}</span><span class="token punctuation">,</span><br />    <span class="token punctuation">{</span><br />      <span class="token property">"id"</span><span class="token operator">:</span> <span class="token number">13009</span><span class="token punctuation">,</span><br />      <span class="token property">"name"</span><span class="token operator">:</span> <span class="token string">"Cocktail Bar"</span><span class="token punctuation">,</span><br />      <span class="token property">"short_name"</span><span class="token operator">:</span> <span class="token string">"Cocktail"</span><span class="token punctuation">,</span><br />      <span class="token property">"plural_name"</span><span class="token operator">:</span> <span class="token string">"Cocktail Bars"</span><span class="token punctuation">,</span><br />      <span class="token property">"icon"</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />        <span class="token property">"prefix"</span><span class="token operator">:</span> <span class="token string">"https://ss3.4sqi.net/img/categories_v2/nightlife/cocktails_"</span><span class="token punctuation">,</span><br />        <span class="token property">"suffix"</span><span class="token operator">:</span> <span class="token string">".png"</span><br />      <span class="token punctuation">}</span><br />    <span class="token punctuation">}</span><span class="token punctuation">,</span><br />    <span class="token punctuation">{</span><br />      <span class="token property">"id"</span><span class="token operator">:</span> <span class="token number">13021</span><span class="token punctuation">,</span><br />      <span class="token property">"name"</span><span class="token operator">:</span> <span class="token string">"Speakeasy"</span><span class="token punctuation">,</span><br />      <span class="token property">"short_name"</span><span class="token operator">:</span> <span class="token string">"Speakeasy"</span><span class="token punctuation">,</span><br />      <span class="token property">"plural_name"</span><span class="token operator">:</span> <span class="token string">"Speakeasies"</span><span class="token punctuation">,</span><br />      <span class="token property">"icon"</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />        <span class="token property">"prefix"</span><span class="token operator">:</span> <span class="token string">"https://ss3.4sqi.net/img/categories_v2/nightlife/secretbar_"</span><span class="token punctuation">,</span><br />        <span class="token property">"suffix"</span><span class="token operator">:</span> <span class="token string">".png"</span><br />      <span class="token punctuation">}</span><br />    <span class="token punctuation">}</span><br />  <span class="token punctuation">]</span><span class="token punctuation">,</span><br />  <span class="token property">"chains"</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br />  <span class="token property">"closed_bucket"</span><span class="token operator">:</span> <span class="token string">"Unsure"</span><span class="token punctuation">,</span><br />  <span class="token property">"geocodes"</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />    <span class="token property">"drop_off"</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />      <span class="token property">"latitude"</span><span class="token operator">:</span> <span class="token number">40.745138</span><span class="token punctuation">,</span><br />      <span class="token property">"longitude"</span><span class="token operator">:</span> <span class="token number">-73.990299</span><br />    <span class="token punctuation">}</span><span class="token punctuation">,</span><br />    <span class="token property">"main"</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />      <span class="token property">"latitude"</span><span class="token operator">:</span> <span class="token number">40.745324</span><span class="token punctuation">,</span><br />      <span class="token property">"longitude"</span><span class="token operator">:</span> <span class="token number">-73.990221</span><br />    <span class="token punctuation">}</span><span class="token punctuation">,</span><br />    <span class="token property">"roof"</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />      <span class="token property">"latitude"</span><span class="token operator">:</span> <span class="token number">40.745324</span><span class="token punctuation">,</span><br />      <span class="token property">"longitude"</span><span class="token operator">:</span> <span class="token number">-73.990221</span><br />    <span class="token punctuation">}</span><br />  <span class="token punctuation">}</span><span class="token punctuation">,</span><br />  <span class="token property">"link"</span><span class="token operator">:</span> <span class="token string">"/v3/places/59e63da08c35dc3e57ab5520"</span><span class="token punctuation">,</span><br />  <span class="token property">"location"</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />    <span class="token property">"address"</span><span class="token operator">:</span> <span class="token string">"49 W 27th St"</span><span class="token punctuation">,</span><br />    <span class="token property">"census_block"</span><span class="token operator">:</span> <span class="token string">"360610058001001"</span><span class="token punctuation">,</span><br />    <span class="token property">"country"</span><span class="token operator">:</span> <span class="token string">"US"</span><span class="token punctuation">,</span><br />    <span class="token property">"cross_street"</span><span class="token operator">:</span> <span class="token string">"btwn Broadway &amp; 6th Ave"</span><span class="token punctuation">,</span><br />    <span class="token property">"dma"</span><span class="token operator">:</span> <span class="token string">"New York"</span><span class="token punctuation">,</span><br />    <span class="token property">"formatted_address"</span><span class="token operator">:</span> <span class="token string">"49 W 27th St (btwn Broadway &amp; 6th Ave), New York, NY 10001"</span><span class="token punctuation">,</span><br />    <span class="token property">"locality"</span><span class="token operator">:</span> <span class="token string">"New York"</span><span class="token punctuation">,</span><br />    <span class="token property">"postcode"</span><span class="token operator">:</span> <span class="token string">"10001"</span><span class="token punctuation">,</span><br />    <span class="token property">"region"</span><span class="token operator">:</span> <span class="token string">"NY"</span><br />  <span class="token punctuation">}</span><span class="token punctuation">,</span><br />  <span class="token property">"name"</span><span class="token operator">:</span> <span class="token string">"Patent Pending"</span><span class="token punctuation">,</span><br />  <span class="token property">"related_places"</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />    <span class="token property">"parent"</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />      <span class="token property">"fsq_id"</span><span class="token operator">:</span> <span class="token string">"59e618dc4c9be64fbe509006"</span><span class="token punctuation">,</span><br />      <span class="token property">"categories"</span><span class="token operator">:</span> <span class="token punctuation">[</span><br />        <span class="token punctuation">{</span><br />          <span class="token property">"id"</span><span class="token operator">:</span> <span class="token number">13035</span><span class="token punctuation">,</span><br />          <span class="token property">"name"</span><span class="token operator">:</span> <span class="token string">"Coffee Shop"</span><span class="token punctuation">,</span><br />          <span class="token property">"short_name"</span><span class="token operator">:</span> <span class="token string">"Coffee Shop"</span><span class="token punctuation">,</span><br />          <span class="token property">"plural_name"</span><span class="token operator">:</span> <span class="token string">"Coffee Shops"</span><span class="token punctuation">,</span><br />          <span class="token property">"icon"</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />            <span class="token property">"prefix"</span><span class="token operator">:</span> <span class="token string">"https://ss3.4sqi.net/img/categories_v2/food/coffeeshop_"</span><span class="token punctuation">,</span><br />            <span class="token property">"suffix"</span><span class="token operator">:</span> <span class="token string">".png"</span><br />          <span class="token punctuation">}</span><br />        <span class="token punctuation">}</span><span class="token punctuation">,</span><br />        <span class="token punctuation">{</span><br />          <span class="token property">"id"</span><span class="token operator">:</span> <span class="token number">13034</span><span class="token punctuation">,</span><br />          <span class="token property">"name"</span><span class="token operator">:</span> <span class="token string">"Café"</span><span class="token punctuation">,</span><br />          <span class="token property">"short_name"</span><span class="token operator">:</span> <span class="token string">"Café"</span><span class="token punctuation">,</span><br />          <span class="token property">"plural_name"</span><span class="token operator">:</span> <span class="token string">"Cafés"</span><span class="token punctuation">,</span><br />          <span class="token property">"icon"</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />            <span class="token property">"prefix"</span><span class="token operator">:</span> <span class="token string">"https://ss3.4sqi.net/img/categories_v2/food/cafe_"</span><span class="token punctuation">,</span><br />            <span class="token property">"suffix"</span><span class="token operator">:</span> <span class="token string">".png"</span><br />          <span class="token punctuation">}</span><br />        <span class="token punctuation">}</span><br />      <span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token property">"name"</span><span class="token operator">:</span> <span class="token string">"Patent Coffee"</span><br />    <span class="token punctuation">}</span><br />  <span class="token punctuation">}</span><span class="token punctuation">,</span><br />  <span class="token property">"timezone"</span><span class="token operator">:</span> <span class="token string">"America/New_York"</span><br /><span class="token punctuation">}</span></code></pre>
<p id="code-skip-day-2-process-photos-2">Ok, that has all the information I need! And a lot more besides. I was thinking I could just pull the information in to the dataframe, and I think that is true, but also I think I want to just replicate the object into a physical file for now. I might want to do more with it later.</p>
<p>I want to play around with these new functions and <a href="https://saturncloud.io/blog/how-to-import-python-file-as-module-in-jupyter-notebook/" target="_blank">test them</a> in my Jupyter Notebook. <a href="https://stackoverflow.com/questions/1254370/reimport-a-module-while-interactive" target="_blank">Looks like</a> the best way to do this is with <a href="https://ipython.readthedocs.io/en/stable/config/extensions/autoreload.html" target="_blank">autoreload</a>.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/foursquare-location-data-site/day-2-process-photos/#code-skip-day-2-process-photos-1" id="skip-to-code-skip-day-2-process-photos-1" class="skip-link">Skip code block ▼</a></p>
<pre class="language-python"><code class="language-python"><span class="token operator">%</span>autoreload <span class="token number">2</span><br /><span class="token keyword">import</span> data_processing<br /><br />config <span class="token operator">=</span> dotenv_values<span class="token punctuation">(</span><span class="token string">'../.env'</span><span class="token punctuation">)</span><br />apiKey <span class="token operator">=</span> config<span class="token punctuation">[</span><span class="token string">'FSQ_API_KEY'</span><span class="token punctuation">]</span><br /><br />data_processing<span class="token punctuation">.</span>get_place_details<span class="token punctuation">(</span><span class="token string">"59e63da08c35dc3e57ab5520"</span><span class="token punctuation">,</span> apiKey<span class="token punctuation">)</span></code></pre>
<p id="code-skip-day-2-process-photos-1"><a target="_blank" href="https://github.com/AramZS/locations/commit/95ac2b1100bc617070d598d5aae836b95c4a5aa6" class="git-commit-link"><code>git commit -am &quot;Adding FSq API checks and file writing and new notebook for testing functions&quot;</code></a></p>
]]></content:encoded>
	</item>
	
	<item>
		<title>Setting up a python project to handle Foursquare data exports</title>
		<link>https://fightwithtools.dev/posts/projects/foursquare-location-data-site/day-1-getting-a-handle-on-the-data/?source=rss</link>
		<pubDate>Wed, 25 Dec 2024 14:59:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/projects/foursquare-location-data-site/day-1-getting-a-handle-on-the-data/</guid>
		<description>Foursquare gave me a big hunk of data files, now what do I do with it?</description>
		<content:encoded><![CDATA[<h2 id="project-scope-and-todos" tabindex="-1">Project Scope and ToDos</h2>
<ol>
<li>Create a new site</li>
<li>Process the Foursquare data to a set of locations with additional data</li>
<li>Set the data up so it can be put on a map (it needs lat and long)</li>
</ol>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Can be searched</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Can show travel paths throughout a day</li>
</ul>
<h2 id="day-1" tabindex="-1">Day 1</h2>
<p>Since the Foursquare site is shutting down I got a data export. I have to decide what I want to do with it now that I have it. It is a big set of data, so I will need to do some work to make it usable and figure out how to treat it and turn it into the type of site I want.</p>
<p>Big dataset, so let's turn to Python to process it. That's what it is best at. It has been a while, but I can start drawing some interesting conclusions from it for sure.</p>
<p>There are a bunch of different files, and it seems like the <code>checkins</code> files are the most relevant. But they don't have latitude and longitude data attached. That's not great. I also have a <code>visits</code> file that does have latitude and longitude, but it does seem to map to anything.</p>
<p>I'll assemble the data into a Pandas dataframe to start playing with it. See if I can find if the two connect at all.</p>
<p>It looks like someone else has encountered this problem. <a href="https://stackoverflow.com/questions/77261620/get-lat-long-of-foursquare-data" target="_blank">They recommend hitting the Foursquare API to get the lat/long</a>.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/foursquare-location-data-site/day-1-getting-a-handle-on-the-data/#code-skip-day-1-getting-a-handle-on-the-data-17" id="skip-to-code-skip-day-1-getting-a-handle-on-the-data-17" class="skip-link">Skip code block ▼</a></p>
<pre class="language-python"><code class="language-python"><span class="token keyword">import</span> requests<br /><span class="token keyword">import</span> json<br /><span class="token keyword">import</span> csv<br /><br />headers <span class="token operator">=</span> <span class="token punctuation">{</span><br />    <span class="token string">"accept"</span><span class="token punctuation">:</span> <span class="token string">"application/json"</span><span class="token punctuation">,</span><br />    <span class="token string">"Authorization"</span><span class="token punctuation">:</span> <span class="token string">"YOUR_API_KEY"</span><br /><span class="token punctuation">}</span><br /><br /><span class="token comment"># define path for products adoc file</span><br />path <span class="token operator">=</span> <span class="token string">r'foursquare.csv'</span><br /><br /><span class="token comment"># clear attributes file if exists</span><br />c <span class="token operator">=</span> <span class="token builtin">open</span><span class="token punctuation">(</span>path<span class="token punctuation">,</span><span class="token string">'w'</span><span class="token punctuation">)</span><br />c<span class="token punctuation">.</span>close<span class="token punctuation">(</span><span class="token punctuation">)</span><br />csv <span class="token operator">=</span> <span class="token builtin">open</span><span class="token punctuation">(</span>path<span class="token punctuation">,</span> <span class="token string">'a'</span><span class="token punctuation">)</span><br /><br /><span class="token keyword">with</span> <span class="token builtin">open</span><span class="token punctuation">(</span><span class="token string">'ids.txt'</span><span class="token punctuation">,</span> <span class="token string">'r'</span><span class="token punctuation">)</span> <span class="token keyword">as</span> f<span class="token punctuation">:</span><br />  <span class="token keyword">for</span> line <span class="token keyword">in</span> f<span class="token punctuation">:</span><br />    fsq_id <span class="token operator">=</span> <span class="token builtin">str</span><span class="token punctuation">(</span>line<span class="token punctuation">)</span><span class="token punctuation">.</span>replace<span class="token punctuation">(</span><span class="token string">"\n"</span><span class="token punctuation">,</span><span class="token string">""</span><span class="token punctuation">)</span><br />    url <span class="token operator">=</span> <span class="token string">"https://api.foursquare.com/v3/places/"</span><span class="token operator">+</span>fsq_id<span class="token operator">+</span><span class="token string">"?fields=geocodes"</span><br />    response <span class="token operator">=</span> requests<span class="token punctuation">.</span>get<span class="token punctuation">(</span>url<span class="token punctuation">,</span> headers<span class="token operator">=</span>headers<span class="token punctuation">)</span><br />    <span class="token keyword">if</span> response<span class="token punctuation">.</span>status_code <span class="token operator">!=</span> <span class="token number">404</span><span class="token punctuation">:</span><br />        locations <span class="token operator">=</span> response<span class="token punctuation">.</span>json<span class="token punctuation">(</span><span class="token punctuation">)</span><br />        csv<span class="token punctuation">.</span>write<span class="token punctuation">(</span>fsq_id<span class="token punctuation">)</span><br />        csv<span class="token punctuation">.</span>write<span class="token punctuation">(</span><span class="token string">", "</span><span class="token punctuation">)</span><br />        csv<span class="token punctuation">.</span>write<span class="token punctuation">(</span><span class="token builtin">str</span><span class="token punctuation">(</span>locations<span class="token punctuation">[</span><span class="token string">'geocodes'</span><span class="token punctuation">]</span><span class="token punctuation">[</span><span class="token string">'main'</span><span class="token punctuation">]</span><span class="token punctuation">[</span><span class="token string">'latitude'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">)</span><br />        csv<span class="token punctuation">.</span>write<span class="token punctuation">(</span><span class="token string">", "</span><span class="token punctuation">)</span><br />        csv<span class="token punctuation">.</span>write<span class="token punctuation">(</span><span class="token builtin">str</span><span class="token punctuation">(</span>locations<span class="token punctuation">[</span><span class="token string">'geocodes'</span><span class="token punctuation">]</span><span class="token punctuation">[</span><span class="token string">'main'</span><span class="token punctuation">]</span><span class="token punctuation">[</span><span class="token string">'longitude'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">)</span><br />        csv<span class="token punctuation">.</span>write<span class="token punctuation">(</span><span class="token string">"\n"</span><span class="token punctuation">)</span><br /><br /><span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string">"done"</span><span class="token punctuation">)</span></code></pre>
<p id="code-skip-day-1-getting-a-handle-on-the-data-17">This leverages the <a href="https://location.foursquare.com/developer/reference/place-details" target="_blank">Place Details API</a>.</p>
<p>Once I loaded the JSON files into memory, I can walk them into a dataframe:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/foursquare-location-data-site/day-1-getting-a-handle-on-the-data/#code-skip-day-1-getting-a-handle-on-the-data-16" id="skip-to-code-skip-day-1-getting-a-handle-on-the-data-16" class="skip-link">Skip code block ▼</a></p>
<pre class="language-python"><code class="language-python"><span class="token comment"># Create a DataFrame from the list of dictionaries</span><br />df <span class="token operator">=</span> pd<span class="token punctuation">.</span>DataFrame<span class="token punctuation">(</span>columns<span class="token operator">=</span><span class="token punctuation">[</span><br />    <span class="token string">'id'</span><span class="token punctuation">,</span><br />    <span class="token string">'createdAt'</span><span class="token punctuation">,</span><br />    <span class="token string">'type'</span><span class="token punctuation">,</span><br />    <span class="token comment"># 'visibility',</span><br />    <span class="token string">'timeZoneOffset'</span><span class="token punctuation">,</span><br />    <span class="token string">'venueId'</span><span class="token punctuation">,</span><br />    <span class="token string">'venueName'</span><span class="token punctuation">,</span><br />    <span class="token string">'venueURL'</span><span class="token punctuation">,</span><br />    <span class="token string">'commentsCount'</span><br /><span class="token punctuation">]</span><span class="token punctuation">)</span><br /><br /><span class="token keyword">for</span> checkinList <span class="token keyword">in</span> data<span class="token punctuation">:</span><br />	<span class="token keyword">for</span> item <span class="token keyword">in</span> checkinList<span class="token punctuation">[</span><span class="token string">"items"</span><span class="token punctuation">]</span><span class="token punctuation">:</span><br />		<span class="token keyword">if</span> <span class="token string">'venue'</span> <span class="token keyword">not</span> <span class="token keyword">in</span> item<span class="token punctuation">:</span><br />			<span class="token keyword">continue</span><br />		df <span class="token operator">=</span> pd<span class="token punctuation">.</span>concat<span class="token punctuation">(</span><span class="token punctuation">[</span>pd<span class="token punctuation">.</span>DataFrame<span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token punctuation">[</span><br />      item<span class="token punctuation">[</span><span class="token string">'id'</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br />      item<span class="token punctuation">[</span><span class="token string">'createdAt'</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br />      item<span class="token punctuation">[</span><span class="token string">'type'</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token comment"># item['visibility'],</span><br />      item<span class="token punctuation">[</span><span class="token string">'timeZoneOffset'</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br />      item<span class="token punctuation">[</span><span class="token string">'venue'</span><span class="token punctuation">]</span><span class="token punctuation">[</span><span class="token string">'id'</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br />      item<span class="token punctuation">[</span><span class="token string">'venue'</span><span class="token punctuation">]</span><span class="token punctuation">[</span><span class="token string">'name'</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br />      item<span class="token punctuation">[</span><span class="token string">'venue'</span><span class="token punctuation">]</span><span class="token punctuation">[</span><span class="token string">'url'</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br />      item<span class="token punctuation">[</span><span class="token string">'comments'</span><span class="token punctuation">]</span><span class="token punctuation">[</span><span class="token string">'count'</span><span class="token punctuation">]</span><br />      <span class="token punctuation">]</span><span class="token punctuation">]</span><span class="token punctuation">,</span> columns<span class="token operator">=</span>df<span class="token punctuation">.</span>columns<span class="token punctuation">)</span><span class="token punctuation">,</span> df<span class="token punctuation">]</span><span class="token punctuation">,</span> ignore_index<span class="token operator">=</span><span class="token boolean">True</span><span class="token punctuation">)</span><br /><br /><br /><span class="token keyword">print</span><span class="token punctuation">(</span>df<span class="token punctuation">.</span>shape<span class="token punctuation">)</span></code></pre>
<p id="code-skip-day-1-getting-a-handle-on-the-data-16">Checked and for some reason only 1000 items don't have visibility, I've manually defaulted those to &quot;private&quot;.</p>
<p>Even now that I've got those included though, the IDs in <code>visits.json</code> and <code>visits.csv</code> don't map to anything in my checkins.</p>
<p>Now my total checkins in the dataframe are <code>14265</code> entries.</p>
<p>Ok, so visits seems to be non-check-in occurrences where I was at a location. The Swarm app will occasionally have draft checkins that it suggests, saying it thinks I was in a particular location and prompting me to check in, correct, or not. This appears to be what is going on here. So for example</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/foursquare-location-data-site/day-1-getting-a-handle-on-the-data/#code-skip-day-1-getting-a-handle-on-the-data-15" id="skip-to-code-skip-day-1-getting-a-handle-on-the-data-15" class="skip-link">Skip code block ▼</a></p>
<pre class="language-json"><code class="language-json">		<span class="token punctuation">{</span><br />			<span class="token property">"id"</span><span class="token operator">:</span> <span class="token string">"673e69ccdc7d4627b68ceb3b"</span><span class="token punctuation">,</span><br />			<span class="token property">"userId"</span><span class="token operator">:</span> <span class="token string">"15234"</span><span class="token punctuation">,</span><br />			<span class="token property">"timeArrived"</span><span class="token operator">:</span> <span class="token string">"2024-11-20 22:59:24.483000"</span><span class="token punctuation">,</span><br />			<span class="token property">"timeDeparted"</span><span class="token operator">:</span> <span class="token string">"2024-11-20 23:15:22.419000"</span><span class="token punctuation">,</span><br />			<span class="token property">"os"</span><span class="token operator">:</span> <span class="token string">"Android"</span><span class="token punctuation">,</span><br />			<span class="token property">"osVersion"</span><span class="token operator">:</span> <span class="token string">"12"</span><span class="token punctuation">,</span><br />			<span class="token property">"deviceModel"</span><span class="token operator">:</span> <span class="token string">"SM-G975U1"</span><span class="token punctuation">,</span><br />			<span class="token property">"isTraveling"</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span><br />			<span class="token property">"latitude"</span><span class="token operator">:</span> <span class="token number">40.6436454</span><span class="token punctuation">,</span><br />			<span class="token property">"longitude"</span><span class="token operator">:</span> <span class="token number">-74.072583</span><span class="token punctuation">,</span><br />			<span class="token property">"city"</span><span class="token operator">:</span> <span class="token string">"Staten Island"</span><span class="token punctuation">,</span><br />			<span class="token property">"state"</span><span class="token operator">:</span> <span class="token string">"New York"</span><span class="token punctuation">,</span><br />			<span class="token property">"postalCode"</span><span class="token operator">:</span> <span class="token string">"8600000US10301"</span><span class="token punctuation">,</span><br />			<span class="token property">"countryCode"</span><span class="token operator">:</span> <span class="token string">"US"</span><span class="token punctuation">,</span><br />			<span class="token property">"locationType"</span><span class="token operator">:</span> <span class="token string">"Venue"</span><br />		<span class="token punctuation">}</span></code></pre>
<p id="code-skip-day-1-getting-a-handle-on-the-data-15">Is a visit. And it happens around the same time as check-ins that I actually made. I looked up the lat/long and found the location seemed to be the Staten Island ferry terminal.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/foursquare-location-data-site/day-1-getting-a-handle-on-the-data/#code-skip-day-1-getting-a-handle-on-the-data-14" id="skip-to-code-skip-day-1-getting-a-handle-on-the-data-14" class="skip-link">Skip code block ▼</a></p>
<pre class="language-python"><code class="language-python"><span class="token keyword">print</span><span class="token punctuation">(</span>df<span class="token punctuation">.</span>query<span class="token punctuation">(</span><span class="token string">'venueName.str.contains("Staten Island")'</span><span class="token punctuation">)</span><span class="token punctuation">)</span></code></pre>
<p id="code-skip-day-1-getting-a-handle-on-the-data-14">Here's the result:</p>
<table>
<thead>
<tr>
<th>id</th>
<th>createdAt</th>
<th>type</th>
<th>visibility</th>
<th>timeZoneOffset</th>
<th>venueId</th>
<th>venueName</th>
<th>venueUrl</th>
<th>commentsCount</th>
</tr>
</thead>
<tbody>
<tr>
<td>5bc75aa89cadd9002ce17dc3</td>
<td>2018-10-17 15:52:08.000000</td>
<td>checkin</td>
<td>private</td>
<td>-240</td>
<td>4165d880f964a5207e1d1fe3</td>
<td>Staten Island Ferry - Whitehall Terminal</td>
<td><a href="https://foursquare.com/v/staten-island-ferry--" target="_blank">https://foursquare.com/v/staten-island-ferry--</a>...</td>
<td>0</td>
</tr>
<tr>
<td>673e61fdf804d01340b055f2</td>
<td>2024-11-20 22:26:05.000000</td>
<td>checkin</td>
<td>closeFriends</td>
<td>-300</td>
<td>4165d880f964a5207e1d1fe3</td>
<td>Staten Island Ferry - Whitehall Terminal</td>
<td><a href="https://foursquare.com/v/staten-island-ferry--" target="_blank">https://foursquare.com/v/staten-island-ferry--</a> ...</td>
<td>0</td>
</tr>
<tr>
<td>673e69ccc2749c4b190f5fb9</td>
<td>2024-11-20 22:59:24.000000</td>
<td>checkin</td>
<td>closeFriends</td>
<td>-300</td>
<td>4a478d19f964a520d2a91fe3</td>
<td>Staten Island Ferry - St. George Terminal</td>
<td><a href="https://foursquare.com/v/staten-island-ferry--" target="_blank">https://foursquare.com/v/staten-island-ferry--</a>...</td>
<td>0</td>
</tr>
<tr>
<td>673e73175e573a13d383bcfa</td>
<td>2024-11-20 23:39:03.000000</td>
<td>checkin</td>
<td>closeFriends</td>
<td>-300</td>
<td>4d35e19d6c7c721eb511cf56</td>
<td>College of Staten Island Main Gate</td>
<td><a href="https://foursquare.com/v/college-of-staten-isl" target="_blank">https://foursquare.com/v/college-of-staten-isl</a>...</td>
<td>0</td>
</tr>
<tr>
<td>673ea1637f8f7e3e6b5232db</td>
<td>2024-11-21 02:56:35.000000</td>
<td>checkin</td>
<td>closeFriends</td>
<td>-300</td>
<td>4165d880f964a5207e1d1fe3</td>
<td>Staten Island Ferry - Whitehall Terminal</td>
<td><a href="https://foursquare.com/v/staten-island-ferry--" target="_blank">https://foursquare.com/v/staten-island-ferry--</a> ...</td>
<td>0</td>
</tr>
</tbody>
</table>
<p>Ok, well, that seems fine, but no match really. There <em>is</em> a close match (if you ignore milliseconds) in timing. But it isn't really enough to join on en-mass, even if it is close. This also shows me that the records that don't have a visibility value look like they are early on in my checkin history, which is useful to know.</p>
<p>So I have 9,993 &quot;visits&quot;. Which I think are dismissed check-in prompts?</p>
<p>There's also a whole file for <code>unconfirmed_vists.json</code> which has 18,279 entries. Where I can find some matches, it looks like they also are maybe pending prompts that I never confirmed or denied? These aren't just lat and long</p>
<p>There's no clear difference between the two. And there's no documentation from Foursquare. I'm going to go with my assumptions here. In that case, the only thing that matters is my checkins. That's cool.</p>
<p>Interestingly, the unconfirmed_visits have lat and long values. They look like this:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/foursquare-location-data-site/day-1-getting-a-handle-on-the-data/#code-skip-day-1-getting-a-handle-on-the-data-13" id="skip-to-code-skip-day-1-getting-a-handle-on-the-data-13" class="skip-link">Skip code block ▼</a></p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span><br />	<span class="token property">"id"</span><span class="token operator">:</span><span class="token string">"673a6e9eddf0e34a16590965"</span><span class="token punctuation">,</span><br />	<span class="token property">"startTime"</span><span class="token operator">:</span><span class="token string">"2024-11-17 22:08:21.628000"</span><span class="token punctuation">,</span><br />	<span class="token property">"endTime"</span><span class="token operator">:</span><span class="token string">"2024-11-17 22:31:27.761000"</span><span class="token punctuation">,</span><br />	<span class="token property">"venueId"</span><span class="token operator">:</span><span class="token string">"59e63da08c35dc3e57ab5520"</span><span class="token punctuation">,</span><br />	<span class="token property">"lat"</span><span class="token operator">:</span><span class="token number">40.74526808227119</span><span class="token punctuation">,</span><br />	<span class="token property">"lng"</span><span class="token operator">:</span><span class="token number">-73.99024878341206</span><span class="token punctuation">,</span><br />	<span class="token property">"venue"</span><span class="token operator">:</span><span class="token punctuation">{</span><br />		<span class="token property">"id"</span><span class="token operator">:</span><span class="token string">"59e63da08c35dc3e57ab5520"</span><span class="token punctuation">,</span><br />		<span class="token property">"name"</span><span class="token operator">:</span><span class="token string">"Patent Pending"</span><span class="token punctuation">,</span><br />		<span class="token property">"url"</span><span class="token operator">:</span><span class="token string">"https:\/\/foursquare.com\/v\/patent-pending\/59e63da08c35dc3e57ab5520"</span><br />	<span class="token punctuation">}</span><br /><span class="token punctuation">}</span></code></pre>
<p id="code-skip-day-1-getting-a-handle-on-the-data-13">There is a checkin around this time, found via</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/foursquare-location-data-site/day-1-getting-a-handle-on-the-data/#code-skip-day-1-getting-a-handle-on-the-data-12" id="skip-to-code-skip-day-1-getting-a-handle-on-the-data-12" class="skip-link">Skip code block ▼</a></p>
<pre class="language-python"><code class="language-python"><span class="token keyword">print</span><span class="token punctuation">(</span>df<span class="token punctuation">.</span>query<span class="token punctuation">(</span><span class="token string">'venueName.str.contains("Patent Pending")'</span><span class="token punctuation">)</span><span class="token punctuation">)</span></code></pre>
<p id="code-skip-day-1-getting-a-handle-on-the-data-12">I'm pretty sure it is based around the time I did the actual checkin, found that via the above at <code>createdAt</code> time <code>2024-11-17 22:31:33.000000</code>.</p>
<p>It looks like comments file is pretty useless:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/foursquare-location-data-site/day-1-getting-a-handle-on-the-data/#code-skip-day-1-getting-a-handle-on-the-data-11" id="skip-to-code-skip-day-1-getting-a-handle-on-the-data-11" class="skip-link">Skip code block ▼</a></p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span><br />	<span class="token property">"userId"</span><span class="token operator">:</span><span class="token number">15234</span><span class="token punctuation">,</span><br />	<span class="token property">"time"</span><span class="token operator">:</span><span class="token string">"2017-03-03 02:37:36.000000"</span><span class="token punctuation">,</span><br />	<span class="token property">"comment"</span><span class="token operator">:</span><span class="token string">"Hey! Just saw this, we just got to Kimchi Grill, if you want to join for food."</span><br /><span class="token punctuation">}</span></code></pre>
<p id="code-skip-day-1-getting-a-handle-on-the-data-11">I could potentially make some assumptions on <code>time</code>, but it doesn't necessarily map out, comments could happen way later, after other checkins.</p>
<p>Then there is the tips file.</p>
<p>It has objects like:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/foursquare-location-data-site/day-1-getting-a-handle-on-the-data/#code-skip-day-1-getting-a-handle-on-the-data-10" id="skip-to-code-skip-day-1-getting-a-handle-on-the-data-10" class="skip-link">Skip code block ▼</a></p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span><br />	<span class="token property">"id"</span><span class="token operator">:</span><span class="token string">"670f00d47d191f5820d40dda"</span><span class="token punctuation">,</span><br />	<span class="token property">"createdAt"</span><span class="token operator">:</span><span class="token string">"2024-10-15 23:55:00.000000"</span><span class="token punctuation">,</span><br />	<span class="token property">"text"</span><span class="token operator">:</span><span class="token string">"Great bookstore, with drinks, snacks, and plentiful recommendations cards with lots of details."</span><span class="token punctuation">,</span><br />	<span class="token property">"type"</span><span class="token operator">:</span><span class="token string">"user"</span><span class="token punctuation">,</span><br />	<span class="token property">"canonicalUrl"</span><span class="token operator">:</span><span class="token string">"https:\/\/foursquare.com\/item\/670f00d47d191f5820d40dda"</span><span class="token punctuation">,</span><br />	<span class="token property">"flags"</span><span class="token operator">:</span><span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br />	<span class="token property">"viewCount"</span><span class="token operator">:</span><span class="token number">29</span><span class="token punctuation">,</span><br />	<span class="token property">"agreeCount"</span><span class="token operator">:</span><span class="token number">0</span><span class="token punctuation">,</span><br />	<span class="token property">"disagreeCount"</span><span class="token operator">:</span><span class="token number">0</span><span class="token punctuation">,</span><br />	<span class="token property">"user"</span><span class="token operator">:</span><span class="token punctuation">{</span><br />		<span class="token property">"id"</span><span class="token operator">:</span><span class="token string">"15234"</span><span class="token punctuation">,</span><br />		<span class="token property">"firstName"</span><span class="token operator">:</span><span class="token string">"Aram"</span><span class="token punctuation">,</span><br />		<span class="token property">"lastName"</span><span class="token operator">:</span><span class="token string">"Zucker-Scharff"</span><span class="token punctuation">,</span><br />		<span class="token property">"handle"</span><span class="token operator">:</span><span class="token string">"chronotope"</span><span class="token punctuation">,</span><br />		<span class="token property">"privateProfile"</span><span class="token operator">:</span><span class="token boolean">false</span><span class="token punctuation">,</span><br />		<span class="token property">"gender"</span><span class="token operator">:</span><span class="token string">"male"</span><span class="token punctuation">,</span><br />		<span class="token property">"address"</span><span class="token operator">:</span><span class="token string">""</span><span class="token punctuation">,</span><br />		<span class="token property">"city"</span><span class="token operator">:</span><span class="token string">""</span><span class="token punctuation">,</span><br />		<span class="token property">"state"</span><span class="token operator">:</span><span class="token string">""</span><span class="token punctuation">,</span><br />		<span class="token property">"countryCode"</span><span class="token operator">:</span><span class="token string">"US"</span><span class="token punctuation">,</span><br />		<span class="token property">"relationship"</span><span class="token operator">:</span><span class="token string">"self"</span><span class="token punctuation">,</span><br />		<span class="token property">"photo"</span><span class="token operator">:</span><span class="token punctuation">{</span><br />			<span class="token property">"prefix"</span><span class="token operator">:</span><span class="token string">"https:\/\/fastly.4sqi.net\/img\/user\/"</span><span class="token punctuation">,</span><br />			<span class="token property">"suffix"</span><span class="token operator">:</span><span class="token string">"\/15234-EMJINMXJKZ5R5S20.jpg"</span><br />		<span class="token punctuation">}</span><br />	<span class="token punctuation">}</span><span class="token punctuation">,</span><br />	<span class="token property">"venue"</span><span class="token operator">:</span><span class="token punctuation">{</span><br />		<span class="token property">"id"</span><span class="token operator">:</span><span class="token string">"64dd65470e981a714e4c9f6c"</span><span class="token punctuation">,</span><br />		<span class="token property">"name"</span><span class="token operator">:</span><span class="token string">"First Light Books"</span><span class="token punctuation">,</span><br />		<span class="token property">"url"</span><span class="token operator">:</span><span class="token string">"https:\/\/foursquare.com\/v\/first-light-books\/64dd65470e981a714e4c9f6c"</span><br />	<span class="token punctuation">}</span><br /><span class="token punctuation">}</span></code></pre>
<p id="code-skip-day-1-getting-a-handle-on-the-data-10">There do appear to be associated photos, but those photos don't seem to be in the <code>pix</code> folder I got with the export. I tried accessing the URL directly, but didn't get anything at that URL. However, looking at the venue, I didn't upload an image.</p>
<p>But that does match my profile image at <code>https://fastly.4sqi.net/img/user/64x64/15234-EMJINMXJKZ5R5S20.jpg</code>.</p>
<p>So I guess that is what that is. This does have a check-in associated with it:</p>
<table>
<thead>
<tr>
<th>id</th>
<th>createdAt</th>
<th>type</th>
<th>visibility</th>
<th>timeZoneOffset</th>
<th>venueId</th>
<th>venueName</th>
<th>venueUrl</th>
<th>commentsCount</th>
</tr>
</thead>
<tbody>
<tr>
<td>670efb74d8a0e46cd107fea5</td>
<td>2024-10-15 23:32:04.000000</td>
<td>checkin</td>
<td>closeFriends</td>
<td>-300</td>
<td>64dd65470e981a714e4c9f6c</td>
<td>First Light Books</td>
<td><a href="https://foursquare.com/v/first-light-books/64d" target="_blank">https://foursquare.com/v/first-light-books/64d</a>...</td>
<td>0</td>
</tr>
</tbody>
</table>
<p>Nothing there to associate based on except ID of the venue.</p>
<p>I am starting to conclude that maybe I also need just a listing of all the venues I've visited.</p>
<p>So I need to build a venues dataframe too.</p>
<p>Ok, so we'll need to load a few files:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/foursquare-location-data-site/day-1-getting-a-handle-on-the-data/#code-skip-day-1-getting-a-handle-on-the-data-9" id="skip-to-code-skip-day-1-getting-a-handle-on-the-data-9" class="skip-link">Skip code block ▼</a></p>
<pre class="language-python"><code class="language-python"><span class="token comment"># Get tips file</span><br />tipsFile <span class="token operator">=</span> <span class="token builtin">open</span><span class="token punctuation">(</span><span class="token string">'../foursquare-export/tips.json'</span><span class="token punctuation">,</span> <span class="token string">'r'</span><span class="token punctuation">)</span><br /><span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string-interpolation"><span class="token string">f"Reading tips file"</span></span><span class="token punctuation">)</span><br />tipsObject <span class="token operator">=</span> json<span class="token punctuation">.</span>load<span class="token punctuation">(</span>tipsFile<span class="token punctuation">)</span><br />tipsSetObject <span class="token operator">=</span> tipsObject<span class="token punctuation">[</span><span class="token string">'items'</span><span class="token punctuation">]</span><br /><br /><span class="token comment"># get Venue Ratings</span><br />ratingsFile <span class="token operator">=</span> <span class="token builtin">open</span><span class="token punctuation">(</span><span class="token string">'../foursquare-export/venueRatings.json'</span><span class="token punctuation">,</span> <span class="token string">'r'</span><span class="token punctuation">)</span><br /><span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string-interpolation"><span class="token string">f"Reading ratings file"</span></span><span class="token punctuation">)</span><br />ratingsObject <span class="token operator">=</span> json<span class="token punctuation">.</span>load<span class="token punctuation">(</span>ratingsFile<span class="token punctuation">)</span><br /><br />venueLikes <span class="token operator">=</span> ratingsObject<span class="token punctuation">[</span><span class="token string">'venueLikes'</span><span class="token punctuation">]</span><br />venueDislikes <span class="token operator">=</span> ratingsObject<span class="token punctuation">[</span><span class="token string">'venueDislikes'</span><span class="token punctuation">]</span><br />venueOkays <span class="token operator">=</span> ratingsObject<span class="token punctuation">[</span><span class="token string">'venueOkays'</span><span class="token punctuation">]</span><br /><br />photosFile <span class="token operator">=</span> <span class="token builtin">open</span><span class="token punctuation">(</span><span class="token string">'../foursquare-export/photos.json'</span><span class="token punctuation">,</span> <span class="token string">'r'</span><span class="token punctuation">)</span><br /><span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string-interpolation"><span class="token string">f"Reading photos file"</span></span><span class="token punctuation">)</span><br />photosObject <span class="token operator">=</span> json<span class="token punctuation">.</span>load<span class="token punctuation">(</span>photosFile<span class="token punctuation">)</span><br />photosSetObject <span class="token operator">=</span> photosObject<span class="token punctuation">[</span><span class="token string">'items'</span><span class="token punctuation">]</span></code></pre>
<p id="code-skip-day-1-getting-a-handle-on-the-data-9">As you can see, the venue ratings file is divided into <code>venueLikes</code>, <code>venueDislikes</code> and <code>venueOkays</code>. So I'm pulling those out.</p>
<p>So we know what a <code>tip</code> looks like.</p>
<p>Here's what each object inside the venue ratings looks like:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/foursquare-location-data-site/day-1-getting-a-handle-on-the-data/#code-skip-day-1-getting-a-handle-on-the-data-8" id="skip-to-code-skip-day-1-getting-a-handle-on-the-data-8" class="skip-link">Skip code block ▼</a></p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span><br />	<span class="token property">"id"</span><span class="token operator">:</span> <span class="token string">"6278124503e634412f05cdaf"</span><span class="token punctuation">,</span><br />	<span class="token property">"name"</span><span class="token operator">:</span> <span class="token string">"Sobremesa Cocina Mexicana"</span><span class="token punctuation">,</span><br />	<span class="token property">"url"</span><span class="token operator">:</span> <span class="token string">"https:\/\/foursquare.com\/v\/sobremesa-cocina-mexicana\/6278124503e634412f05cdaf"</span><br /><span class="token punctuation">}</span><span class="token punctuation">,</span></code></pre>
<p id="code-skip-day-1-getting-a-handle-on-the-data-8">And then we've got the photos object:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/foursquare-location-data-site/day-1-getting-a-handle-on-the-data/#code-skip-day-1-getting-a-handle-on-the-data-7" id="skip-to-code-skip-day-1-getting-a-handle-on-the-data-7" class="skip-link">Skip code block ▼</a></p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span><br />	<span class="token property">"id"</span><span class="token operator">:</span><span class="token string">"4db1b674fd28f0dcfa1c0d2c"</span><span class="token punctuation">,</span><br />	<span class="token property">"createdAt"</span><span class="token operator">:</span><span class="token string">"2011-04-22 17:10:12.000000"</span><span class="token punctuation">,</span><br />	<span class="token property">"prefix"</span><span class="token operator">:</span><span class="token string">"https:\/\/fastly.4sqi.net\/img\/general\/"</span><span class="token punctuation">,</span><br />	<span class="token property">"suffix"</span><span class="token operator">:</span><span class="token string">"\/BMGMLXNIP44I0WPVA2LOPEMOYCFXBGQ1ZFTY1IILIQXJP3WA.jpg"</span><span class="token punctuation">,</span><br />	<span class="token property">"width"</span><span class="token operator">:</span><span class="token number">538</span><span class="token punctuation">,</span><br />	<span class="token property">"height"</span><span class="token operator">:</span><span class="token number">720</span><span class="token punctuation">,</span><br />	<span class="token property">"demoted"</span><span class="token operator">:</span><span class="token boolean">false</span><span class="token punctuation">,</span><br />	<span class="token property">"visibility"</span><span class="token operator">:</span><span class="token string">"friends"</span><span class="token punctuation">,</span><br />	<span class="token property">"fullUrl"</span><span class="token operator">:</span><span class="token string">"https:\/\/fastly.4sqi.net\/img\/general\/538x720\/BMGMLXNIP44I0WPVA2LOPEMOYCFXBGQ1ZFTY1IILIQXJP3WA.jpg"</span><span class="token punctuation">,</span><br />	<span class="token property">"relatedItemUrl"</span><span class="token operator">:</span><span class="token string">"https:\/\/www.swarmapp.com\/checkin\/4db1b66fa86e63d21171a701"</span><br /><span class="token punctuation">}</span></code></pre>
<p id="code-skip-day-1-getting-a-handle-on-the-data-7">or</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/foursquare-location-data-site/day-1-getting-a-handle-on-the-data/#code-skip-day-1-getting-a-handle-on-the-data-6" id="skip-to-code-skip-day-1-getting-a-handle-on-the-data-6" class="skip-link">Skip code block ▼</a></p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span><br />	<span class="token property">"id"</span><span class="token operator">:</span><span class="token string">"51fc5b1f498ea67cd47c6be5"</span><span class="token punctuation">,</span><br />	<span class="token property">"createdAt"</span><span class="token operator">:</span><span class="token string">"2013-08-03 01:21:35.000000"</span><span class="token punctuation">,</span><br />	<span class="token property">"prefix"</span><span class="token operator">:</span><span class="token string">"https:\/\/fastly.4sqi.net\/img\/general\/"</span><span class="token punctuation">,</span><br />	<span class="token property">"suffix"</span><span class="token operator">:</span><span class="token string">"\/15234_GrwLQ564TbAJeS3qJjRxK5ZYDOVCj93L1ATyPJt_3RU.jpg"</span><span class="token punctuation">,</span><br />	<span class="token property">"width"</span><span class="token operator">:</span><span class="token number">720</span><span class="token punctuation">,</span><br />	<span class="token property">"height"</span><span class="token operator">:</span><span class="token number">960</span><span class="token punctuation">,</span><br />	<span class="token property">"demoted"</span><span class="token operator">:</span><span class="token boolean">false</span><span class="token punctuation">,</span><br />	<span class="token property">"visibility"</span><span class="token operator">:</span><span class="token string">"public"</span><span class="token punctuation">,</span><br />	<span class="token property">"fullUrl"</span><span class="token operator">:</span><span class="token string">"https:\/\/fastly.4sqi.net\/img\/general\/720x960\/15234_GrwLQ564TbAJeS3qJjRxK5ZYDOVCj93L1ATyPJt_3RU.jpg"</span><span class="token punctuation">,</span><br />	<span class="token property">"relatedItemUrl"</span><span class="token operator">:</span><span class="token string">"https:\/\/foursquare.com\/v\/51fc5a63498ec02f4de928e0"</span><br /><span class="token punctuation">}</span><span class="token punctuation">,</span></code></pre>
<p id="code-skip-day-1-getting-a-handle-on-the-data-6">There the <code>suffix</code> field does match up with a file in the <code>pix</code> folder, so that's where those connect up.</p>
<p>The <code>relatedItemUrl</code> doesn't go to anywhere that is online on the web. The value at the end of that though, the <code>4db1b66fa86e63d21171a701</code> part of the <code>relatedItemUrl</code> does match up with an <code>id</code> in the <code>checkins</code> files! So that's how I can associate a photo with a check-in and venue it seems.</p>
<p>So what format should the second dataframe be?</p>
<p>I'm thinking:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/foursquare-location-data-site/day-1-getting-a-handle-on-the-data/#code-skip-day-1-getting-a-handle-on-the-data-5" id="skip-to-code-skip-day-1-getting-a-handle-on-the-data-5" class="skip-link">Skip code block ▼</a></p>
<pre class="language-python"><code class="language-python">venuesDf <span class="token operator">=</span> pd<span class="token punctuation">.</span>DataFrame<span class="token punctuation">(</span>columns<span class="token operator">=</span><span class="token punctuation">[</span><br />    <span class="token string">'id'</span><span class="token punctuation">,</span> <span class="token comment"># venue id</span><br />    <span class="token string">'name'</span><span class="token punctuation">,</span> <span class="token comment"># venue name</span><br />    <span class="token string">'url'</span><span class="token punctuation">,</span> <span class="token comment"># venue url</span><br />    <span class="token string">'latitude'</span><span class="token punctuation">,</span><br />    <span class="token string">'longitude'</span><span class="token punctuation">,</span><br />    <span class="token string">'tipString'</span><span class="token punctuation">,</span> <span class="token comment"># tip text</span><br />    <span class="token string">'tipCreatedAt'</span><span class="token punctuation">,</span><br />    <span class="token string">'tipId'</span><span class="token punctuation">,</span><br />    <span class="token string">'tipUrl'</span><span class="token punctuation">,</span> <span class="token comment"># tip canonicalUrl</span><br />    <span class="token string">'tipViews'</span><span class="token punctuation">,</span> <span class="token comment"># tip viewCount</span><br />    <span class="token string">'tipAgreeCount'</span><span class="token punctuation">,</span> <span class="token comment"># tip agreeCount</span><br />    <span class="token string">'tipDisagreeCount'</span><span class="token punctuation">,</span> <span class="token comment"># tip disagreeCount</span><br />    <span class="token string">'rating'</span><span class="token punctuation">,</span> <span class="token comment"># from ratings file, can be like, dislike, okay</span><br />    <span class="token string">'imageSuffix'</span><span class="token punctuation">,</span> <span class="token comment"># from photos file, is the `suffix` field</span><br />    <span class="token string">'imageWidth'</span><span class="token punctuation">,</span> <span class="token comment"># from photos file, is the `width` field</span><br />    <span class="token string">'imageHeight'</span><span class="token punctuation">,</span> <span class="token comment"># from photos file, is the `height` field</span><br />    <span class="token string">'imageId'</span><span class="token punctuation">,</span> <span class="token comment"># from photos file, is the `id` field</span><br />    <span class="token string">'imageCreatedAt'</span><span class="token punctuation">,</span> <span class="token comment"># from photos file, is the `createdAt` field</span><br />    <span class="token string">'checkIns'</span> <span class="token comment"># array of string checkin IDs.</span><br /><span class="token punctuation">]</span><span class="token punctuation">)</span></code></pre>
<p id="code-skip-day-1-getting-a-handle-on-the-data-5">Ok, so I want to append the other checkin IDs. How to do this? In theory this should work.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/foursquare-location-data-site/day-1-getting-a-handle-on-the-data/#code-skip-day-1-getting-a-handle-on-the-data-4" id="skip-to-code-skip-day-1-getting-a-handle-on-the-data-4" class="skip-link">Skip code block ▼</a></p>
<pre class="language-python"><code class="language-python"><span class="token keyword">for</span> index<span class="token punctuation">,</span> row <span class="token keyword">in</span> df<span class="token punctuation">.</span>iterrows<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span><br />	venueRow <span class="token operator">=</span> venuesDf<span class="token punctuation">.</span>loc<span class="token punctuation">[</span>venuesDf<span class="token punctuation">[</span><span class="token string">'id'</span><span class="token punctuation">]</span><span class="token operator">==</span>row<span class="token punctuation">[</span><span class="token string">'venueId'</span><span class="token punctuation">]</span><span class="token punctuation">]</span><br />	<span class="token keyword">if</span> venueRow<span class="token punctuation">.</span>empty<span class="token punctuation">:</span><br />		<span class="token comment"># print(f"Venue not found for {row['venueId']}")</span><br />		<span class="token comment"># continue</span><br />		venuesDf<span class="token punctuation">.</span>loc<span class="token punctuation">[</span><span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token punctuation">[</span><br />      row<span class="token punctuation">[</span><span class="token string">'venueId'</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br />      row<span class="token punctuation">[</span><span class="token string">'venueName'</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br />      row<span class="token punctuation">[</span><span class="token string">"venueURL"</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token string">""</span><span class="token punctuation">,</span> <span class="token comment"># latitude</span><br />      <span class="token string">""</span><span class="token punctuation">,</span> <span class="token comment"># longitude</span><br />      <span class="token string">""</span><span class="token punctuation">,</span> <span class="token comment"># tipString</span><br />      <span class="token string">""</span><span class="token punctuation">,</span> <span class="token comment"># tipCreatedAt</span><br />      <span class="token string">""</span><span class="token punctuation">,</span> <span class="token comment"># tipId</span><br />      <span class="token string">""</span><span class="token punctuation">,</span> <span class="token comment"># tipUrl</span><br />      <span class="token string">""</span><span class="token punctuation">,</span> <span class="token comment"># tipViews</span><br />      <span class="token string">""</span><span class="token punctuation">,</span> <span class="token comment"># tipAgreeCount</span><br />      <span class="token string">""</span><span class="token punctuation">,</span> <span class="token comment"># tipDisagreeCount</span><br />      <span class="token string">""</span><span class="token punctuation">,</span> <span class="token comment"># rating</span><br />      <span class="token string">""</span><span class="token punctuation">,</span> <span class="token comment"># imageSuffix</span><br />      <span class="token string">""</span><span class="token punctuation">,</span> <span class="token comment"># imageWidth</span><br />      <span class="token string">""</span><span class="token punctuation">,</span> <span class="token comment"># imageHeight</span><br />      <span class="token string">""</span><span class="token punctuation">,</span> <span class="token comment"># imageId</span><br />      <span class="token string">""</span><span class="token punctuation">,</span> <span class="token comment"># imageCreatedAt</span><br />      <span class="token punctuation">[</span>row<span class="token punctuation">[</span><span class="token string">'id'</span><span class="token punctuation">]</span><span class="token punctuation">]</span> <span class="token comment"># checkIns</span><br />      <span class="token punctuation">]</span>  <span class="token comment"># adding a row</span><br />		venuesDf<span class="token punctuation">.</span>index <span class="token operator">=</span> venuesDf<span class="token punctuation">.</span>index <span class="token operator">+</span> <span class="token number">1</span>  <span class="token comment"># shifting index</span><br />		venuesDf <span class="token operator">=</span> venuesDf<span class="token punctuation">.</span>sort_index<span class="token punctuation">(</span><span class="token punctuation">)</span>  <span class="token comment"># sorting by index</span><br />	<span class="token keyword">else</span><span class="token punctuation">:</span><br />		<span class="token comment"># add a new checkin to the series of checkins for this venue</span><br />		venuesDf<span class="token punctuation">.</span>loc<span class="token punctuation">[</span>venuesDf<span class="token punctuation">[</span><span class="token string">'id'</span><span class="token punctuation">]</span> <span class="token operator">==</span> row<span class="token punctuation">[</span><span class="token string">'venueId'</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token string">'checkIns'</span><span class="token punctuation">]</span> <span class="token operator">=</span> venuesDf<span class="token punctuation">.</span>loc<span class="token punctuation">[</span>venuesDf<span class="token punctuation">[</span><span class="token string">'id'</span><span class="token punctuation">]</span> <span class="token operator">==</span> row<span class="token punctuation">[</span><span class="token string">'venueId'</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token string">'checkIns'</span><span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token builtin">apply</span><span class="token punctuation">(</span><span class="token keyword">lambda</span> x<span class="token punctuation">:</span> x <span class="token operator">+</span> <span class="token punctuation">[</span>row<span class="token punctuation">[</span><span class="token string">'id'</span><span class="token punctuation">]</span><span class="token punctuation">]</span><span class="token punctuation">)</span></code></pre>
<p id="code-skip-day-1-getting-a-handle-on-the-data-4"><a target="_blank" href="https://github.com/AramZS/locations/commit/e572ac052be701952f45cd97db6dfa63f6a125a7" class="git-commit-link"><code>git commit -am &quot;Getting the initial feed in of venues into their own dataframe&quot;</code></a></p>
<p>Ok, this is appending the ID where needed.</p>
<p>Now I need to get the ratings in:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/foursquare-location-data-site/day-1-getting-a-handle-on-the-data/#code-skip-day-1-getting-a-handle-on-the-data-3" id="skip-to-code-skip-day-1-getting-a-handle-on-the-data-3" class="skip-link">Skip code block ▼</a></p>
<pre class="language-python"><code class="language-python"><span class="token keyword">def</span> <span class="token function">addVenueRating</span><span class="token punctuation">(</span>ratingSet<span class="token punctuation">,</span> ratingType<span class="token punctuation">,</span> venueDFSet<span class="token punctuation">)</span><span class="token punctuation">:</span><br />	<span class="token keyword">for</span> ratingItem <span class="token keyword">in</span> ratingSet<span class="token punctuation">:</span><br />		venueRatingId <span class="token operator">=</span> ratingItem<span class="token punctuation">[</span><span class="token string">'url'</span><span class="token punctuation">]</span><span class="token punctuation">.</span>split<span class="token punctuation">(</span><span class="token string">'/'</span><span class="token punctuation">)</span><span class="token punctuation">[</span><span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">]</span><br />		venueRow <span class="token operator">=</span> venueDFSet<span class="token punctuation">.</span>loc<span class="token punctuation">[</span>venueDFSet<span class="token punctuation">[</span><span class="token string">'id'</span><span class="token punctuation">]</span><span class="token operator">==</span>venueRatingId<span class="token punctuation">]</span><br />		<span class="token keyword">if</span> venueRow<span class="token punctuation">.</span>empty<span class="token punctuation">:</span><br />			<span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string-interpolation"><span class="token string">f"Venue not found for </span><span class="token interpolation"><span class="token punctuation">{</span>venueRatingId<span class="token punctuation">}</span></span><span class="token string">"</span></span><span class="token punctuation">)</span><br />			venueDFSet<span class="token punctuation">.</span>loc<span class="token punctuation">[</span><span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token punctuation">[</span><br />				row<span class="token punctuation">[</span><span class="token string">'venueId'</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br />				row<span class="token punctuation">[</span><span class="token string">'venueName'</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br />				row<span class="token punctuation">[</span><span class="token string">"venueURL"</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br />				<span class="token string">""</span><span class="token punctuation">,</span> <span class="token comment"># latitude</span><br />				<span class="token string">""</span><span class="token punctuation">,</span> <span class="token comment"># longitude</span><br />				<span class="token string">""</span><span class="token punctuation">,</span> <span class="token comment"># tipString</span><br />				<span class="token string">""</span><span class="token punctuation">,</span> <span class="token comment"># tipCreatedAt</span><br />				<span class="token string">""</span><span class="token punctuation">,</span> <span class="token comment"># tipId</span><br />				<span class="token string">""</span><span class="token punctuation">,</span> <span class="token comment"># tipUrl</span><br />				<span class="token string">""</span><span class="token punctuation">,</span> <span class="token comment"># tipViews</span><br />				<span class="token string">""</span><span class="token punctuation">,</span> <span class="token comment"># tipAgreeCount</span><br />				<span class="token string">""</span><span class="token punctuation">,</span> <span class="token comment"># tipDisagreeCount</span><br />				<span class="token string">""</span><span class="token punctuation">,</span> <span class="token comment"># rating</span><br />				<span class="token string">""</span><span class="token punctuation">,</span> <span class="token comment"># imageSuffix</span><br />				<span class="token string">""</span><span class="token punctuation">,</span> <span class="token comment"># imageWidth</span><br />				<span class="token string">""</span><span class="token punctuation">,</span> <span class="token comment"># imageHeight</span><br />				<span class="token string">""</span><span class="token punctuation">,</span> <span class="token comment"># imageId</span><br />				<span class="token string">""</span><span class="token punctuation">,</span> <span class="token comment"># imageCreatedAt</span><br />				<span class="token punctuation">[</span>row<span class="token punctuation">[</span><span class="token string">'id'</span><span class="token punctuation">]</span><span class="token punctuation">]</span> <span class="token comment"># checkIns</span><br />			<span class="token punctuation">]</span>  <span class="token comment"># adding a row</span><br />			venueDFSet<span class="token punctuation">.</span>index <span class="token operator">=</span> venueDFSet<span class="token punctuation">.</span>index <span class="token operator">+</span> <span class="token number">1</span>  <span class="token comment"># shifting index</span><br />			venueDFSet <span class="token operator">=</span> venueDFSet<span class="token punctuation">.</span>sort_index<span class="token punctuation">(</span><span class="token punctuation">)</span>  <span class="token comment"># sorting by index</span><br />			<span class="token keyword">continue</span><br />		venueDFSet<span class="token punctuation">.</span>loc<span class="token punctuation">[</span>venueDFSet<span class="token punctuation">[</span><span class="token string">'id'</span><span class="token punctuation">]</span> <span class="token operator">==</span> venueRatingId<span class="token punctuation">,</span> <span class="token string">'rating'</span><span class="token punctuation">]</span> <span class="token operator">=</span> ratingType<br /><br />addVenueRating<span class="token punctuation">(</span>venueLikes<span class="token punctuation">,</span> <span class="token string">"like"</span><span class="token punctuation">,</span> venuesDf<span class="token punctuation">)</span><br />addVenueRating<span class="token punctuation">(</span>venueDislikes<span class="token punctuation">,</span> <span class="token string">"dislike"</span><span class="token punctuation">,</span> venuesDf<span class="token punctuation">)</span><br />addVenueRating<span class="token punctuation">(</span>venueOkays<span class="token punctuation">,</span> <span class="token string">"okay"</span><span class="token punctuation">,</span> venuesDf<span class="token punctuation">)</span></code></pre>
<p id="code-skip-day-1-getting-a-handle-on-the-data-3">I discovered there were a few venues I guess I rated without a corresponding check-in? Had to make sure to create them I guess.</p>
<p>Ok, now I have ratings and checkins. I now need photos and tips.</p>
<p>Tips first? Ok, this does it:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/foursquare-location-data-site/day-1-getting-a-handle-on-the-data/#code-skip-day-1-getting-a-handle-on-the-data-2" id="skip-to-code-skip-day-1-getting-a-handle-on-the-data-2" class="skip-link">Skip code block ▼</a></p>
<pre class="language-python"><code class="language-python"><span class="token keyword">for</span> tip <span class="token keyword">in</span> tipsSetObject<span class="token punctuation">:</span><br />	tipVenueId <span class="token operator">=</span> tip<span class="token punctuation">[</span><span class="token string">"venue"</span><span class="token punctuation">]</span><span class="token punctuation">[</span><span class="token string">"id"</span><span class="token punctuation">]</span><br />	venueRow <span class="token operator">=</span> venuesDf<span class="token punctuation">.</span>loc<span class="token punctuation">[</span>venuesDf<span class="token punctuation">[</span><span class="token string">'id'</span><span class="token punctuation">]</span><span class="token operator">==</span>tipVenueId<span class="token punctuation">]</span><br />	<span class="token keyword">if</span> venueRow<span class="token punctuation">.</span>empty<span class="token punctuation">:</span><br />		<span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string-interpolation"><span class="token string">f"Venue not found for </span><span class="token interpolation"><span class="token punctuation">{</span>tip<span class="token punctuation">[</span><span class="token string">'id'</span><span class="token punctuation">]</span><span class="token punctuation">}</span></span><span class="token string">"</span></span><span class="token punctuation">)</span><br />		<span class="token keyword">continue</span><br />	<span class="token comment"># print(f"Venue found for {tipVenueId}")</span><br />	venuesDf<span class="token punctuation">.</span>loc<span class="token punctuation">[</span>venuesDf<span class="token punctuation">[</span><span class="token string">'id'</span><span class="token punctuation">]</span> <span class="token operator">==</span> tipVenueId<span class="token punctuation">,</span> <span class="token string">'tipString'</span><span class="token punctuation">]</span> <span class="token operator">=</span> tip<span class="token punctuation">[</span><span class="token string">"text"</span><span class="token punctuation">]</span><br />	venuesDf<span class="token punctuation">.</span>loc<span class="token punctuation">[</span>venuesDf<span class="token punctuation">[</span><span class="token string">'id'</span><span class="token punctuation">]</span> <span class="token operator">==</span> tipVenueId<span class="token punctuation">,</span> <span class="token string">'tipCreatedAt'</span><span class="token punctuation">]</span> <span class="token operator">=</span> tip<span class="token punctuation">[</span><span class="token string">"createdAt"</span><span class="token punctuation">]</span><br />	venuesDf<span class="token punctuation">.</span>loc<span class="token punctuation">[</span>venuesDf<span class="token punctuation">[</span><span class="token string">'id'</span><span class="token punctuation">]</span> <span class="token operator">==</span> tipVenueId<span class="token punctuation">,</span> <span class="token string">'tipId'</span><span class="token punctuation">]</span> <span class="token operator">=</span> tip<span class="token punctuation">[</span><span class="token string">"id"</span><span class="token punctuation">]</span><br />	venuesDf<span class="token punctuation">.</span>loc<span class="token punctuation">[</span>venuesDf<span class="token punctuation">[</span><span class="token string">'id'</span><span class="token punctuation">]</span> <span class="token operator">==</span> tipVenueId<span class="token punctuation">,</span> <span class="token string">'tipViews'</span><span class="token punctuation">]</span> <span class="token operator">=</span> tip<span class="token punctuation">[</span><span class="token string">"viewCount"</span><span class="token punctuation">]</span><br />	venuesDf<span class="token punctuation">.</span>loc<span class="token punctuation">[</span>venuesDf<span class="token punctuation">[</span><span class="token string">'id'</span><span class="token punctuation">]</span> <span class="token operator">==</span> tipVenueId<span class="token punctuation">,</span> <span class="token string">'tipAgreeCount'</span><span class="token punctuation">]</span> <span class="token operator">=</span> tip<span class="token punctuation">[</span><span class="token string">"agreeCount"</span><span class="token punctuation">]</span><br />	venuesDf<span class="token punctuation">.</span>loc<span class="token punctuation">[</span>venuesDf<span class="token punctuation">[</span><span class="token string">'id'</span><span class="token punctuation">]</span> <span class="token operator">==</span> tipVenueId<span class="token punctuation">,</span> <span class="token string">'tipDisagreeCount'</span><span class="token punctuation">]</span> <span class="token operator">=</span> tip<span class="token punctuation">[</span><span class="token string">"disagreeCount"</span><span class="token punctuation">]</span><br />	venuesDf<span class="token punctuation">.</span>loc<span class="token punctuation">[</span>venuesDf<span class="token punctuation">[</span><span class="token string">'id'</span><span class="token punctuation">]</span> <span class="token operator">==</span> tipVenueId<span class="token punctuation">,</span> <span class="token string">'tipUrl'</span><span class="token punctuation">]</span> <span class="token operator">=</span> tip<span class="token punctuation">[</span><span class="token string">"canonicalUrl"</span><span class="token punctuation">]</span><br /><br /><span class="token keyword">print</span><span class="token punctuation">(</span>venuesDf<span class="token punctuation">.</span>loc<span class="token punctuation">[</span>venuesDf<span class="token punctuation">[</span><span class="token string">'id'</span><span class="token punctuation">]</span><span class="token operator">==</span><span class="token string">"64dd65470e981a714e4c9f6c"</span><span class="token punctuation">]</span><span class="token punctuation">)</span></code></pre>
<p id="code-skip-day-1-getting-a-handle-on-the-data-2"><a target="_blank" href="https://github.com/AramZS/locations/commit/854bf46bd42279332afad93e1ed6b6390f21df1f" class="git-commit-link"><code>git commit -am &quot;Set up tip pull into the venue dataframe&quot;</code></a></p>
<p>Next up is the images and then the last thing is to figure out how to pull lat and long data.</p>
<p>Hmmm. Looks like checkins can also have a <code>shout</code> value:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/foursquare-location-data-site/day-1-getting-a-handle-on-the-data/#code-skip-day-1-getting-a-handle-on-the-data-1" id="skip-to-code-skip-day-1-getting-a-handle-on-the-data-1" class="skip-link">Skip code block ▼</a></p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span><br />	<span class="token property">"id"</span><span class="token operator">:</span><span class="token string">"673583d957abcd42163c5c32"</span><span class="token punctuation">,</span><br />	<span class="token property">"createdAt"</span><span class="token operator">:</span><span class="token string">"2024-11-14 05:00:09.000000"</span><span class="token punctuation">,</span><br />	<span class="token property">"type"</span><span class="token operator">:</span><span class="token string">"checkin"</span><span class="token punctuation">,</span><br />	<span class="token property">"visibility"</span><span class="token operator">:</span><span class="token string">"closeFriends"</span><span class="token punctuation">,</span><br />	<span class="token property">"entities"</span><span class="token operator">:</span><span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br />	<span class="token property">"shout"</span><span class="token operator">:</span><span class="token string">"Kareoke time!"</span><span class="token punctuation">,</span><br />	<span class="token property">"timeZoneOffset"</span><span class="token operator">:</span><span class="token number">-300</span><span class="token punctuation">,</span><br />	<span class="token property">"venue"</span><span class="token operator">:</span><span class="token punctuation">{</span><br />		<span class="token property">"id"</span><span class="token operator">:</span><span class="token string">"5285412911d2a3e51484ff56"</span><span class="token punctuation">,</span><br />		<span class="token property">"name"</span><span class="token operator">:</span><span class="token string">"The Brew Inn"</span><span class="token punctuation">,</span><br />		<span class="token property">"url"</span><span class="token operator">:</span><span class="token string">"https:\/\/foursquare.com\/v\/the-brew-inn\/5285412911d2a3e51484ff56"</span><span class="token punctuation">}</span><span class="token punctuation">,</span><br />		<span class="token property">"comments"</span><span class="token operator">:</span><span class="token punctuation">{</span><span class="token property">"count"</span><span class="token operator">:</span><span class="token number">0</span><span class="token punctuation">}</span><br />	<span class="token punctuation">}</span></code></pre>
<p id="code-skip-day-1-getting-a-handle-on-the-data-1">Ok, back to photos.</p>
<p>Looks like we got a problem: When the URL for a photo contains <code>foursquare</code> it doesn't map to a check-in, but to the location. Need to check.</p>
<p>Interesting. Somehow I have images that don't have attached check-ins. Seems impossible, but ok. Maybe from earlier versions of the app.</p>
<p>The photos don't seem to be joining in. Something is wrong with my logic. Hmmm.</p>
<p><a target="_blank" href="https://github.com/AramZS/locations/commit/391549c6bf0b0d6ca567ef05164958f5316266bc" class="git-commit-link"><code>git commit -am &quot;Attempting to process photos list&quot;</code></a></p>
]]></content:encoded>
	</item>
	
	<item>
		<title>Setting up a new site to get more hands on with Astro - Day 1</title>
		<link>https://fightwithtools.dev/posts/projects/tfts-grid/day-1-setting-up-astro-project/?source=rss</link>
		<pubDate>Tue, 24 Dec 2024 02:59:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/projects/tfts-grid/day-1-setting-up-astro-project/</guid>
		<description>Rebuilding an old site that broke, a wiki for a game I run.</description>
		<content:encoded><![CDATA[<h2 id="project-scope-and-todos" tabindex="-1">Project Scope and ToDos</h2>
<ol>
<li>Create a new site</li>
</ol>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Can be searched</li>
</ul>
<h2 id="day-1" tabindex="-1">Day 1</h2>
<p>Going through the Astro Vercel setup</p>
<h3 id="usage-with-vercel" tabindex="-1">Usage with Vercel</h3>
<ul>
<li><a href="https://docs.astro.build/en/guides/integrations-guide/vercel/" target="_blank">@astrojs/vercel | Docs</a></li>
<li><a href="https://docs.astro.build/en/guides/on-demand-rendering/" target="_blank">On-demand rendering | Docs</a></li>
<li><code>npx vercel login</code></li>
<li>Build locally
<ul>
<li><code>npx vercel build</code></li>
</ul>
</li>
<li><strong>Note</strong>: Vercel serverless currently (12/08/24) only works with Node 18. Make sure to use Node 18. - <a href="https://vercel.com/guides/serverless-function-contains-invalid-runtime-error" target="_blank">Serverless Function contains invalid runtime error</a></li>
</ul>
<h3 id="trying-plugins" tabindex="-1">Trying plugins</h3>
<p>I'm also interested in trying out more plugins with Astro. Here's some of the ones I'm looking at</p>
<h4 id="plugins" tabindex="-1">Plugins</h4>
<ul>
<li><a href="https://docs.astro.build/en/guides/integrations-guide/mdx/" target="_blank">@astrojs/mdx | Docs</a></li>
<li><a href="https://docs.astro.build/en/guides/integrations-guide/partytown/" target="_blank">@astrojs/partytown | Docs</a></li>
<li><a href="https://docs.astro.build/en/guides/integrations-guide/sitemap/" target="_blank">@astrojs/sitemap | Docs</a></li>
<li><a href="https://docs.astro.build/en/guides/integrations-guide/alpinejs/" target="_blank">@astrojs/alpinejs | Docs</a></li>
<li>Interesting - <a href="https://docs.astro.build/en/recipes/sharing-state/" target="_blank">Share state between Astro components | Docs</a></li>
</ul>
]]></content:encoded>
	</item>
	
	<item>
		<title>XYZ Site - Day 10 - Next step to rebuild Pocket exporting by optimizing for Netlify.</title>
		<link>https://fightwithtools.dev/posts/projects/aramzsxyz/day-10-getting-pocket-working-post-build-netlify-processing/?source=rss</link>
		<pubDate>Thu, 28 Nov 2024 21:59:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/projects/aramzsxyz/day-10-getting-pocket-working-post-build-netlify-processing/</guid>
		<description>Previously I had exported a nice simple JSON file I could turn into files, but that site broke, so trying Readwise instead</description>
		<content:encoded><![CDATA[<h2 id="project-scope-and-todos" tabindex="-1">Project Scope and ToDos</h2>
<ol>
<li>Create a versatile blog site</li>
<li>Create a framework that makes it easy to add external data to the site</li>
</ol>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Give the site the capacity to replicate the logging and rating I do on Serialized and Letterboxd.</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Be able to pull down RSS feeds from other sites and create forward links to my other sites</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Create forward links to sites I want to post about.</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Create a way to pull in my Goodreads data and display it on the site</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Create a way to automate pulls from other data sources</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Combine easy inputs like text lists and JSON data files with markdown files that I can build on top of.</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Add a TMDB credit to footer in base.njk</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Make sure tags do not repeat in the displayed tag list.</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Get my Kindle Quotes into the site</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> YouTube Channel Recommendations</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Minify HTML via Netlify plugin.</li>
</ul>
<h2 id="day-10" tabindex="-1">Day 10</h2>
<p>Ok, on a train, and learning all about <a href="https://docs.netlify.com/cli/get-started/" target="_blank">the Netlify CLI</a> so I can run the <a href="https://docs.netlify.com/build-plugins/create-plugins/#local-plugins" target="_blank">build</a> <a href="https://docs.netlify.com/build-plugins/?_gl=1*134epdf*_gcl_au*MTQzNzMxMjc2MS4xNzI0OTA0NzcwLjUwMTc0NTAzMy4xNzMyNDY4MzMzLjE3MzI0NjgzMzM." target="_blank">plugin</a> to minify the HTML locally.</p>
<p>I'm making sure <a href="https://docs.netlify.com/configure-builds/file-based-configuration/#sample-netlify-toml-file" target="_blank">my TOML file is configured correctly</a>.</p>
<p>Looks like it is. I can console.log to echo the configuration out and make sure.</p>
<p>I think it is set up correctly to use <code>onPostBuild</code> so that's good.</p>
<h3 id="using-netlify-cli" tabindex="-1">Using Netlify CLI</h3>
<p>I'm installing Netlify's CLI local to the project. So to authenticate in (which I need to do for some reason) I have to use <code>npx netlify link</code>.</p>
<p>I logged in last night, but it looks like I need to push <code>npx netlify status</code> to get it warmed up or something. Then I can use <code>npx netlify build</code>. That gets it running locally!</p>
<p>Looks like these <a href="https://github.com/kangax/html-minifier" target="_blank">options</a> to give me a similar HTML minification to what I had before:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/aramzsxyz/day-10-getting-pocket-working-post-build-netlify-processing/#code-skip-day-10-getting-pocket-working-post-build-netlify-processing-1" id="skip-to-code-skip-day-10-getting-pocket-working-post-build-netlify-processing-1" class="skip-link">Skip code block ▼</a></p>
<pre class="language-bash"><code class="language-bash"><span class="token punctuation">{</span><br />  collapseWhitespace: true,<br />  collapseInlineTagWhitespace: false,<br />  conservativeCollapse: true,<br />  preserveLineBreaks: false,<br />  removeComments: true,<br />  useShortDoctype: <span class="token boolean">true</span><br /><span class="token punctuation">}</span></code></pre>
<p id="code-skip-day-10-getting-pocket-working-post-build-netlify-processing-1">I think this is looking pretty good. Let's try and push it out.</p>
<p><a target="_blank" href="https://github.com/AramZS/aramzs.xyz/commit/315238a8dae5a2c354e3ce95901d205a9ff668ea" class="git-commit-link"><code>git commit -am &quot;Setting up logging and, hopefully, the right configuration for my Netlify plugin&quot;</code></a></p>
<p>Looks like it works!</p>
<p data-wordfix="true">I'm actually not sure how much extra time this saves, but I think by running it separate from the build, it should really decrease the amount of stuff that has to be held in memory. All that said, it looks like I've cut down around 10m from my production build time. Definitely a good sign.</p>
<p>I think the right thing to do, now that I have all these improvements, is merge them into main and then try and merge my Amplify changes in.</p>
<h3 id="subtree-update" tabindex="-1">Subtree Update</h3>
<p>Going to also <a href="https://www.atlassian.com/git/tutorials/git-subtree" target="_blank">subtree push</a></p>
<p><code>git subtree push --prefix plugins/netlify-plugin-html-minify git@github.com:AramZS/netlify-plugin-html-minify.git master</code></p>
<p>and <a href="https://github.com/philhawksworth/netlify-plugin-minify-html/pull/27" target="_blank">try and see if I can get the current owner of the html minification plugin to update theirs</a> and make it more broadly usable!</p>
<h3 id="things-looking-good!" tabindex="-1">Things looking good!</h3>
<p>Decided to start new and pull in the changes from other branches I needed. <a href="https://github.com/AramZS/aramzs.xyz/commit/bdd2033f12342d76295a3cb4876c9dd0f78644da" target="_blank">And it worked</a>! Things are looking good! Build time is very fast. This is great!</p>
<p>So a quick review of what worked here!</p>
<ul>
<li>I altered the process of loading postcss to manage it through the Eleventy loader. This allowed me to specify a single file to process, cutting down on the persistent set of files that were getting built to never be used.</li>
<li>I moved the HTML Minification process out of the Eleventy flow. By moving it to a Netlify plugin it allowed Node to drop the memory used to build the site with Eleventy and avoid the memory limit I was tripping over before by initiating a new block of memory instead of continuing to expand what Eleventy was working with.</li>
<li>I took a look at a Nunjucks filter that was running on every page and prioritized which pages it needed to run on and which I could avoid. Since my Amplify pages forward users directly to the target site, there's no need to have a bunch of article counts no one will ever see. I removed it.</li>
<li>The <code>filter</code> native Array property function is surprisingly expensive in execution time. Running it at even the reduced scale was pretty harmful to my build time. I switched it to a custom function which should consistently perform better</li>
<li>The <code>groupByKey</code> function is pretty powerful and clever! But I was only using it to count up a bunch posts and generate a full count number. I could make it a lot more performant by having it skip <code>mediaType</code> posts when they were not intended to be included. Then even faster by having it skip Amplify posts.</li>
<li>I could also speed up <code>groupByKey</code> significantly by switching it to using a standard <code>Object</code> instead of a <code>Map</code>. Maps are cool, and I like using them, but it turns out they take a <em>lot</em> more to process than standard objects. I wasn't really using their special features here, so I switched to a standard object.</li>
<li>Finally, on the <code>groupByKey</code> front, it's important to use the right tool for the right job. I may use it for other things later, but by having it build the huge object filled with every post in the collection it was sticking a ton of data in the active memory during the build. I made a <code>countByKey</code> function that just added up the posts and stored a single number instead of the whole object for each post. This really did great things for performance as well.</li>
<li>I added the 2023 Amplify posts to the ignore list via <code>eleventyConfig.ignores.add(&quot;src/content/amplify/2023/**&quot;);</code>. I don't really need them right now. <a href="https://www.w3.org/Provider/Style/URI" target="_blank">Good URLs stay alive forever</a> though, so, even though I don't think there are a ton of my Amplify links floating around, I'd like to get them back online. One of my ideas on this front is to use a date check to decide to automatically ignore a segment of Amplify posts and push them to my <code>_redirects</code> file instead, so they'll keep doing what they are intended to do without weighing down the build time. Something to experiment with later.</li>
</ul>
<p>There is likely more I can do to improve appearance, but it is high difficulty. Most notably, I could remove Amplify entirely from the <code>contentType</code> grouping. I really should have thought that through the first time, but now I'm pretty locked in though a bunch of places and fixing it is going to be a huge pain. I am having really good performance right know though, way better than even before I added all the Amplify posts. I think I'll save this as an option for later, if it is needed.</p>
<p>I'm pretty happy with all this, and the significant improvement in build time it created! I'm pretty consistently under 200s now! A huge improvement! We'll have to keep an eye on the stats here and see when we might need to improve a little more in advance this time.</p>
<p>Also, I noticed that there are some rendered files, like the Amplify files, that are just pretty large when they don't need to be. I could play around with improving that in the future. But for now, yay, my site works again!</p>
<p>Before:</p>
<p><img src="https://fightwithtools.dev/img/before-build-time.png" alt="Extensions activation" /></p>
<p>After:</p>
<p><img src="https://fightwithtools.dev/img/after-build-time.png" alt="Extensions activation" /></p>
<p>Even adding every single Amplify in to the production build of the novel only takes it up to 8m. A huge improvement!</p>
]]></content:encoded>
	</item>
	
	<item>
		<title>XYZ Site - Day 9 - PostCSS Mods - Speed up the massive build time and decrease needed memory by limiting what CSS gets built.</title>
		<link>https://fightwithtools.dev/posts/projects/aramzsxyz/day-9-getting-pocket-working-speeding-up-build/?source=rss</link>
		<pubDate>Wed, 27 Nov 2024 21:59:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/projects/aramzsxyz/day-9-getting-pocket-working-speeding-up-build/</guid>
		<description>Why can't I just designate files to process with PostCSS easily?</description>
		<content:encoded><![CDATA[<h2 id="project-scope-and-todos" tabindex="-1">Project Scope and ToDos</h2>
<ol>
<li>Create a versatile blog site</li>
<li>Create a framework that makes it easy to add external data to the site</li>
</ol>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Give the site the capacity to replicate the logging and rating I do on Serialized and Letterboxd.</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Be able to pull down RSS feeds from other sites and create forward links to my other sites</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Create forward links to sites I want to post about.</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Create a way to pull in my Goodreads data and display it on the site</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Create a way to automate pulls from other data sources</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Combine easy inputs like text lists and JSON data files with markdown files that I can build on top of.</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Add a TMDB credit to footer in base.njk</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Make sure tags do not repeat in the displayed tag list.</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Get my Kindle Quotes into the site</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> YouTube Channel Recommendations</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Minify HTML via Netlify plugin.</li>
</ul>
<h2 id="day-9" tabindex="-1">Day 9</h2>
<p>I'm trying to speed up the build time. It turns out that this many files is causing the memory in my Netlify build is causing the process to use up too much memory. So a few hacks to get in place.</p>
<p><code>filter</code> is too expensive for arrays from everything I've read so I'm going to try and replace it with a <code>for</code> I pulled off a blogpost.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/aramzsxyz/day-9-getting-pocket-working-speeding-up-build/#code-skip-day-9-getting-pocket-working-speeding-up-build-6" id="skip-to-code-skip-day-9-getting-pocket-working-speeding-up-build-6" class="skip-link">Skip code block ▼</a></p>
<pre class="language-js"><code class="language-js"><br /><span class="token comment">/**<br />@func util<br />a custom high-performance filter<br />via https://dev.to/functional_js/write-a-custom-javascript-filter-function-that-is-60-faster-than-array-filter-4b66<br />@perf<br />60% faster than the built-in JavaScript filter func<br />@typedef {(e: *) => boolean} filterFnAny<br />@param {filterFnAny} fn<br />@param {*[]} a<br />@return {*[]}<br />*/</span><br /><span class="token keyword">const</span> <span class="token function-variable function">betterFilter</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">fn<span class="token punctuation">,</span> a</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />  <span class="token keyword">const</span> f <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token comment">//final</span><br />  <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">let</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&lt;</span> a<span class="token punctuation">.</span>length<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">fn</span><span class="token punctuation">(</span>a<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />      f<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span>a<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />    <span class="token punctuation">}</span><br />  <span class="token punctuation">}</span><br />  <span class="token keyword">return</span> f<span class="token punctuation">;</span><br /><span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
<p id="code-skip-day-9-getting-pocket-working-speeding-up-build-6">There are a few places the filters for Nunjucks are using that <code>filter</code>, so I'll replace them.</p>
<p>I can also exclude <code>amplify</code> contentType posts from a number of places where it is building big objects up. Discarding them and doing it early in those processes should mean the build will take up less memory and go faster.</p>
<p>This is helping drop some of the build time, but it is still expensive.</p>
<p>My last build gave me this info:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/aramzsxyz/day-9-getting-pocket-working-speeding-up-build/#code-skip-day-9-getting-pocket-working-speeding-up-build-5" id="skip-to-code-skip-day-9-getting-pocket-working-speeding-up-build-5" class="skip-link">Skip code block ▼</a></p>
<pre class="language-bash"><code class="language-bash"><span class="token punctuation">[</span>11ty<span class="token punctuation">]</span> Benchmark  16412ms  <span class="token number">15</span>% <span class="token number">12166</span>× <span class="token punctuation">(</span>Configuration<span class="token punctuation">)</span> <span class="token string">"excludeStubs"</span> Nunjucks Filter<br /><span class="token punctuation">[</span>11ty<span class="token punctuation">]</span> Benchmark  35852ms  <span class="token number">33</span>% <span class="token number">36435</span>× <span class="token punctuation">(</span>Configuration<span class="token punctuation">)</span> <span class="token string">"countByKey"</span> Nunjucks Filter<br /><span class="token punctuation">[</span>11ty<span class="token punctuation">]</span> Benchmark  13719ms  <span class="token number">13</span>% <span class="token number">12168</span>× <span class="token punctuation">(</span>Configuration<span class="token punctuation">)</span> <span class="token string">"identifyGlyphs"</span> Transform</code></pre>
<p id="code-skip-day-9-getting-pocket-working-speeding-up-build-5">Big build functions. Let's see if I can accelerate further.</p>
<p>I'm going to try and use <code>&quot;@11ty/eleventy-plugin-directory-output&quot;</code> to give me some ideas of where I can decrease CPU and memory usage as well.</p>
<p>I've managed to improve some of these, but they're still expensive, especially when run so many times. <code>countByKey</code> is part of the menu build, so especially expensive.</p>
<p data-wordfix="true">I also want to try and remove the HTML minify process to Netlify, but the plugin they have for that doesn't seem to work, probably because it is so out of date. I'm going to <a href="https://www.atlassian.com/git/tutorials/git-subtree" target="_blank">subtree</a> it in and run it internally.</p>
<p><a target="_blank" href="https://github.com/AramZS/aramzs.xyz/commit/db3ddef461615f0fd17343258a5892af871a41c0" class="git-commit-link"><code>git commit -am &quot;Moving html minification to a netlify function&quot;</code></a></p>
<p>Let's try and run this on Netlify to see if my switchover works!</p>
<p>Huh, apparently in order to run Netlify <a href="https://docs.netlify.com/build-plugins/" target="_blank">plugins</a> that are local to the project I need to add a plugin:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/aramzsxyz/day-9-getting-pocket-working-speeding-up-build/#code-skip-day-9-getting-pocket-working-speeding-up-build-4" id="skip-to-code-skip-day-9-getting-pocket-working-speeding-up-build-4" class="skip-link">Skip code block ▼</a></p>
<pre class="language-yaml"><code class="language-yaml"><span class="token punctuation">[</span><span class="token punctuation">[</span>plugins<span class="token punctuation">]</span><span class="token punctuation">]</span><br />package = "@netlify/plugin<span class="token punctuation">-</span>local<span class="token punctuation">-</span>install<span class="token punctuation">-</span>core"</code></pre>
<p id="code-skip-day-9-getting-pocket-working-speeding-up-build-4">This gets it running, but it doesn't seem to actually minify the HTML, no matter <a href="http://perfectionkills.com/experimenting-with-html-minifier/" target="_blank">what options</a> I put in! Ugh. Maybe I'll leave that alone for now to fiddle with later. <a href="https://docs.netlify.com/cli/get-started/#run-builds-locally" target="_blank">Looks like there is info about how to test it here</a>.</p>
<p>I'm also looking at how to fix it so it isn't spending time building the sub-css files that are prefixed with <code>_</code>, which it seems to be doing.</p>
<p>Is there really no way to get postcss not to waste time on the included files? It seems very strange to me.</p>
<p data-wordfix="true">Ok, I looked around and <a href="https://github.com/11ty/eleventy/discussions/2388" target="_blank">found</a> a way that speeds things up significantly. I can add it <a href="https://www.11ty.dev/docs/languages/custom/" target="_blank">as a template format</a> and then manage it with an extension.</p>
<p>I can manage it in an extensions file.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/aramzsxyz/day-9-getting-pocket-working-speeding-up-build/#code-skip-day-9-getting-pocket-working-speeding-up-build-3" id="skip-to-code-skip-day-9-getting-pocket-working-speeding-up-build-3" class="skip-link">Skip code block ▼</a></p>
<pre class="language-js"><code class="language-js"><span class="token keyword">const</span> cssHandler <span class="token operator">=</span> <span class="token punctuation">{</span><br />  <span class="token literal-property property">outputFileExtension</span><span class="token operator">:</span> <span class="token string">'css'</span><span class="token punctuation">,</span><br />  <span class="token function-variable function">compile</span><span class="token operator">:</span> <span class="token keyword">async</span> <span class="token punctuation">(</span><span class="token parameter">inputContent<span class="token punctuation">,</span> inputPath</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />    <span class="token keyword">if</span> <span class="token punctuation">(</span>inputPath <span class="token operator">!==</span> <span class="token string">'./src/styles/main.css'</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />      <span class="token keyword">return</span><span class="token punctuation">;</span><br />    <span class="token punctuation">}</span><br /><br />    <span class="token keyword">return</span> <span class="token keyword">async</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />      <span class="token keyword">const</span> postcss <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'postcss'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />      <span class="token comment">// https://github.com/postcss/postcss-load-config</span><br />      <span class="token keyword">const</span> postcssrc <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'postcss-load-config'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />      console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'postcssrc'</span><span class="token punctuation">,</span> postcssrc<span class="token punctuation">)</span><span class="token punctuation">;</span><br />      <span class="token comment">// https://github.com/11ty/eleventy/discussions/2388</span><br />      <span class="token keyword">let</span> cssPromise <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Promise</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">resolve<span class="token punctuation">,</span> reject</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />        <span class="token function">postcssrc</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> plugins<span class="token punctuation">,</span> options <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />          console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'pcss plugins'</span><span class="token punctuation">,</span> plugins<span class="token punctuation">)</span><span class="token punctuation">;</span><br />          options<span class="token punctuation">.</span>from <span class="token operator">=</span> inputPath<span class="token punctuation">;</span><br />          console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'pcss options'</span><span class="token punctuation">,</span> options<span class="token punctuation">)</span><span class="token punctuation">;</span><br />          <span class="token function">postcss</span><span class="token punctuation">(</span>plugins<span class="token punctuation">)</span><br />            <span class="token punctuation">.</span><span class="token function">process</span><span class="token punctuation">(</span>inputContent<span class="token punctuation">,</span> options<span class="token punctuation">)</span><br />            <span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">result</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />              <span class="token function">resolve</span><span class="token punctuation">(</span>result<span class="token punctuation">.</span>css<span class="token punctuation">)</span><br />            <span class="token punctuation">}</span><span class="token punctuation">)</span><br />        <span class="token punctuation">}</span><span class="token punctuation">)</span><br />      <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />      <span class="token keyword">const</span> cssResult <span class="token operator">=</span> <span class="token keyword">await</span> cssPromise<span class="token punctuation">;</span><br />      <span class="token comment">// console.log('cssResult', cssResult);</span><br />      <span class="token comment">// debugger;</span><br />      <span class="token keyword">return</span> cssResult<span class="token punctuation">;</span><br /><br />      <span class="token keyword">let</span> output <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token function">postcss</span><span class="token punctuation">(</span><span class="token punctuation">[</span><br />        pimport<span class="token punctuation">,</span><br />        autoprefixer<span class="token punctuation">,</span><br />        csso<br />      <span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">process</span><span class="token punctuation">(</span>inputContent<span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">from</span><span class="token operator">:</span> inputPath <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />    <span class="token punctuation">}</span><br />  <span class="token punctuation">}</span><br /><span class="token punctuation">}</span><span class="token punctuation">;</span><br /><br /><br />module<span class="token punctuation">.</span>exports <span class="token operator">=</span> <span class="token punctuation">{</span><br />  <span class="token literal-property property">css</span><span class="token operator">:</span> cssHandler<br /><span class="token punctuation">}</span></code></pre>
<p id="code-skip-day-9-getting-pocket-working-speeding-up-build-3">which I can then load like this in my eleventy config file:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/aramzsxyz/day-9-getting-pocket-working-speeding-up-build/#code-skip-day-9-getting-pocket-working-speeding-up-build-2" id="skip-to-code-skip-day-9-getting-pocket-working-speeding-up-build-2" class="skip-link">Skip code block ▼</a></p>
<pre class="language-js"><code class="language-js">  eleventyConfig<span class="token punctuation">.</span><span class="token function">addTemplateFormats</span><span class="token punctuation">(</span><span class="token string">'css'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br />  Object<span class="token punctuation">.</span><span class="token function">keys</span><span class="token punctuation">(</span>extensions<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">extensionName</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />		eleventyConfig<span class="token punctuation">.</span><span class="token function">addExtension</span><span class="token punctuation">(</span>extensionName<span class="token punctuation">,</span> extensions<span class="token punctuation">[</span>extensionName<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p id="code-skip-day-9-getting-pocket-working-speeding-up-build-2">I added the use of <code>'postcss-load-config'</code> here to let me manage postcss settings and plugins from a file at <code>postcss.config.js</code>.</p>
<p>In case you are wondering, the logging looks like this:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/aramzsxyz/day-9-getting-pocket-working-speeding-up-build/#code-skip-day-9-getting-pocket-working-speeding-up-build-1" id="skip-to-code-skip-day-9-getting-pocket-working-speeding-up-build-1" class="skip-link">Skip code block ▼</a></p>
<pre class="language-bash"><code class="language-bash">postcssrc <span class="token punctuation">[</span>Function: rc<span class="token punctuation">]</span><br />pcss plugins <span class="token punctuation">[</span><br />  <span class="token punctuation">[</span>Function: AtImport<span class="token punctuation">]</span> <span class="token punctuation">{</span> postcss: <span class="token boolean">true</span> <span class="token punctuation">}</span>,<br />  <span class="token punctuation">[</span>Function: plugin<span class="token punctuation">]</span> <span class="token punctuation">{</span><br />    postcss: true,<br />    data: <span class="token punctuation">{</span> browsers: <span class="token punctuation">[</span>Object<span class="token punctuation">]</span>, prefixes: <span class="token punctuation">[</span>Object<span class="token punctuation">]</span> <span class="token punctuation">}</span>,<br />    defaults: <span class="token punctuation">[</span> <span class="token string">'> 0.5%'</span>, <span class="token string">'last 2 versions'</span>, <span class="token string">'Firefox ESR'</span>, <span class="token string">'not dead'</span> <span class="token punctuation">]</span>,<br />    info: <span class="token punctuation">[</span>Function <span class="token punctuation">(</span>anonymous<span class="token punctuation">)</span><span class="token punctuation">]</span><br />  <span class="token punctuation">}</span>,<br />  <span class="token punctuation">{</span> postcssPlugin: <span class="token string">'postcss-purgecss'</span>, OnceExit: <span class="token punctuation">[</span>Function: OnceExit<span class="token punctuation">]</span> <span class="token punctuation">}</span>,<br />  <span class="token punctuation">[</span>Function <span class="token punctuation">(</span>anonymous<span class="token punctuation">)</span><span class="token punctuation">]</span> <span class="token punctuation">{</span> postcss: <span class="token boolean">true</span> <span class="token punctuation">}</span><br /><span class="token punctuation">]</span><br />pcss options <span class="token punctuation">{</span><br />  configLocation: <span class="token string">'./postcss.config.js'</span>,<br />  cwd: <span class="token string">'/Users/chrono/Dev/aramzs.xyz'</span>,<br />  env: undefined,<br />  from: <span class="token string">'./src/styles/main.css'</span><br /><span class="token punctuation">}</span></code></pre>
<p id="code-skip-day-9-getting-pocket-working-speeding-up-build-1">Looks like the <code>options</code> we get out of that tool is just everything supplied in the export of the file that isn't on the <code>plugins</code> property.</p>
<p>Ok, that works <em>much</em> faster. Mostly because it only has to process the <code>main.css</code> file and not build the others.</p>
<p><a target="_blank" href="https://github.com/AramZS/aramzs.xyz/commit/ecb89ef623364d01a3037b7dea80fabae6fb7496" class="git-commit-link"><code>git commit -am &quot;Move postcss processing internal to the template format flow of eleventy&quot;</code></a></p>
<p>I can also remove invocations of my most expensive functions from the pages that forward users where the users will never see the menu that triggers them.</p>
<p><a target="_blank" href="https://github.com/AramZS/aramzs.xyz/commit/2e70c355994d671dd3198c31e4ac35c7756e851e" class="git-commit-link"><code>git commit -am &quot;Remove the invocations of the counting function from pages that no user is likely to see because they mostly are forwarding people&quot;</code></a></p>
]]></content:encoded>
	</item>
	
	<item>
		<title>XYZ Site - Day 8 - Next step to rebuild Pocket exporting - export to flat file.</title>
		<link>https://fightwithtools.dev/posts/projects/aramzsxyz/day-8-getting-pocket-working-processing-to-flat-file-part-3/?source=rss</link>
		<pubDate>Tue, 26 Nov 2024 21:59:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/projects/aramzsxyz/day-8-getting-pocket-working-processing-to-flat-file-part-3/</guid>
		<description>Now that I've figured out the API, I have to get it written to the flat files in my system for 11ty to build</description>
		<content:encoded><![CDATA[<h2 id="project-scope-and-todos" tabindex="-1">Project Scope and ToDos</h2>
<ol>
<li>Create a versatile blog site</li>
<li>Create a framework that makes it easy to add external data to the site</li>
</ol>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Give the site the capacity to replicate the logging and rating I do on Serialized and Letterboxd.</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Be able to pull down RSS feeds from other sites and create forward links to my other sites</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Create forward links to sites I want to post about.</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Create a way to pull in my Goodreads data and display it on the site</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Create a way to automate pulls from other data sources</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Combine easy inputs like text lists and JSON data files with markdown files that I can build on top of.</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Add a TMDB credit to footer in base.njk</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Make sure tags do not repeat in the displayed tag list.</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Get my Kindle Quotes into the site</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> YouTube Channel Recommendations</li>
</ul>
<h2 id="day-8" tabindex="-1">Day 8</h2>
<p>Ok, I'm pulling the link object into my markdown writer and it is looking good. It is retaining the right naming conventions.</p>
<p>I'm going to use Sort - Oldest to see if it will match up with my old file titles. It looks like it might be rewriting over existing files. I don't want that. I'll try passing in the neverOverwrite property I assigned to my JSON-to-flat-file creator. I also want to try and figure out how to bring in cover images for social for this. I should be able to pull them out of the pocket object.</p>
<p>Ok, it's looking good. I had to adjust how images are rendered to check if they have https in the string and not try to prepend my img path if they do.</p>
<p>Now I'm pre-setting some of the set up to crawl the whole API and get every article I'm missing. I want to use the <code>since</code> param in the config I pass to only get new articles after this, so I'll set up for that too.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/aramzsxyz/day-8-getting-pocket-working-processing-to-flat-file-part-3/#code-skip-day-8-getting-pocket-working-processing-to-flat-file-part-3-1" id="skip-to-code-skip-day-8-getting-pocket-working-processing-to-flat-file-part-3-1" class="skip-link">Skip code block ▼</a></p>
<pre class="language-js"><code class="language-js"><br /><span class="token keyword">const</span> <span class="token function-variable function">walkPocketAPI</span> <span class="token operator">=</span> <span class="token keyword">async</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />  <span class="token comment">// let resultObj = await processPocketExport(0);</span><br />  <span class="token keyword">let</span> offset <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span><br />  <span class="token keyword">let</span> total <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span><br />  <span class="token comment">// let resultSet = [];</span><br /><br />  <span class="token keyword">do</span> <span class="token punctuation">{</span><br />    <span class="token keyword">let</span> resultObj <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token function">processPocketExport</span><span class="token punctuation">(</span>offset<span class="token punctuation">)</span><span class="token punctuation">;</span><br />    <span class="token comment">// resultSet = resultSet.concat(resultObj.resultSet);</span><br />    total <span class="token operator">=</span> resultObj<span class="token punctuation">.</span>total<span class="token punctuation">;</span><br />    offset <span class="token operator">+=</span> resultObj<span class="token punctuation">.</span>resultSet<span class="token punctuation">.</span>length<span class="token punctuation">;</span><br />  <span class="token punctuation">}</span> <span class="token keyword">while</span> <span class="token punctuation">(</span>total <span class="token operator">></span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br />  <span class="token keyword">return</span> resultSet<span class="token punctuation">;</span><br />  <span class="token comment">// return result;</span><br /><span class="token punctuation">}</span></code></pre>
<p id="code-skip-day-8-getting-pocket-working-processing-to-flat-file-part-3-1">Hmmm. It looks like the API response isn't sending me a <code>total</code> value. Well, let's adjust to that.</p>
<p>Oops, forgot to make sure that it can handle a lack of tags. I'll fix that.</p>
<p>Ok, now I just need to make sure I can handle a few other places it can fail and fix the return in the above function and I should be good to go.</p>
]]></content:encoded>
	</item>
	
	<item>
		<title>Fixing the right click context menu in OSX Finder</title>
		<link>https://fightwithtools.dev/posts/writing/dropbox-sync-fix/?source=rss</link>
		<pubDate>Fri, 22 Nov 2024 20:30:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/writing/dropbox-sync-fix/</guid>
		<description>Grabbed some open source code and made a few modifications that let me use Spotipy to archive my Liked Songs into another playlist.</description>
		<content:encoded><![CDATA[<p>I have been very slowly setting up a new work computer and keeping track of what is going on by updating my <a href="https://github.com/AramZS/dotfiles" target="_blank">dotfile repository</a>. I installed Dropbox and then I went to open one of my Obsidian vaults I keep synced with Dropbox only to find that it wasn't working because Dropbox hadn't fully downloaded the files. Normally this is an easy solve: I right click on the folder and say &quot;Make available offline&quot;. But the menu options weren't available! I searched around, tried a bunch of forum posts' suggestions; even rebooted my computer twice.</p>
<p>All of this and none of it worked! I was at a loss. Then I fiddled around more with Quick Actions &gt; Customize on the folder right click and found the solution. If you too are looking for a solution, here is what it is (adapted from the Apple OSX documentation):</p>
<h2 id="the-solution" tabindex="-1">The Solution</h2>
<p>Go to Apple menu  &gt; System Settings, click Privacy &amp; Security in the sidebar, then click Extensions on the right. (You may need to scroll down.) Click Added Extensions and hit the checkboxes to enable Dropbox's Finder Extensions</p>
<h2 id="the-solution-visualized" tabindex="-1">The Solution Visualized</h2>
<p>Here's the steps with screenshots:</p>
<p>Find the Extensions button on the bottom of Privacy &amp; Security:<br />
<img src="https://fightwithtools.dev/img/dropbox-folders-step-one.png" alt="Extensions activation" /></p>
<p>Once that is open, you can click Added extensions:<br />
<img src="https://fightwithtools.dev/img/dropbox-folders-step-two.png" alt="Added extensions area" /></p>
<p>Then you can activate the Dropbox extensions and everything should work!<br />
<img src="https://fightwithtools.dev/img/dropbox-folders-step-three.png" alt="Dropbox extensions checked to activate" /></p>
]]></content:encoded>
	</item>
	
	<item>
		<title>XYZ Site - Day 7 - Next step to rebuild Pocket exporting - part 2.</title>
		<link>https://fightwithtools.dev/posts/projects/aramzsxyz/day-7-getting-pocket-working-part-2/?source=rss</link>
		<pubDate>Thu, 21 Nov 2024 21:59:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/projects/aramzsxyz/day-7-getting-pocket-working-part-2/</guid>
		<description>Continuing to try and process Pocket's API output.</description>
		<content:encoded><![CDATA[<h2 id="project-scope-and-todos" tabindex="-1">Project Scope and ToDos</h2>
<ol>
<li>Create a versatile blog site</li>
<li>Create a framework that makes it easy to add external data to the site</li>
</ol>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Give the site the capacity to replicate the logging and rating I do on Serialized and Letterboxd.</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Be able to pull down RSS feeds from other sites and create forward links to my other sites</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Create forward links to sites I want to post about.</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Create a way to pull in my Goodreads data and display it on the site</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Create a way to automate pulls from other data sources</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Combine easy inputs like text lists and JSON data files with markdown files that I can build on top of.</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Add a TMDB credit to footer in base.njk</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Make sure tags do not repeat in the displayed tag list.</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Get my Kindle Quotes into the site</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> YouTube Channel Recommendations</li>
</ul>
<h2 id="day-7" tabindex="-1">Day 7</h2>
<p>Ok, let's look at translating objects from the Pocket API to my own.</p>
<p>Ok, most of the translation is pretty obvious. However, there is something a little weird.</p>
<p>Here's my old object:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/aramzsxyz/day-7-getting-pocket-working-part-2/#code-skip-day-7-getting-pocket-working-part-2-4" id="skip-to-code-skip-day-7-getting-pocket-working-part-2-4" class="skip-link">Skip code block ▼</a></p>
<pre class="language-js"><code class="language-js"><span class="token keyword">let</span> dataSet <span class="token operator">=</span> <span class="token punctuation">{</span><br />	<span class="token literal-property property">link</span><span class="token operator">:</span> aChild<span class="token punctuation">.</span>href<span class="token punctuation">,</span><br />	<span class="token literal-property property">date</span><span class="token operator">:</span> isoDate<span class="token punctuation">,</span><br />	<span class="token literal-property property">tags</span><span class="token operator">:</span> aChild<span class="token punctuation">.</span><span class="token function">getAttribute</span><span class="token punctuation">(</span><span class="token string">'tags'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">split</span><span class="token punctuation">(</span><span class="token string">','</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">filter</span><span class="token punctuation">(</span><span class="token parameter">e</span> <span class="token operator">=></span> e<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token parameter">tag</span> <span class="token operator">=></span> tag<span class="token punctuation">.</span><span class="token function">toLowerCase</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br />	<span class="token literal-property property">title</span><span class="token operator">:</span> aChild<span class="token punctuation">.</span>textContent<span class="token punctuation">,</span><br />	<span class="token literal-property property">content</span><span class="token operator">:</span> <span class="token string">''</span><span class="token punctuation">,</span><br />	<span class="token literal-property property">isBasedOn</span><span class="token operator">:</span> aChild<span class="token punctuation">.</span>href<span class="token punctuation">,</span><br />	<span class="token literal-property property">slug</span><span class="token operator">:</span> <span class="token function">slugger</span><span class="token punctuation">(</span>dateFileString <span class="token operator">+</span> <span class="token string">"-"</span> <span class="token operator">+</span> aChild<span class="token punctuation">.</span>textContent<span class="token punctuation">)</span><span class="token punctuation">,</span><br />	<span class="token literal-property property">dateFolder</span><span class="token operator">:</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>year<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">/</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>month<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">/</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>day<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><br /><span class="token punctuation">}</span></code></pre>
<p id="code-skip-day-7-getting-pocket-working-part-2-4">The weird thing is the <code>textContent</code> check of the slug. I want to have the same slugs as before. The files do look like they are taking a URL. The <code>aChild</code> object is the link but the link it is pulling here is as follows:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/aramzsxyz/day-7-getting-pocket-working-part-2/#code-skip-day-7-getting-pocket-working-part-2-3" id="skip-to-code-skip-day-7-getting-pocket-working-part-2-3" class="skip-link">Skip code block ▼</a></p>
<pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>https://www.poynter.org/business-work/2024/over-half-of-journalists-considered-quitting-due-to-burnout-this-year-per-new-report/<span class="token punctuation">"</span></span> <span class="token attr-name">time_added</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>1727312468<span class="token punctuation">"</span></span> <span class="token attr-name">tags</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>journalism<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Over half of journalists considered quitting due to burnout this year, per new report - Poynter<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>a</span><span class="token punctuation">></span></span></code></pre>
<p id="code-skip-day-7-getting-pocket-working-part-2-3">Well, it should be fine as long as I'm using the same slug right?</p>
<p>Ok, so we'll hook it up to my function and take a look at trying to write some files.</p>
<p>Hmmm, the CLI tool isn't opening the browser like it did before. I wonder if it is a systems thing.</p>
<p>Ok, just needed to restart the computer I guess.</p>
<p>I also needed to break down the date object into a more manageable function:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/aramzsxyz/day-7-getting-pocket-working-part-2/#code-skip-day-7-getting-pocket-working-part-2-2" id="skip-to-code-skip-day-7-getting-pocket-working-part-2-2" class="skip-link">Skip code block ▼</a></p>
<pre class="language-js"><code class="language-js"><span class="token keyword">const</span> <span class="token function-variable function">dateInfoObjMaker</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">initialDateString</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />  <span class="token keyword">let</span> dateString <span class="token operator">=</span> <span class="token string">''</span><span class="token punctuation">;</span><br />  <span class="token keyword">try</span> <span class="token punctuation">{</span><br />    dateString <span class="token operator">=</span> initialDateString <span class="token operator">||</span> <span class="token string">''</span><span class="token punctuation">;</span><br />  <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span>e<span class="token punctuation">)</span> <span class="token punctuation">{</span><br />    console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Date error'</span><span class="token punctuation">,</span> el<span class="token punctuation">,</span> aChild<span class="token punctuation">)</span><span class="token punctuation">;</span><br />    <span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">Error</span><span class="token punctuation">(</span><span class="token string">'Could not parse date'</span> <span class="token operator">+</span> el<span class="token punctuation">)</span><br />  <span class="token punctuation">}</span><br />  <span class="token keyword">let</span> dateObj <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span><span class="token function">parseInt</span><span class="token punctuation">(</span>dateString<span class="token punctuation">)</span> <span class="token operator">*</span> <span class="token number">1000</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />  <span class="token comment">// Generate a file-slug YYYY-MM-DD string from the date</span><br />  <span class="token keyword">let</span> date <span class="token operator">=</span> dateObj<span class="token punctuation">;</span><br />  <span class="token keyword">let</span> yearFormatter <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Intl<span class="token punctuation">.</span>DateTimeFormat</span><span class="token punctuation">(</span><span class="token string">'en-US'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">timeZone</span><span class="token operator">:</span> <span class="token string">'America/New_York'</span><span class="token punctuation">,</span> <span class="token literal-property property">year</span><span class="token operator">:</span> <span class="token string">'numeric'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br />  <span class="token keyword">let</span> year <span class="token operator">=</span> yearFormatter<span class="token punctuation">.</span><span class="token function">format</span><span class="token punctuation">(</span>dateObj<span class="token punctuation">)</span><span class="token punctuation">;</span><br />  <span class="token comment">// Use Intl.DateTimeFormat to get the month in New York timezone</span><br />  <span class="token keyword">let</span> monthFormatter <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Intl<span class="token punctuation">.</span>DateTimeFormat</span><span class="token punctuation">(</span><span class="token string">'en-US'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">timeZone</span><span class="token operator">:</span> <span class="token string">'America/New_York'</span><span class="token punctuation">,</span> <span class="token literal-property property">month</span><span class="token operator">:</span> <span class="token string">'2-digit'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />  <span class="token keyword">let</span> month <span class="token operator">=</span> monthFormatter<span class="token punctuation">.</span><span class="token function">format</span><span class="token punctuation">(</span>date<span class="token punctuation">)</span><span class="token punctuation">;</span><br />  <span class="token comment">// Use Intl.DateTimeFormat to get the day in New York timezone</span><br />  <span class="token keyword">let</span> dayFormatter <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Intl<span class="token punctuation">.</span>DateTimeFormat</span><span class="token punctuation">(</span><span class="token string">'en-US'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">timeZone</span><span class="token operator">:</span> <span class="token string">'America/New_York'</span><span class="token punctuation">,</span> <span class="token literal-property property">day</span><span class="token operator">:</span> <span class="token string">'2-digit'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />  <span class="token keyword">let</span> day <span class="token operator">=</span> dayFormatter<span class="token punctuation">.</span><span class="token function">format</span><span class="token punctuation">(</span>date<span class="token punctuation">)</span><span class="token punctuation">;</span><br />  <span class="token keyword">let</span> dateFileString <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>year<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">-</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>month<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">-</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>day<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span><br />  <span class="token keyword">let</span> isoDate <span class="token operator">=</span> <span class="token string">''</span><span class="token punctuation">;</span><br />  <span class="token keyword">try</span> <span class="token punctuation">{</span><br />    isoDate <span class="token operator">=</span> dateObj<span class="token punctuation">.</span><span class="token function">toISOString</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />  <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span>e<span class="token punctuation">)</span> <span class="token punctuation">{</span><br />    console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Date error'</span><span class="token punctuation">,</span> e<span class="token punctuation">,</span> dateString<span class="token punctuation">)</span><span class="token punctuation">;</span><br />    <span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">Error</span><span class="token punctuation">(</span><span class="token string">'Could not parse date'</span> <span class="token operator">+</span> dateString<span class="token punctuation">)</span><br />  <span class="token punctuation">}</span><br />  <span class="token keyword">return</span> <span class="token punctuation">{</span><br />    <span class="token literal-property property">year</span><span class="token operator">:</span> year<span class="token punctuation">,</span><br />    <span class="token literal-property property">month</span><span class="token operator">:</span> month<span class="token punctuation">,</span><br />    <span class="token literal-property property">day</span><span class="token operator">:</span> day<span class="token punctuation">,</span><br />    <span class="token literal-property property">dateFileString</span><span class="token operator">:</span> dateFileString<span class="token punctuation">,</span><br />    <span class="token literal-property property">isoDate</span><span class="token operator">:</span> isoDate<br />  <span class="token punctuation">}</span><br /><span class="token punctuation">}</span></code></pre>
<p id="code-skip-day-7-getting-pocket-working-part-2-2">Looking good! I think I got it:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/aramzsxyz/day-7-getting-pocket-working-part-2/#code-skip-day-7-getting-pocket-working-part-2-1" id="skip-to-code-skip-day-7-getting-pocket-working-part-2-1" class="skip-link">Skip code block ▼</a></p>
<pre class="language-js"><code class="language-js"><span class="token punctuation">{</span><br />	<span class="token literal-property property">link</span><span class="token operator">:</span> <span class="token string">'https://www.axios.com/2024/11/21/sec-chair-gary-gensler-step-down'</span><span class="token punctuation">,</span><br />	<span class="token literal-property property">date</span><span class="token operator">:</span> <span class="token string">'2024-11-21T18:04:50.000Z'</span><span class="token punctuation">,</span><br />	<span class="token literal-property property">tags</span><span class="token operator">:</span> <span class="token punctuation">[</span> <span class="token string">'economy'</span><span class="token punctuation">,</span> <span class="token string">'politics'</span> <span class="token punctuation">]</span><span class="token punctuation">,</span><br />	<span class="token literal-property property">title</span><span class="token operator">:</span> <span class="token string">'https://www.axios.com/2024/11/21/sec-chair-gary-gensler-step-down'</span><span class="token punctuation">,</span><br />	<span class="token literal-property property">description</span><span class="token operator">:</span> <span class="token string">''</span><span class="token punctuation">,</span><br />	<span class="token literal-property property">content</span><span class="token operator">:</span> <span class="token string">''</span><span class="token punctuation">,</span><br />	<span class="token literal-property property">isBasedOn</span><span class="token operator">:</span> <span class="token string">'https://www.axios.com/2024/11/21/sec-chair-gary-gensler-step-down'</span><span class="token punctuation">,</span><br />	<span class="token literal-property property">slug</span><span class="token operator">:</span> <span class="token string">'2024-11-21-httpswwwaxioscom20241121sec-chair-gary-gensler-step-down'</span><span class="token punctuation">,</span><br />	<span class="token literal-property property">dateFolder</span><span class="token operator">:</span> <span class="token string">'2024/11/21'</span><br /><span class="token punctuation">}</span><span class="token punctuation">,</span></code></pre>
<p id="code-skip-day-7-getting-pocket-working-part-2-1">The next step is seeing how it looks when I write it to a file.</p>
]]></content:encoded>
	</item>
	
	<item>
		<title>XYZ Site - Day 6 - Starting to rebuild Pocket exporting.</title>
		<link>https://fightwithtools.dev/posts/projects/aramzsxyz/day-6-getting-pocket-working/?source=rss</link>
		<pubDate>Wed, 20 Nov 2024 21:59:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/projects/aramzsxyz/day-6-getting-pocket-working/</guid>
		<description>I have too many things saved into Pocket right now, so I can't export a file anymore. I've got to figure out their API instead.</description>
		<content:encoded><![CDATA[<h2 id="project-scope-and-todos" tabindex="-1">Project Scope and ToDos</h2>
<ol>
<li>Create a versatile blog site</li>
<li>Create a framework that makes it easy to add external data to the site</li>
</ol>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Give the site the capacity to replicate the logging and rating I do on Serialized and Letterboxd.</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Be able to pull down RSS feeds from other sites and create forward links to my other sites</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Create forward links to sites I want to post about.</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Create a way to pull in my Goodreads data and display it on the site</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Create a way to automate pulls from other data sources</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Combine easy inputs like text lists and JSON data files with markdown files that I can build on top of.</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Add a TMDB credit to footer in base.njk</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Make sure tags do not repeat in the displayed tag list.</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Get my Kindle Quotes into the site</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> YouTube Channel Recommendations</li>
</ul>
<h2 id="day-6" tabindex="-1">Day 6</h2>
<p>Time to fix my broken processing of Pocket exports. Let's start with using a CLI auth tool. That will be the node Pocket API CLI tool. I can use that plus a dotenv CLI package to pass in the consumer key from a <code>.env</code> file without committing it.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/aramzsxyz/day-6-getting-pocket-working/#code-skip-day-6-getting-pocket-working-4" id="skip-to-code-skip-day-6-getting-pocket-working-4" class="skip-link">Skip code block ▼</a></p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span><br />	...<br />    <span class="token property">"write:pocket-info-user"</span><span class="token operator">:</span> <span class="token string">"node -e \"console.log('POCKET_UN=\\\"'+$(sed '3q;d' .env-json.json).username.trim()+'\\\"');\" >> .env"</span><span class="token punctuation">,</span><br />    <span class="token property">"write:pocket-info-access"</span><span class="token operator">:</span> <span class="token string">"node -e \"console.log('ACCESS_TOKEN=\\\"'+$(sed '3q;d' .env-json.json).access_token.trim()+'\\\"');\" >> .env"</span><span class="token punctuation">,</span><br />    <span class="token property">"activate:pocket"</span><span class="token operator">:</span> <span class="token string">"node_modules/pocket-auth-cli/bin/pocket-auth $CON_KEY > .env-json.json &amp;&amp; total_string=\"CON_KEY=\\\"$CON_KEY\\\"\" &amp;&amp; echo $total_string > .env &amp;&amp; npm run write:pocket-info-access &amp;&amp; npm run write:pocket-info-user &amp;&amp; node -e 'var w = require(\"./bin/enrichers/pocket-api.js\"); w.writeAmplify()'"</span><span class="token punctuation">,</span><br />    <span class="token property">"get:pocket"</span><span class="token operator">:</span> <span class="token string">"node node_modules/dotenv-cli/cli.js -- npm run activate:pocket"</span></code></pre>
<p id="code-skip-day-6-getting-pocket-working-4">Now I can process the resulting variables that this process has written into my .env file in my JS code.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/aramzsxyz/day-6-getting-pocket-working/#code-skip-day-6-getting-pocket-working-3" id="skip-to-code-skip-day-6-getting-pocket-working-3" class="skip-link">Skip code block ▼</a></p>
<pre class="language-js"><code class="language-js"><br /><span class="token keyword">const</span> <span class="token function-variable function">processPocketExport</span> <span class="token operator">=</span> <span class="token keyword">async</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />  <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'dotenv'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">config</span><span class="token punctuation">(</span><span class="token punctuation">)</span><br /><br />  <span class="token keyword">let</span> consumer_key <span class="token operator">=</span> process<span class="token punctuation">.</span>env<span class="token punctuation">.</span><span class="token constant">CON_KEY</span><span class="token punctuation">;</span><br />  <span class="token keyword">let</span> access_token <span class="token operator">=</span> process<span class="token punctuation">.</span>env<span class="token punctuation">.</span><span class="token constant">ACCESS_TOKEN</span><span class="token punctuation">;</span><br /><br />  <span class="token keyword">let</span> pocket <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">getPocket</span><span class="token punctuation">(</span>consumer_key<span class="token punctuation">)</span><span class="token punctuation">;</span><br />  <span class="token comment">//sets access_token</span><br />  pocket<span class="token punctuation">.</span><span class="token function">setAccessToken</span><span class="token punctuation">(</span>access_token<span class="token punctuation">)</span><br />  <span class="token keyword">const</span> pocketConfigForGet <span class="token operator">=</span> <span class="token punctuation">{</span><br />    <span class="token literal-property property">state</span><span class="token operator">:</span> <span class="token string">'all'</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">sort</span><span class="token operator">:</span> <span class="token string">'newest'</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">detailType</span><span class="token operator">:</span> <span class="token string">'complete'</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">count</span><span class="token operator">:</span> <span class="token number">4</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">offset</span><span class="token operator">:</span> <span class="token number">0</span><br />  <span class="token punctuation">}</span><br />  <span class="token comment">//returns articles</span><br />  <span class="token keyword">let</span> response <span class="token operator">=</span> <span class="token keyword">await</span> pocket<span class="token punctuation">.</span><span class="token function">getArticles</span><span class="token punctuation">(</span>pocketConfigForGet<span class="token punctuation">)</span><br /><br />  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>response<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br /><span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
<p id="code-skip-day-6-getting-pocket-working-3">This gives me the results from the read API endpoint from Pocket.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/aramzsxyz/day-6-getting-pocket-working/#code-skip-day-6-getting-pocket-working-2" id="skip-to-code-skip-day-6-getting-pocket-working-2" class="skip-link">Skip code block ▼</a></p>
<pre class="language-js"><code class="language-js"><span class="token punctuation">{</span><br />  <span class="token literal-property property">maxActions</span><span class="token operator">:</span> <span class="token number">30</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">cachetype</span><span class="token operator">:</span> <span class="token string">'db'</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">status</span><span class="token operator">:</span> <span class="token number">1</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">error</span><span class="token operator">:</span> <span class="token keyword">null</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">complete</span><span class="token operator">:</span> <span class="token number">1</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">since</span><span class="token operator">:</span> <span class="token number">1732166480</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">list</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />    <span class="token string-property property">'4136799598'</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />      <span class="token literal-property property">item_id</span><span class="token operator">:</span> <span class="token string">'4136799598'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">favorite</span><span class="token operator">:</span> <span class="token string">'0'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">status</span><span class="token operator">:</span> <span class="token string">'1'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">time_added</span><span class="token operator">:</span> <span class="token string">'1732155928'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">time_updated</span><span class="token operator">:</span> <span class="token string">'1732178996'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">time_read</span><span class="token operator">:</span> <span class="token string">'1732178996'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">time_favorited</span><span class="token operator">:</span> <span class="token string">'0'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">sort_id</span><span class="token operator">:</span> <span class="token number">0</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">tags</span><span class="token operator">:</span> <span class="token punctuation">[</span>Object<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">top_image_url</span><span class="token operator">:</span> <span class="token string">'https://unwinnable.com/wp-content/uploads/2024/11/Springer.jpg'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">resolved_id</span><span class="token operator">:</span> <span class="token string">'4136799598'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">given_url</span><span class="token operator">:</span> <span class="token string">'https://unwinnable.com/2024/11/19/a-nightmare-on-valleyfield-drive/'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">given_title</span><span class="token operator">:</span> <span class="token string">'A Nightmare on Valleyfield Drive - Unwinnable | Unwinnable'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">resolved_title</span><span class="token operator">:</span> <span class="token string">'A Nightmare on Valleyfield Drive'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">resolved_url</span><span class="token operator">:</span> <span class="token string">'https://unwinnable.com/2024/11/19/a-nightmare-on-valleyfield-drive/'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">excerpt</span><span class="token operator">:</span> <span class="token string">'This column is a reprint from Unwinnable Monthly #180. If you like what you see, grab the magazine for less than ten dollars, or subscribe and get all future magazines for half price. Now this.'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">is_article</span><span class="token operator">:</span> <span class="token string">'1'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">is_index</span><span class="token operator">:</span> <span class="token string">'0'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">has_video</span><span class="token operator">:</span> <span class="token string">'0'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">has_image</span><span class="token operator">:</span> <span class="token string">'1'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">word_count</span><span class="token operator">:</span> <span class="token string">'1136'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">lang</span><span class="token operator">:</span> <span class="token string">'en'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">time_to_read</span><span class="token operator">:</span> <span class="token number">5</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">listen_duration_estimate</span><span class="token operator">:</span> <span class="token number">440</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">authors</span><span class="token operator">:</span> <span class="token punctuation">[</span>Object<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">domain_metadata</span><span class="token operator">:</span> <span class="token punctuation">[</span>Object<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">images</span><span class="token operator">:</span> <span class="token punctuation">[</span>Object<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">image</span><span class="token operator">:</span> <span class="token punctuation">[</span>Object<span class="token punctuation">]</span><br />    <span class="token punctuation">}</span><span class="token punctuation">,</span><br />    <span class="token string-property property">'4137300187'</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />      <span class="token literal-property property">item_id</span><span class="token operator">:</span> <span class="token string">'4137300187'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">favorite</span><span class="token operator">:</span> <span class="token string">'0'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">status</span><span class="token operator">:</span> <span class="token string">'0'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">time_added</span><span class="token operator">:</span> <span class="token string">'1732153566'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">time_updated</span><span class="token operator">:</span> <span class="token string">'1732153582'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">time_read</span><span class="token operator">:</span> <span class="token string">'0'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">time_favorited</span><span class="token operator">:</span> <span class="token string">'0'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">sort_id</span><span class="token operator">:</span> <span class="token number">2</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">tags</span><span class="token operator">:</span> <span class="token punctuation">[</span>Object<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">top_image_url</span><span class="token operator">:</span> <span class="token string">'https://static.politico.com/dims4/default/55a1666/2147483647/resize/1200/quality/100/?url=https://static.politico.com/1a/5c/71191d2044058aaf12b82f49e34e/trump-73479.jpg'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">resolved_id</span><span class="token operator">:</span> <span class="token string">'4137300187'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">given_url</span><span class="token operator">:</span> <span class="token string">'https://www.eenews.net/articles/trump-allies-want-to-resurrect-red-teams-to-question-climate-science/'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">given_title</span><span class="token operator">:</span> <span class="token string">'Trump allies want to resurrect ‘red teams’ to question climate science - E&amp;'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">resolved_title</span><span class="token operator">:</span> <span class="token string">'Trump allies want to resurrect ‘red teams’ to question climate science'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">resolved_url</span><span class="token operator">:</span> <span class="token string">'https://www.eenews.net/articles/trump-allies-want-to-resurrect-red-teams-to-question-climate-science/'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">excerpt</span><span class="token operator">:</span> <span class="token string">'The second Trump administration may take a page out of military strategy to challenge established climate science.'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">is_article</span><span class="token operator">:</span> <span class="token string">'1'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">is_index</span><span class="token operator">:</span> <span class="token string">'0'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">has_video</span><span class="token operator">:</span> <span class="token string">'0'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">has_image</span><span class="token operator">:</span> <span class="token string">'1'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">word_count</span><span class="token operator">:</span> <span class="token string">'922'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">lang</span><span class="token operator">:</span> <span class="token string">'en'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">time_to_read</span><span class="token operator">:</span> <span class="token number">4</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">listen_duration_estimate</span><span class="token operator">:</span> <span class="token number">357</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">authors</span><span class="token operator">:</span> <span class="token punctuation">[</span>Object<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">domain_metadata</span><span class="token operator">:</span> <span class="token punctuation">[</span>Object<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">images</span><span class="token operator">:</span> <span class="token punctuation">[</span>Object<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">image</span><span class="token operator">:</span> <span class="token punctuation">[</span>Object<span class="token punctuation">]</span><br />    <span class="token punctuation">}</span><span class="token punctuation">,</span><br />    <span class="token string-property property">'4137356790'</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />      <span class="token literal-property property">item_id</span><span class="token operator">:</span> <span class="token string">'4137356790'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">favorite</span><span class="token operator">:</span> <span class="token string">'0'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">status</span><span class="token operator">:</span> <span class="token string">'0'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">time_added</span><span class="token operator">:</span> <span class="token string">'1732154258'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">time_updated</span><span class="token operator">:</span> <span class="token string">'1732154263'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">time_read</span><span class="token operator">:</span> <span class="token string">'0'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">time_favorited</span><span class="token operator">:</span> <span class="token string">'0'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">sort_id</span><span class="token operator">:</span> <span class="token number">1</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">tags</span><span class="token operator">:</span> <span class="token punctuation">[</span>Object<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">top_image_url</span><span class="token operator">:</span> <span class="token string">'https://webapi.project-syndicate.org/library/3df3445c1d2626e11bbfe7756d7d1039.2-1-super.1.jpg'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">resolved_id</span><span class="token operator">:</span> <span class="token string">'4137356790'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">given_url</span><span class="token operator">:</span> <span class="token string">'https://www.project-syndicate.org/commentary/illusion-of-soil-carbon-offsets-by-sophie-scherger-2024-11'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">given_title</span><span class="token operator">:</span> <span class="token string">"Carbon Farming Won't Save the Planet by Sophie Scherger - Project Syndicate"</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">resolved_title</span><span class="token operator">:</span> <span class="token string">"Carbon Farming Won't Save the Planet"</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">resolved_url</span><span class="token operator">:</span> <span class="token string">'https://www.project-syndicate.org/commentary/illusion-of-soil-carbon-offsets-by-sophie-scherger-2024-11'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">excerpt</span><span class="token operator">:</span> <span class="token string">'At first glance, funding climate action through soil carbon credits instead of taxpayer dollars may seem like a win-win solution. But real-world evidence suggests that improving soil health and supporting farmers as they adapt to more sustainable practices would be far more effective.'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">is_article</span><span class="token operator">:</span> <span class="token string">'1'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">is_index</span><span class="token operator">:</span> <span class="token string">'0'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">has_video</span><span class="token operator">:</span> <span class="token string">'0'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">has_image</span><span class="token operator">:</span> <span class="token string">'1'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">word_count</span><span class="token operator">:</span> <span class="token string">'795'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">lang</span><span class="token operator">:</span> <span class="token string">'en'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">time_to_read</span><span class="token operator">:</span> <span class="token number">4</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">listen_duration_estimate</span><span class="token operator">:</span> <span class="token number">308</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">domain_metadata</span><span class="token operator">:</span> <span class="token punctuation">[</span>Object<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">images</span><span class="token operator">:</span> <span class="token punctuation">[</span>Object<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">image</span><span class="token operator">:</span> <span class="token punctuation">[</span>Object<span class="token punctuation">]</span><br />    <span class="token punctuation">}</span><span class="token punctuation">,</span><br />    <span class="token string-property property">'4137436970'</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />      <span class="token literal-property property">item_id</span><span class="token operator">:</span> <span class="token string">'4137436970'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">favorite</span><span class="token operator">:</span> <span class="token string">'0'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">status</span><span class="token operator">:</span> <span class="token string">'0'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">time_added</span><span class="token operator">:</span> <span class="token string">'1732153374'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">time_updated</span><span class="token operator">:</span> <span class="token string">'1732153395'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">time_read</span><span class="token operator">:</span> <span class="token string">'0'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">time_favorited</span><span class="token operator">:</span> <span class="token string">'0'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">sort_id</span><span class="token operator">:</span> <span class="token number">3</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">tags</span><span class="token operator">:</span> <span class="token punctuation">[</span>Object<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">top_image_url</span><span class="token operator">:</span> <span class="token string">'https://img-cdn.inc.com/image/upload/f_webp,q_auto,c_fit/vip/2024/11/80-hrs-lifestyle-inc_c2044e.jpg'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">resolved_id</span><span class="token operator">:</span> <span class="token string">'4137436970'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">given_url</span><span class="token operator">:</span> <span class="token string">'https://www.inc.com/sam-blum/this-22-year-old-tech-ceo-says-an-80-hour-work-week-is-a-lifestyle-choice-it-earned-him-death-threats-and-job-seekers/91022060'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">given_title</span><span class="token operator">:</span> <span class="token string">'This 22-Year-Old Tech CEO Says an 80-Hour Work Week Is a Lifestyle Choice. '</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">resolved_title</span><span class="token operator">:</span> <span class="token string">'This 22-Year-Old Tech CEO Says an 80-Hour Work Week Is a Lifestyle Choice. It Earned Him Death Threats. And Job Seekers.'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">resolved_url</span><span class="token operator">:</span> <span class="token string">'https://www.inc.com/sam-blum/this-22-year-old-tech-ceo-says-an-80-hour-work-week-is-a-lifestyle-choice-it-earned-him-death-threats-and-job-seekers/91022060'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">excerpt</span><span class="token operator">:</span> <span class="token string">'Daksh Gupta, the 22-year-old founder of Greptile, a San Francisco-based enterprise software company, posted on X earlier this month that his firm “offers no work-life-balance.” The typical day is a 14-hour slog, and employees often work weekends.'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">is_article</span><span class="token operator">:</span> <span class="token string">'1'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">is_index</span><span class="token operator">:</span> <span class="token string">'0'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">has_video</span><span class="token operator">:</span> <span class="token string">'0'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">has_image</span><span class="token operator">:</span> <span class="token string">'0'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">word_count</span><span class="token operator">:</span> <span class="token string">'702'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">lang</span><span class="token operator">:</span> <span class="token string">'en'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">time_to_read</span><span class="token operator">:</span> <span class="token number">3</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">listen_duration_estimate</span><span class="token operator">:</span> <span class="token number">272</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">authors</span><span class="token operator">:</span> <span class="token punctuation">[</span>Object<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">domain_metadata</span><span class="token operator">:</span> <span class="token punctuation">[</span>Object<span class="token punctuation">]</span><br />    <span class="token punctuation">}</span><br />  <span class="token punctuation">}</span><br /><span class="token punctuation">}</span></code></pre>
<p id="code-skip-day-6-getting-pocket-working-2">I want to fully expand the objects so I know what I'm working with. Let's use <code>util.inspect</code> here: <code>console.log(util.inspect(response, {showHidden: false, depth: null, colors: true}))</code></p>
<p>Got it!</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/aramzsxyz/day-6-getting-pocket-working/#code-skip-day-6-getting-pocket-working-1" id="skip-to-code-skip-day-6-getting-pocket-working-1" class="skip-link">Skip code block ▼</a></p>
<pre class="language-js"><code class="language-js"><span class="token punctuation">{</span><br />  <span class="token literal-property property">maxActions</span><span class="token operator">:</span> <span class="token number">30</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">cachetype</span><span class="token operator">:</span> <span class="token string">'db'</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">status</span><span class="token operator">:</span> <span class="token number">1</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">error</span><span class="token operator">:</span> <span class="token keyword">null</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">complete</span><span class="token operator">:</span> <span class="token number">1</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">since</span><span class="token operator">:</span> <span class="token number">1732167050</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">list</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />    <span class="token string-property property">'4136799598'</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />      <span class="token literal-property property">item_id</span><span class="token operator">:</span> <span class="token string">'4136799598'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">favorite</span><span class="token operator">:</span> <span class="token string">'0'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">status</span><span class="token operator">:</span> <span class="token string">'1'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">time_added</span><span class="token operator">:</span> <span class="token string">'1732155928'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">time_updated</span><span class="token operator">:</span> <span class="token string">'1732178996'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">time_read</span><span class="token operator">:</span> <span class="token string">'1732178996'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">time_favorited</span><span class="token operator">:</span> <span class="token string">'0'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">sort_id</span><span class="token operator">:</span> <span class="token number">0</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">tags</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">culture</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">tag</span><span class="token operator">:</span> <span class="token string">'culture'</span><span class="token punctuation">,</span> <span class="token literal-property property">item_id</span><span class="token operator">:</span> <span class="token string">'4136799598'</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">top_image_url</span><span class="token operator">:</span> <span class="token string">'https://unwinnable.com/wp-content/uploads/2024/11/Springer.jpg'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">resolved_id</span><span class="token operator">:</span> <span class="token string">'4136799598'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">given_url</span><span class="token operator">:</span> <span class="token string">'https://unwinnable.com/2024/11/19/a-nightmare-on-valleyfield-drive/'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">given_title</span><span class="token operator">:</span> <span class="token string">'A Nightmare on Valleyfield Drive - Unwinnable | Unwinnable'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">resolved_title</span><span class="token operator">:</span> <span class="token string">'A Nightmare on Valleyfield Drive'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">resolved_url</span><span class="token operator">:</span> <span class="token string">'https://unwinnable.com/2024/11/19/a-nightmare-on-valleyfield-drive/'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">excerpt</span><span class="token operator">:</span> <span class="token string">'This column is a reprint from Unwinnable Monthly #180. If you like what you see, grab the magazine for less than ten dollars, or subscribe and get all future magazines for half price. Now this.'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">is_article</span><span class="token operator">:</span> <span class="token string">'1'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">is_index</span><span class="token operator">:</span> <span class="token string">'0'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">has_video</span><span class="token operator">:</span> <span class="token string">'0'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">has_image</span><span class="token operator">:</span> <span class="token string">'1'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">word_count</span><span class="token operator">:</span> <span class="token string">'1136'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">lang</span><span class="token operator">:</span> <span class="token string">'en'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">time_to_read</span><span class="token operator">:</span> <span class="token number">5</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">listen_duration_estimate</span><span class="token operator">:</span> <span class="token number">440</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">authors</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />        <span class="token string-property property">'95063516'</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />          <span class="token literal-property property">author_id</span><span class="token operator">:</span> <span class="token string">'95063516'</span><span class="token punctuation">,</span><br />          <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'Noah Springer'</span><span class="token punctuation">,</span><br />          <span class="token literal-property property">url</span><span class="token operator">:</span> <span class="token string">'https://unwinnable.com/author/noah-springer/'</span><span class="token punctuation">,</span><br />          <span class="token literal-property property">item_id</span><span class="token operator">:</span> <span class="token string">'4136799598'</span><br />        <span class="token punctuation">}</span><br />      <span class="token punctuation">}</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">domain_metadata</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'unwinnable.com'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">images</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />        <span class="token string-property property">'1'</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />          <span class="token literal-property property">item_id</span><span class="token operator">:</span> <span class="token string">'4136799598'</span><span class="token punctuation">,</span><br />          <span class="token literal-property property">image_id</span><span class="token operator">:</span> <span class="token string">'1'</span><span class="token punctuation">,</span><br />          <span class="token literal-property property">src</span><span class="token operator">:</span> <span class="token string">'https://unwinnable.com/wp-content/uploads/2024/10/UM180.jpg'</span><span class="token punctuation">,</span><br />          <span class="token literal-property property">width</span><span class="token operator">:</span> <span class="token string">'314'</span><span class="token punctuation">,</span><br />          <span class="token literal-property property">height</span><span class="token operator">:</span> <span class="token string">'443'</span><span class="token punctuation">,</span><br />          <span class="token literal-property property">credit</span><span class="token operator">:</span> <span class="token string">''</span><span class="token punctuation">,</span><br />          <span class="token literal-property property">caption</span><span class="token operator">:</span> <span class="token string">''</span><br />        <span class="token punctuation">}</span><span class="token punctuation">,</span><br />        <span class="token string-property property">'2'</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />          <span class="token literal-property property">item_id</span><span class="token operator">:</span> <span class="token string">'4136799598'</span><span class="token punctuation">,</span><br />          <span class="token literal-property property">image_id</span><span class="token operator">:</span> <span class="token string">'2'</span><span class="token punctuation">,</span><br />          <span class="token literal-property property">src</span><span class="token operator">:</span> <span class="token string">'https://unwinnable.com/wp-content/uploads/2024/11/Springer-2-794x412.png'</span><span class="token punctuation">,</span><br />          <span class="token literal-property property">width</span><span class="token operator">:</span> <span class="token string">'794'</span><span class="token punctuation">,</span><br />          <span class="token literal-property property">height</span><span class="token operator">:</span> <span class="token string">'412'</span><span class="token punctuation">,</span><br />          <span class="token literal-property property">credit</span><span class="token operator">:</span> <span class="token string">''</span><span class="token punctuation">,</span><br />          <span class="token literal-property property">caption</span><span class="token operator">:</span> <span class="token string">''</span><br />        <span class="token punctuation">}</span><br />      <span class="token punctuation">}</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">image</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />        <span class="token literal-property property">item_id</span><span class="token operator">:</span> <span class="token string">'4136799598'</span><span class="token punctuation">,</span><br />        <span class="token literal-property property">src</span><span class="token operator">:</span> <span class="token string">'https://unwinnable.com/wp-content/uploads/2024/10/UM180.jpg'</span><span class="token punctuation">,</span><br />        <span class="token literal-property property">width</span><span class="token operator">:</span> <span class="token string">'314'</span><span class="token punctuation">,</span><br />        <span class="token literal-property property">height</span><span class="token operator">:</span> <span class="token string">'443'</span><br />      <span class="token punctuation">}</span><br />    <span class="token punctuation">}</span><span class="token punctuation">,</span><br />    <span class="token string-property property">'4137300187'</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />      <span class="token literal-property property">item_id</span><span class="token operator">:</span> <span class="token string">'4137300187'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">favorite</span><span class="token operator">:</span> <span class="token string">'0'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">status</span><span class="token operator">:</span> <span class="token string">'0'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">time_added</span><span class="token operator">:</span> <span class="token string">'1732153566'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">time_updated</span><span class="token operator">:</span> <span class="token string">'1732153582'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">time_read</span><span class="token operator">:</span> <span class="token string">'0'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">time_favorited</span><span class="token operator">:</span> <span class="token string">'0'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">sort_id</span><span class="token operator">:</span> <span class="token number">2</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">tags</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">climate</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">tag</span><span class="token operator">:</span> <span class="token string">'climate'</span><span class="token punctuation">,</span> <span class="token literal-property property">item_id</span><span class="token operator">:</span> <span class="token string">'4137300187'</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">top_image_url</span><span class="token operator">:</span> <span class="token string">'https://static.politico.com/dims4/default/55a1666/2147483647/resize/1200/quality/100/?url=https://static.politico.com/1a/5c/71191d2044058aaf12b82f49e34e/trump-73479.jpg'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">resolved_id</span><span class="token operator">:</span> <span class="token string">'4137300187'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">given_url</span><span class="token operator">:</span> <span class="token string">'https://www.eenews.net/articles/trump-allies-want-to-resurrect-red-teams-to-question-climate-science/'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">given_title</span><span class="token operator">:</span> <span class="token string">'Trump allies want to resurrect ‘red teams’ to question climate science - E&amp;'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">resolved_title</span><span class="token operator">:</span> <span class="token string">'Trump allies want to resurrect ‘red teams’ to question climate science'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">resolved_url</span><span class="token operator">:</span> <span class="token string">'https://www.eenews.net/articles/trump-allies-want-to-resurrect-red-teams-to-question-climate-science/'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">excerpt</span><span class="token operator">:</span> <span class="token string">'The second Trump administration may take a page out of military strategy to challenge established climate science.'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">is_article</span><span class="token operator">:</span> <span class="token string">'1'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">is_index</span><span class="token operator">:</span> <span class="token string">'0'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">has_video</span><span class="token operator">:</span> <span class="token string">'0'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">has_image</span><span class="token operator">:</span> <span class="token string">'1'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">word_count</span><span class="token operator">:</span> <span class="token string">'922'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">lang</span><span class="token operator">:</span> <span class="token string">'en'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">time_to_read</span><span class="token operator">:</span> <span class="token number">4</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">listen_duration_estimate</span><span class="token operator">:</span> <span class="token number">357</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">authors</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />        <span class="token string-property property">'1289487'</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />          <span class="token literal-property property">author_id</span><span class="token operator">:</span> <span class="token string">'1289487'</span><span class="token punctuation">,</span><br />          <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'SCOTT WALDMAN'</span><span class="token punctuation">,</span><br />          <span class="token literal-property property">url</span><span class="token operator">:</span> <span class="token string">''</span><span class="token punctuation">,</span><br />          <span class="token literal-property property">item_id</span><span class="token operator">:</span> <span class="token string">'4137300187'</span><br />        <span class="token punctuation">}</span><br />      <span class="token punctuation">}</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">domain_metadata</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'www.eenews.net'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">images</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />        <span class="token string-property property">'1'</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />          <span class="token literal-property property">item_id</span><span class="token operator">:</span> <span class="token string">'4137300187'</span><span class="token punctuation">,</span><br />          <span class="token literal-property property">image_id</span><span class="token operator">:</span> <span class="token string">'1'</span><span class="token punctuation">,</span><br />          <span class="token literal-property property">src</span><span class="token operator">:</span> <span class="token string">'https://static.politico.com/dims4/default/55a1666/2147483647/resize/600/quality/100/?url=https://static.politico.com/1a/5c/71191d2044058aaf12b82f49e34e/trump-73479.jpg'</span><span class="token punctuation">,</span><br />          <span class="token literal-property property">width</span><span class="token operator">:</span> <span class="token string">'0'</span><span class="token punctuation">,</span><br />          <span class="token literal-property property">height</span><span class="token operator">:</span> <span class="token string">'0'</span><span class="token punctuation">,</span><br />          <span class="token literal-property property">credit</span><span class="token operator">:</span> <span class="token string">''</span><span class="token punctuation">,</span><br />          <span class="token literal-property property">caption</span><span class="token operator">:</span> <span class="token string">'President-elect Donald Trump speaks during a meeting with the House Republican Conference in Washington on Nov. 13. Pool photo by Allison Robbert'</span><br />        <span class="token punctuation">}</span><br />      <span class="token punctuation">}</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">image</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />        <span class="token literal-property property">item_id</span><span class="token operator">:</span> <span class="token string">'4137300187'</span><span class="token punctuation">,</span><br />        <span class="token literal-property property">src</span><span class="token operator">:</span> <span class="token string">'https://static.politico.com/dims4/default/55a1666/2147483647/resize/600/quality/100/?url=https://static.politico.com/1a/5c/71191d2044058aaf12b82f49e34e/trump-73479.jpg'</span><span class="token punctuation">,</span><br />        <span class="token literal-property property">width</span><span class="token operator">:</span> <span class="token string">'0'</span><span class="token punctuation">,</span><br />        <span class="token literal-property property">height</span><span class="token operator">:</span> <span class="token string">'0'</span><br />      <span class="token punctuation">}</span><br />    <span class="token punctuation">}</span><span class="token punctuation">,</span><br />    <span class="token string-property property">'4137356790'</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />      <span class="token literal-property property">item_id</span><span class="token operator">:</span> <span class="token string">'4137356790'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">favorite</span><span class="token operator">:</span> <span class="token string">'0'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">status</span><span class="token operator">:</span> <span class="token string">'0'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">time_added</span><span class="token operator">:</span> <span class="token string">'1732154258'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">time_updated</span><span class="token operator">:</span> <span class="token string">'1732154263'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">time_read</span><span class="token operator">:</span> <span class="token string">'0'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">time_favorited</span><span class="token operator">:</span> <span class="token string">'0'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">sort_id</span><span class="token operator">:</span> <span class="token number">1</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">tags</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">climate</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">tag</span><span class="token operator">:</span> <span class="token string">'climate'</span><span class="token punctuation">,</span> <span class="token literal-property property">item_id</span><span class="token operator">:</span> <span class="token string">'4137356790'</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">top_image_url</span><span class="token operator">:</span> <span class="token string">'https://webapi.project-syndicate.org/library/3df3445c1d2626e11bbfe7756d7d1039.2-1-super.1.jpg'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">resolved_id</span><span class="token operator">:</span> <span class="token string">'4137356790'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">given_url</span><span class="token operator">:</span> <span class="token string">'https://www.project-syndicate.org/commentary/illusion-of-soil-carbon-offsets-by-sophie-scherger-2024-11'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">given_title</span><span class="token operator">:</span> <span class="token string">"Carbon Farming Won't Save the Planet by Sophie Scherger - Project Syndicate"</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">resolved_title</span><span class="token operator">:</span> <span class="token string">"Carbon Farming Won't Save the Planet"</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">resolved_url</span><span class="token operator">:</span> <span class="token string">'https://www.project-syndicate.org/commentary/illusion-of-soil-carbon-offsets-by-sophie-scherger-2024-11'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">excerpt</span><span class="token operator">:</span> <span class="token string">'At first glance, funding climate action through soil carbon credits instead of taxpayer dollars may seem like a win-win solution. But real-world evidence suggests that improving soil health and supporting farmers as they adapt to more sustainable practices would be far more effective.'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">is_article</span><span class="token operator">:</span> <span class="token string">'1'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">is_index</span><span class="token operator">:</span> <span class="token string">'0'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">has_video</span><span class="token operator">:</span> <span class="token string">'0'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">has_image</span><span class="token operator">:</span> <span class="token string">'1'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">word_count</span><span class="token operator">:</span> <span class="token string">'795'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">lang</span><span class="token operator">:</span> <span class="token string">'en'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">time_to_read</span><span class="token operator">:</span> <span class="token number">4</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">listen_duration_estimate</span><span class="token operator">:</span> <span class="token number">308</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">domain_metadata</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />        <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'Project Syndicate'</span><span class="token punctuation">,</span><br />        <span class="token literal-property property">logo</span><span class="token operator">:</span> <span class="token string">'https://logo.clearbit.com/project-syndicate.org?size=800'</span><br />      <span class="token punctuation">}</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">images</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />        <span class="token string-property property">'1'</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />          <span class="token literal-property property">item_id</span><span class="token operator">:</span> <span class="token string">'4137356790'</span><span class="token punctuation">,</span><br />          <span class="token literal-property property">image_id</span><span class="token operator">:</span> <span class="token string">'1'</span><span class="token punctuation">,</span><br />          <span class="token literal-property property">src</span><span class="token operator">:</span> <span class="token string">'https://webapi.project-syndicate.org/library/becdb3b63fbb8839238df869cc13153b.16-9-medium.1.jpg'</span><span class="token punctuation">,</span><br />          <span class="token literal-property property">width</span><span class="token operator">:</span> <span class="token string">'480'</span><span class="token punctuation">,</span><br />          <span class="token literal-property property">height</span><span class="token operator">:</span> <span class="token string">'270'</span><span class="token punctuation">,</span><br />          <span class="token literal-property property">credit</span><span class="token operator">:</span> <span class="token string">''</span><span class="token punctuation">,</span><br />          <span class="token literal-property property">caption</span><span class="token operator">:</span> <span class="token string">''</span><br />        <span class="token punctuation">}</span><span class="token punctuation">,</span><br />        <span class="token string-property property">'2'</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />          <span class="token literal-property property">item_id</span><span class="token operator">:</span> <span class="token string">'4137356790'</span><span class="token punctuation">,</span><br />          <span class="token literal-property property">image_id</span><span class="token operator">:</span> <span class="token string">'2'</span><span class="token punctuation">,</span><br />          <span class="token literal-property property">src</span><span class="token operator">:</span> <span class="token string">'https://webapi.project-syndicate.org/library/0afd4a7f1b2009d4f8b8754a84559f53.16-9-medium.1.jpg'</span><span class="token punctuation">,</span><br />          <span class="token literal-property property">width</span><span class="token operator">:</span> <span class="token string">'480'</span><span class="token punctuation">,</span><br />          <span class="token literal-property property">height</span><span class="token operator">:</span> <span class="token string">'270'</span><span class="token punctuation">,</span><br />          <span class="token literal-property property">credit</span><span class="token operator">:</span> <span class="token string">''</span><span class="token punctuation">,</span><br />          <span class="token literal-property property">caption</span><span class="token operator">:</span> <span class="token string">''</span><br />        <span class="token punctuation">}</span><span class="token punctuation">,</span><br />        <span class="token string-property property">'3'</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />          <span class="token literal-property property">item_id</span><span class="token operator">:</span> <span class="token string">'4137356790'</span><span class="token punctuation">,</span><br />          <span class="token literal-property property">image_id</span><span class="token operator">:</span> <span class="token string">'3'</span><span class="token punctuation">,</span><br />          <span class="token literal-property property">src</span><span class="token operator">:</span> <span class="token string">'https://webapi.project-syndicate.org/library/5e3b73dbaa2e26d472a8786e4bcf9407.16-9-medium.1.jpg'</span><span class="token punctuation">,</span><br />          <span class="token literal-property property">width</span><span class="token operator">:</span> <span class="token string">'480'</span><span class="token punctuation">,</span><br />          <span class="token literal-property property">height</span><span class="token operator">:</span> <span class="token string">'270'</span><span class="token punctuation">,</span><br />          <span class="token literal-property property">credit</span><span class="token operator">:</span> <span class="token string">''</span><span class="token punctuation">,</span><br />          <span class="token literal-property property">caption</span><span class="token operator">:</span> <span class="token string">''</span><br />        <span class="token punctuation">}</span><span class="token punctuation">,</span><br />        <span class="token string-property property">'4'</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />          <span class="token literal-property property">item_id</span><span class="token operator">:</span> <span class="token string">'4137356790'</span><span class="token punctuation">,</span><br />          <span class="token literal-property property">image_id</span><span class="token operator">:</span> <span class="token string">'4'</span><span class="token punctuation">,</span><br />          <span class="token literal-property property">src</span><span class="token operator">:</span> <span class="token string">'https://webapi.project-syndicate.org/library/5150820f497697cf28b3c6ee415a4618.16-9-medium.1.jpg'</span><span class="token punctuation">,</span><br />          <span class="token literal-property property">width</span><span class="token operator">:</span> <span class="token string">'480'</span><span class="token punctuation">,</span><br />          <span class="token literal-property property">height</span><span class="token operator">:</span> <span class="token string">'270'</span><span class="token punctuation">,</span><br />          <span class="token literal-property property">credit</span><span class="token operator">:</span> <span class="token string">''</span><span class="token punctuation">,</span><br />          <span class="token literal-property property">caption</span><span class="token operator">:</span> <span class="token string">''</span><br />        <span class="token punctuation">}</span><br />      <span class="token punctuation">}</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">image</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />        <span class="token literal-property property">item_id</span><span class="token operator">:</span> <span class="token string">'4137356790'</span><span class="token punctuation">,</span><br />        <span class="token literal-property property">src</span><span class="token operator">:</span> <span class="token string">'https://webapi.project-syndicate.org/library/becdb3b63fbb8839238df869cc13153b.16-9-medium.1.jpg'</span><span class="token punctuation">,</span><br />        <span class="token literal-property property">width</span><span class="token operator">:</span> <span class="token string">'480'</span><span class="token punctuation">,</span><br />        <span class="token literal-property property">height</span><span class="token operator">:</span> <span class="token string">'270'</span><br />      <span class="token punctuation">}</span><br />    <span class="token punctuation">}</span><span class="token punctuation">,</span><br />    <span class="token string-property property">'4137436970'</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />      <span class="token literal-property property">item_id</span><span class="token operator">:</span> <span class="token string">'4137436970'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">favorite</span><span class="token operator">:</span> <span class="token string">'0'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">status</span><span class="token operator">:</span> <span class="token string">'0'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">time_added</span><span class="token operator">:</span> <span class="token string">'1732153374'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">time_updated</span><span class="token operator">:</span> <span class="token string">'1732153395'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">time_read</span><span class="token operator">:</span> <span class="token string">'0'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">time_favorited</span><span class="token operator">:</span> <span class="token string">'0'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">sort_id</span><span class="token operator">:</span> <span class="token number">3</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">tags</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />        <span class="token literal-property property">labor</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">tag</span><span class="token operator">:</span> <span class="token string">'labor'</span><span class="token punctuation">,</span> <span class="token literal-property property">item_id</span><span class="token operator">:</span> <span class="token string">'4137436970'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span><br />        <span class="token literal-property property">tech</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">tag</span><span class="token operator">:</span> <span class="token string">'tech'</span><span class="token punctuation">,</span> <span class="token literal-property property">item_id</span><span class="token operator">:</span> <span class="token string">'4137436970'</span> <span class="token punctuation">}</span><br />      <span class="token punctuation">}</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">top_image_url</span><span class="token operator">:</span> <span class="token string">'https://img-cdn.inc.com/image/upload/f_webp,q_auto,c_fit/vip/2024/11/80-hrs-lifestyle-inc_c2044e.jpg'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">resolved_id</span><span class="token operator">:</span> <span class="token string">'4137436970'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">given_url</span><span class="token operator">:</span> <span class="token string">'https://www.inc.com/sam-blum/this-22-year-old-tech-ceo-says-an-80-hour-work-week-is-a-lifestyle-choice-it-earned-him-death-threats-and-job-seekers/91022060'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">given_title</span><span class="token operator">:</span> <span class="token string">'This 22-Year-Old Tech CEO Says an 80-Hour Work Week Is a Lifestyle Choice. '</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">resolved_title</span><span class="token operator">:</span> <span class="token string">'This 22-Year-Old Tech CEO Says an 80-Hour Work Week Is a Lifestyle Choice. It Earned Him Death Threats. And Job Seekers.'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">resolved_url</span><span class="token operator">:</span> <span class="token string">'https://www.inc.com/sam-blum/this-22-year-old-tech-ceo-says-an-80-hour-work-week-is-a-lifestyle-choice-it-earned-him-death-threats-and-job-seekers/91022060'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">excerpt</span><span class="token operator">:</span> <span class="token string">'Daksh Gupta, the 22-year-old founder of Greptile, a San Francisco-based enterprise software company, posted on X earlier this month that his firm “offers no work-life-balance.” The typical day is a 14-hour slog, and employees often work weekends.'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">is_article</span><span class="token operator">:</span> <span class="token string">'1'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">is_index</span><span class="token operator">:</span> <span class="token string">'0'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">has_video</span><span class="token operator">:</span> <span class="token string">'0'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">has_image</span><span class="token operator">:</span> <span class="token string">'0'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">word_count</span><span class="token operator">:</span> <span class="token string">'702'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">lang</span><span class="token operator">:</span> <span class="token string">'en'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">time_to_read</span><span class="token operator">:</span> <span class="token number">3</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">listen_duration_estimate</span><span class="token operator">:</span> <span class="token number">272</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">authors</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />        <span class="token string-property property">'182809703'</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />          <span class="token literal-property property">author_id</span><span class="token operator">:</span> <span class="token string">'182809703'</span><span class="token punctuation">,</span><br />          <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'Sam Blum'</span><span class="token punctuation">,</span><br />          <span class="token literal-property property">url</span><span class="token operator">:</span> <span class="token string">'https://www.inc.com/author/sam-blum'</span><span class="token punctuation">,</span><br />          <span class="token literal-property property">item_id</span><span class="token operator">:</span> <span class="token string">'4137436970'</span><br />        <span class="token punctuation">}</span><br />      <span class="token punctuation">}</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">domain_metadata</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />        <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'Inc. Magazine'</span><span class="token punctuation">,</span><br />        <span class="token literal-property property">logo</span><span class="token operator">:</span> <span class="token string">'https://logo.clearbit.com/inc.com?size=800'</span><br />      <span class="token punctuation">}</span><br />    <span class="token punctuation">}</span><br />  <span class="token punctuation">}</span><br /><span class="token punctuation">}</span></code></pre>
<p id="code-skip-day-6-getting-pocket-working-1">Ok, so now I need to figure out a way to walk through as much of the Pocket API output as possible, avoid re-writing files I've already written, and transform these objects into the flat files I want to output.</p>
]]></content:encoded>
	</item>
	
	<item>
		<title>XYZ Site - Day 5 - Rebuilding my quotes flat file generator</title>
		<link>https://fightwithtools.dev/posts/projects/aramzsxyz/day-5-rebuilding-quote-processing-async/?source=rss</link>
		<pubDate>Fri, 08 Nov 2024 21:59:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/projects/aramzsxyz/day-5-rebuilding-quote-processing-async/</guid>
		<description>Previously I had exported a nice simple JSON file I could turn into files, but that site broke, so trying Readwise instead</description>
		<content:encoded><![CDATA[<h2 id="project-scope-and-todos" tabindex="-1">Project Scope and ToDos</h2>
<ol>
<li>Create a versatile blog site</li>
<li>Create a framework that makes it easy to add external data to the site</li>
</ol>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Give the site the capacity to replicate the logging and rating I do on Serialized and Letterboxd.</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Be able to pull down RSS feeds from other sites and create forward links to my other sites</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Create forward links to sites I want to post about.</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Create a way to pull in my Goodreads data and display it on the site</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Create a way to automate pulls from other data sources</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Combine easy inputs like text lists and JSON data files with markdown files that I can build on top of.</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Add a TMDB credit to footer in base.njk</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Make sure tags do not repeat in the displayed tag list.</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Get my Kindle Quotes into the site</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> YouTube Channel Recommendations</li>
</ul>
<h2 id="day-5" tabindex="-1">Day 5</h2>
<p>So previously I had a simple JSON file I could pull from <a href="http://clippings.io/" target="_blank">Clippings.Io</a> and just walk each object and turn it into a flat file. It was such a negligible transform I didn't even think much about it. Now that service appears to have broken, so I'm looking at a new service called Readwise. Let's see if it works.</p>
<p>I played around with some more specific CSV to JSON libraries, but they really didn't work so I'm going with <code>csv</code> and <code>csv-parse</code> to keep it as simple as possible. Now I'll have to write more of my own code, but obviously I don't have any problem with that. First let's try to make sure everything works as intended:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/aramzsxyz/day-5-rebuilding-quote-processing-async/#code-skip-day-5-rebuilding-quote-processing-async-7" id="skip-to-code-skip-day-5-rebuilding-quote-processing-async-7" class="skip-link">Skip code block ▼</a></p>
<pre class="language-js"><code class="language-js"><span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">readCSVFromFolder</span><span class="token punctuation">(</span><span class="token parameter">folderPath</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />  <span class="token comment">//let parse = csvParse.parse({delimiter: ":"});</span><br />  <span class="token keyword">const</span> records <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span><br />  <span class="token keyword">let</span> counter <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span><br />  <span class="token keyword">let</span> headers <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span><br />  <span class="token keyword">const</span> parser <span class="token operator">=</span> fs<br />  <span class="token punctuation">.</span><span class="token function">createReadStream</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">./to-process/readwise-data.csv</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><br />  <span class="token punctuation">.</span><span class="token function">pipe</span><span class="token punctuation">(</span>csvParse<span class="token punctuation">.</span><span class="token function">parse</span><span class="token punctuation">(</span><span class="token punctuation">{</span><br />    <span class="token literal-property property">trim</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span><br />  <span class="token comment">// CSV options if any</span><br />  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />  <span class="token keyword">for</span> <span class="token keyword">await</span> <span class="token punctuation">(</span><span class="token keyword">const</span> record <span class="token keyword">of</span> parser<span class="token punctuation">)</span> <span class="token punctuation">{</span><br />    <span class="token keyword">if</span> <span class="token punctuation">(</span>counter <span class="token operator">===</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />      <span class="token comment">// Skip the first row</span><br />      counter<span class="token operator">++</span><span class="token punctuation">;</span><br />      headers <span class="token operator">=</span> record<span class="token punctuation">;</span><br />      <span class="token keyword">continue</span><span class="token punctuation">;</span><br />    <span class="token punctuation">}</span><br />    counter<span class="token operator">++</span><span class="token punctuation">;</span><br />    <span class="token comment">// Work with each record</span><br />    <span class="token keyword">let</span> jsonRecord <span class="token operator">=</span> record<span class="token punctuation">.</span><span class="token function">reduce</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">acc<span class="token punctuation">,</span> value<span class="token punctuation">,</span> index</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />      acc<span class="token punctuation">[</span>headers<span class="token punctuation">[</span>index<span class="token punctuation">]</span><span class="token punctuation">]</span> <span class="token operator">=</span> value<span class="token punctuation">;</span><br />      <span class="token keyword">return</span> acc<span class="token punctuation">;</span><br />    <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />    records<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span>record<span class="token punctuation">)</span><span class="token punctuation">;</span><br />    console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>jsonRecord<span class="token punctuation">)</span><span class="token punctuation">;</span><br />  <span class="token punctuation">}</span><br />  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>records<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span></code></pre>
<p id="code-skip-day-5-rebuilding-quote-processing-async-7">This is mostly <a href="https://csv.js.org/parse/examples/async_iterator/#async-iterator" target="_blank">straight out of the documentation</a>. I've never used an async iterator like this before, but it does make things a lot easier.</p>
<p>It's a simple library, so it is just taking each CSV item and turning it into an entry in an array. Each entry is itself an array. But I want JSON objects. So I took the first entry of the array (where the table headers are) and wrote it out to an array. Now I can use that array to pull from for my object keys.</p>
<p>Very straightforward here. And it works! Here's the first object on my list:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/aramzsxyz/day-5-rebuilding-quote-processing-async/#code-skip-day-5-rebuilding-quote-processing-async-6" id="skip-to-code-skip-day-5-rebuilding-quote-processing-async-6" class="skip-link">Skip code block ▼</a></p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span><br />  Highlight<span class="token operator">:</span> 'Words can be like X-rays<span class="token punctuation">,</span> if you use them properly—they’ll go through anything. You read and you’re pierced.'<span class="token punctuation">,</span><br />  'Book Title'<span class="token operator">:</span> 'Brave New World'<span class="token punctuation">,</span><br />  'Book Author'<span class="token operator">:</span> 'Aldous Huxley'<span class="token punctuation">,</span><br />  'Amazon Book ID'<span class="token operator">:</span> 'B000FA5R5S'<span class="token punctuation">,</span><br />  Note<span class="token operator">:</span> ''<span class="token punctuation">,</span><br />  Color<span class="token operator">:</span> 'yellow'<span class="token punctuation">,</span><br />  Tags<span class="token operator">:</span> ''<span class="token punctuation">,</span><br />  'Location Type'<span class="token operator">:</span> 'location'<span class="token punctuation">,</span><br />  Location<span class="token operator">:</span> '<span class="token number">911</span>'<span class="token punctuation">,</span><br />  'Highlighted at'<span class="token operator">:</span> '<span class="token number">2011</span><span class="token number">-01</span><span class="token number">-30</span> <span class="token number">04</span><span class="token operator">:</span><span class="token number">56</span><span class="token operator">:</span><span class="token number">00</span>+<span class="token number">00</span><span class="token operator">:</span><span class="token number">00</span>'<span class="token punctuation">,</span><br />  'Document tags'<span class="token operator">:</span> ''<br /><span class="token punctuation">}</span></code></pre>
<p id="code-skip-day-5-rebuilding-quote-processing-async-6">These aren't the best JSON object keys, but it is a good start.</p>
<p>I'm not deep in fancy typescript or anything here so I have to map these out to the object I built from the old format, using a class-style function:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/aramzsxyz/day-5-rebuilding-quote-processing-async/#code-skip-day-5-rebuilding-quote-processing-async-5" id="skip-to-code-skip-day-5-rebuilding-quote-processing-async-5" class="skip-link">Skip code block ▼</a></p>
<pre class="language-js"><code class="language-js"><span class="token keyword">function</span> <span class="token function">Quote</span><span class="token punctuation">(</span><span class="token parameter">quoteObj</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />	<span class="token keyword">this</span><span class="token punctuation">.</span>sourceTitle <span class="token operator">=</span> <span class="token string">""</span><span class="token punctuation">;</span><br />	<span class="token keyword">this</span><span class="token punctuation">.</span>cite <span class="token operator">=</span> <span class="token punctuation">{</span><br />		<span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">""</span><span class="token punctuation">,</span><br />		<span class="token literal-property property">href</span><span class="token operator">:</span> <span class="token string">""</span><span class="token punctuation">,</span><br />	<span class="token punctuation">}</span><span class="token punctuation">;</span> <span class="token comment">// author</span><br />	<span class="token keyword">this</span><span class="token punctuation">.</span>blockquote <span class="token operator">=</span> <span class="token string">""</span><span class="token punctuation">;</span><br />	<span class="token keyword">this</span><span class="token punctuation">.</span>createdDate <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toISOString</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token keyword">this</span><span class="token punctuation">.</span>publishDate <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toISOString</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token keyword">this</span><span class="token punctuation">.</span>location <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span><br />	<span class="token keyword">this</span><span class="token punctuation">.</span>type <span class="token operator">=</span> <span class="token string">"quote"</span><span class="token punctuation">;</span><br />	<span class="token keyword">this</span><span class="token punctuation">.</span>handedFrom <span class="token operator">=</span> <span class="token string">"Kindle"</span><span class="token punctuation">;</span><br />	<span class="token keyword">this</span><span class="token punctuation">.</span>referringUri <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">;</span><br />	<span class="token keyword">this</span><span class="token punctuation">.</span>notes <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span><br />	<span class="token keyword">this</span><span class="token punctuation">.</span>publish <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">;</span><br />	<span class="token keyword">this</span><span class="token punctuation">.</span>slug <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">;</span><br />	<span class="token keyword">this</span><span class="token punctuation">.</span>tags <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token string">"Quote"</span><span class="token punctuation">]</span><span class="token punctuation">;</span><br />	Object<span class="token punctuation">.</span><span class="token function">assign</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">,</span> quoteObj<span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token keyword">var</span> quoteHasContent <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">;</span><br />	<span class="token keyword">if</span> <span class="token punctuation">(</span><br />		quoteObj<span class="token punctuation">.</span><span class="token function">hasOwnProperty</span><span class="token punctuation">(</span><span class="token string">"blockquote"</span><span class="token punctuation">)</span> <span class="token operator">&amp;&amp;</span><br />		quoteObj<span class="token punctuation">.</span>blockquote<span class="token punctuation">.</span>length <span class="token operator">></span> <span class="token number">3</span><br />	<span class="token punctuation">)</span> <span class="token punctuation">{</span><br />		quoteHasContent <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">;</span><br />	<span class="token punctuation">}</span><br />	<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>quoteHasContent<span class="token punctuation">)</span> <span class="token punctuation">{</span><br />		<span class="token keyword">this</span><span class="token punctuation">.</span>publish <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">;</span><br />	<span class="token punctuation">}</span><br />  <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">hasOwnProperty</span><span class="token punctuation">(</span><span class="token string">"page"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">{</span><br />    <span class="token keyword">this</span><span class="token punctuation">.</span>pageNum <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>page<span class="token punctuation">;</span><br />    <span class="token keyword">delete</span> <span class="token keyword">this</span><span class="token punctuation">.</span>page<span class="token punctuation">;</span><br />  <span class="token punctuation">}</span><br /><span class="token punctuation">}</span></code></pre>
<p id="code-skip-day-5-rebuilding-quote-processing-async-5">There are a few extra fields here because my quotes section isn't <em>only</em> for Kindle quotes, it's for everyone! But that structure, if I keep to it, will mean that I have to do very little change at the file writing stage.</p>
<p>There is a major change I will have to do. Previously my parse and write process was very blunt. It was fine for running locally but now that I've got a Readstream I can operate on the CSV with more efficiency. It will be more performant to, instead of parse the file, get the objects, right the objects; parse the individual objects, and write them to the flat files I use for my site at that time, during the processing of the Readstream.</p>
<p>That's fine. LFG!!!</p>
<p>Let's do the transform to the new format:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/aramzsxyz/day-5-rebuilding-quote-processing-async/#code-skip-day-5-rebuilding-quote-processing-async-4" id="skip-to-code-skip-day-5-rebuilding-quote-processing-async-4" class="skip-link">Skip code block ▼</a></p>
<pre class="language-js"><code class="language-js"><span class="token keyword">function</span> <span class="token function">readwiseReformatQuote</span><span class="token punctuation">(</span><span class="token parameter">clipping</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />	<span class="token comment">// console.log("Clipping", clipping);</span><br />	<span class="token keyword">var</span> quoteObj <span class="token operator">=</span> <span class="token punctuation">{</span><br />		<span class="token literal-property property">sourceTitle</span><span class="token operator">:</span> clipping<span class="token punctuation">[</span><span class="token string">"Book Title"</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br />		<span class="token literal-property property">cite</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />      <span class="token literal-property property">name</span><span class="token operator">:</span> clipping<span class="token punctuation">[</span><span class="token string">"Book Author"</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">href</span><span class="token operator">:</span> <span class="token boolean">false</span><br />    <span class="token punctuation">}</span><span class="token punctuation">,</span><br />		<span class="token literal-property property">blockquote</span><span class="token operator">:</span> clipping<span class="token punctuation">.</span>Highlight<span class="token punctuation">,</span><br />		<span class="token literal-property property">location</span><span class="token operator">:</span> clipping<span class="token punctuation">[</span><span class="token string">'Location Type'</span><span class="token punctuation">]</span> <span class="token operator">===</span> <span class="token string">"location"</span> <span class="token operator">?</span> clipping<span class="token punctuation">.</span>Location <span class="token operator">:</span> <span class="token keyword">null</span><span class="token punctuation">,</span><br />		<span class="token literal-property property">page</span><span class="token operator">:</span> <span class="token keyword">null</span><span class="token punctuation">,</span><br />		<span class="token literal-property property">createdDate</span><span class="token operator">:</span> clipping<span class="token punctuation">[</span><span class="token string">"Highlighted at"</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">date</span><span class="token operator">:</span> <span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span>clipping<span class="token punctuation">[</span><span class="token string">"Highlighted at"</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toISOString</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br />		<span class="token literal-property property">publishDate</span><span class="token operator">:</span> <span class="token keyword">null</span><span class="token punctuation">,</span><br />		<span class="token literal-property property">annotationType</span><span class="token operator">:</span> <span class="token string">"Highlight"</span><span class="token punctuation">,</span><br />		<span class="token literal-property property">notes</span><span class="token operator">:</span> clipping<span class="token punctuation">.</span>Note <span class="token operator">?</span> <span class="token punctuation">[</span>clipping<span class="token punctuation">.</span>Note<span class="token punctuation">]</span> <span class="token operator">:</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br />		<span class="token literal-property property">publish</span><span class="token operator">:</span> clipping<span class="token punctuation">.</span>publish <span class="token operator">?</span> clipping<span class="token punctuation">.</span>publish <span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">tags</span><span class="token operator">:</span> clipping<span class="token punctuation">[</span><span class="token string">"Document tags"</span><span class="token punctuation">]</span> <span class="token operator">?</span> clipping<span class="token punctuation">[</span><span class="token string">"Document tags"</span><span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">split</span><span class="token punctuation">(</span><span class="token string">','</span><span class="token punctuation">)</span> <span class="token operator">:</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br />	<span class="token punctuation">}</span><span class="token punctuation">;</span><br />	console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">"Readwise transformed"</span><span class="token punctuation">,</span> clipping<span class="token punctuation">,</span> quoteObj<span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token keyword">return</span> quoteObj<span class="token punctuation">;</span><br /><span class="token punctuation">}</span></code></pre>
<p id="code-skip-day-5-rebuilding-quote-processing-async-4">Here is the function for writing the file:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/aramzsxyz/day-5-rebuilding-quote-processing-async/#code-skip-day-5-rebuilding-quote-processing-async-3" id="skip-to-code-skip-day-5-rebuilding-quote-processing-async-3" class="skip-link">Skip code block ▼</a></p>
<pre class="language-js"><code class="language-js"><span class="token keyword">function</span> <span class="token function">quoteObjectWriter</span><span class="token punctuation">(</span><span class="token parameter">quoteObj</span><span class="token punctuation">)</span><span class="token punctuation">{</span><br />  <span class="token keyword">let</span> sourcePath <span class="token operator">=</span> <span class="token string">''</span><span class="token punctuation">;</span><br />  <span class="token keyword">if</span> <span class="token punctuation">(</span>quoteObj<span class="token punctuation">.</span>sourceSlug <span class="token operator">&amp;&amp;</span> quoteObj<span class="token punctuation">.</span>sourceSlug<span class="token punctuation">.</span>length <span class="token operator">></span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />    sourcePath <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">/</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>quoteObj<span class="token punctuation">.</span>sourceSlug<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span><br />  <span class="token punctuation">}</span><br />  <span class="token keyword">return</span> <span class="token function">processObjectToMarkdown</span><span class="token punctuation">(</span><br />    <span class="token string">"title"</span><span class="token punctuation">,</span><br />    <span class="token string">"content"</span><span class="token punctuation">,</span><br />    <span class="token string">"./src/content/resources/quotes"</span><span class="token operator">+</span>sourcePath<span class="token punctuation">,</span><br />    quoteObj<span class="token punctuation">,</span><br />    <span class="token boolean">true</span><br />  <span class="token punctuation">)</span><br /><span class="token punctuation">}</span></code></pre>
<p id="code-skip-day-5-rebuilding-quote-processing-async-3">Ok, first test showed some interesting issues. It looks like it pulled in quotes that I exported from Pocket as well, which I forgot was something I added to Readwise. This is cool! I want some way to differentiate the two for further development though!</p>
<p>Here is what a Pocket-sourced Readwise JSON looks like:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/aramzsxyz/day-5-rebuilding-quote-processing-async/#code-skip-day-5-rebuilding-quote-processing-async-2" id="skip-to-code-skip-day-5-rebuilding-quote-processing-async-2" class="skip-link">Skip code block ▼</a></p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span><br />  Highlight<span class="token operator">:</span> 'A longstanding 1800s ban on wearing masks during protests in New York State<span class="token punctuation">,</span> originally introduced to discourage tenant demonstrations<span class="token punctuation">,</span> was repealed in <span class="token number">2020</span> when the world began wearing masks to stop the spread of COVID<span class="token number">-19</span>.'<span class="token punctuation">,</span><br />  'Book Title'<span class="token operator">:</span> 'At-Risk Hell’s Kitchen Resident Hits Out at Proposed Mask Ban'<span class="token punctuation">,</span><br />  'Book Author'<span class="token operator">:</span> 'Dashiell Allen'<span class="token punctuation">,</span><br />  'Amazon Book ID'<span class="token operator">:</span> ''<span class="token punctuation">,</span><br />  Note<span class="token operator">:</span> ''<span class="token punctuation">,</span><br />  Color<span class="token operator">:</span> ''<span class="token punctuation">,</span><br />  Tags<span class="token operator">:</span> ''<span class="token punctuation">,</span><br />  'Location Type'<span class="token operator">:</span> ''<span class="token punctuation">,</span><br />  Location<span class="token operator">:</span> '<span class="token number">0</span>'<span class="token punctuation">,</span><br />  'Highlighted at'<span class="token operator">:</span> '<span class="token number">2024</span><span class="token number">-08</span><span class="token number">-03</span> <span class="token number">14</span><span class="token operator">:</span><span class="token number">27</span><span class="token operator">:</span><span class="token number">41</span>+<span class="token number">00</span><span class="token operator">:</span><span class="token number">00</span>'<span class="token punctuation">,</span><br />  'Document tags'<span class="token operator">:</span> 'nyc<span class="token punctuation">,</span>politics'<br /><span class="token punctuation">}</span></code></pre>
<p id="code-skip-day-5-rebuilding-quote-processing-async-2">And here is what the file that comes out of that looks like right now:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/aramzsxyz/day-5-rebuilding-quote-processing-async/#code-skip-day-5-rebuilding-quote-processing-async-1" id="skip-to-code-skip-day-5-rebuilding-quote-processing-async-1" class="skip-link">Skip code block ▼</a></p>
<pre class="language-md"><code class="language-md"><span class="token frontmatter"><span class="token punctuation">---</span><br /><span class="token key atrule">annotationType</span><span class="token punctuation">:</span> Highlight<br /><span class="token key atrule">blockquote</span><span class="token punctuation">:</span> <span class="token punctuation">></span><span class="token punctuation">-</span><br />  A longstanding 1800s ban on wearing masks during protests in New York State<span class="token punctuation">,</span><br />  originally introduced to discourage tenant demonstrations<span class="token punctuation">,</span> was repealed in<br />  2020 when the world began wearing masks to stop the spread of COVID<span class="token punctuation">-</span><span class="token number">19.</span><br /><span class="token key atrule">cite</span><span class="token punctuation">:</span><br />  <span class="token key atrule">name</span><span class="token punctuation">:</span> Dashiell Allen<br />  <span class="token key atrule">href</span><span class="token punctuation">:</span> <span class="token boolean important">false</span><br /><span class="token key atrule">createdDate</span><span class="token punctuation">:</span> <span class="token string">'2024-08-03 14:27:41+00:00'</span><br /><span class="token key atrule">date</span><span class="token punctuation">:</span> <span class="token string">'2024-08-03T14:27:41.000Z'</span><br /><span class="token key atrule">handedFrom</span><span class="token punctuation">:</span> Kindle<br /><span class="token key atrule">id</span><span class="token punctuation">:</span> 041a7d8c6bd019882888796524cc94ed<br /><span class="token key atrule">location</span><span class="token punctuation">:</span> <span class="token null important">null</span><br /><span class="token key atrule">notes</span><span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><br /><span class="token key atrule">pageNum</span><span class="token punctuation">:</span> <span class="token null important">null</span><br /><span class="token key atrule">publish</span><span class="token punctuation">:</span> <span class="token boolean important">true</span><br /><span class="token key atrule">publishDate</span><span class="token punctuation">:</span> <span class="token null important">null</span><br /><span class="token key atrule">referringUri</span><span class="token punctuation">:</span> <span class="token boolean important">false</span><br /><span class="token key atrule">slug</span><span class="token punctuation">:</span> a<span class="token punctuation">-</span>longstanding<span class="token punctuation">-</span>1800s<span class="token punctuation">-</span>ban<span class="token punctuation">-</span>on<span class="token punctuation">-</span>041a7<br /><span class="token key atrule">sourceSlug</span><span class="token punctuation">:</span> at<span class="token punctuation">-</span>risk<span class="token punctuation">-</span>hells<span class="token punctuation">-</span>kitchen<span class="token punctuation">-</span>resident<span class="token punctuation">-</span>hits<span class="token punctuation">-</span>out<span class="token punctuation">-</span>at<span class="token punctuation">-</span>proposed<span class="token punctuation">-</span>mask<span class="token punctuation">-</span>ban<br /><span class="token key atrule">sourceTitle</span><span class="token punctuation">:</span> At<span class="token punctuation">-</span>Risk Hell’s Kitchen Resident Hits Out at Proposed Mask Ban<br /><span class="token key atrule">tags</span><span class="token punctuation">:</span><br />  <span class="token punctuation">-</span> nyc<br />  <span class="token punctuation">-</span> politics<br /><span class="token key atrule">title</span><span class="token punctuation">:</span> <span class="token punctuation">></span><span class="token punctuation">-</span><br />  A longstanding 1800s ban on wearing masks during protests in<span class="token punctuation">...</span> <span class="token punctuation">-</span> At<span class="token punctuation">-</span>Risk<br />  Hell’s Kitchen Resident Hits Out at Proposed Mask Ban<br /><span class="token key atrule">type</span><span class="token punctuation">:</span> quote<br /><span class="token punctuation">---</span></span><br /><br />> A longstanding 1800s ban on wearing masks during protests in New York State, originally introduced to discourage tenant demonstrations, was repealed in 2020 when the world began wearing masks to stop the spread of COVID-19.</code></pre>
<p id="code-skip-day-5-rebuilding-quote-processing-async-1">I think I can check and if <code>Location Type</code> and <code>Amazon Book ID</code> doesn't exist then I can assume that the quote is from Pocket. Cool!</p>
<p>For whatever reason Readwise doesn't do the following:</p>
<ul>
<li>Include book subtitles</li>
<li>Include page numbers</li>
<li>Use special characters like smartquotes in titles.</li>
</ul>
<p>The first two sort of suck, the 3rd is great. The downside to not including the book subtitles or special characters in titles that were there before is that it means some quotes are recreated in new folders because my parser understands the names to be different. I'm ok with that. I'll delete the old folders.</p>
<p>Let's clean up and recreate with the new rules.</p>
<p><code>git clean -fdn</code> yeah, that looks right.</p>
<p><code>git clean -fd</code></p>
<p>Ok, let's go again!</p>
<p><code>npm run make:quotes</code></p>
<p>Ooops. I forgot that setting a property to <code>null</code> will still set it to override an object when I merge them. Let's comment out <code>publishDate</code> which is intended to show when I published the quote on my site.</p>
<p><code>git clean -fd</code></p>
<p>Once more:</p>
<p><code>npm run make:quotes</code></p>
<p>Ok, that looks good, let's try serving it locally!</p>
<p>Cleaning up some of the repeated folders and wow...</p>
<p>It is very weird to me that apparently they just change some of the book titles some times. You'd think that would be a stable identifier for a book published before the internet existed.</p>
<p>Apparently Amazon has re-categorized The Algebraist as being part of Iain M Banks' Culture series? Even though Wikipedia says it is not part of that series? And this has apparently forced the series number to change. Apparently the listing of the Kindle book was altered to make it part of the Culture series as part of a reprinting issued a few months ago. <a href="https://en.wikipedia.org/wiki/Talk:The_Algebraist#c-Psychobabble-2006-09-01T22:32:00.000Z-Not_a_Culture_novel?" target="_blank">Some wikipedians are gonna get real mad</a>.</p>
<p>Why do some Diskworld books not have numbers as part of the subtitle now? Odd. And some of the Discworld novels they <em>added</em> numbers to! WTF.</p>
<p>Ok, serves great locally. Looks good.</p>
<p>Let's try connecting a few more import sources to Readwise, running a new export and see what we get.</p>
<p>Annoying that Readwise does nothing to tell me what particular import source a quote comes from. I'm just going to categorize everything that is an article as coming from Pocket for now. It's a bit of a cheat, but it looks like they don't differentiate internally in their own system so <em>shrugz</em>.</p>
<p>Better than nothing and hey, I got quote imports working again! Looks like this is a good stopping point.</p>
]]></content:encoded>
	</item>
	
	<item>
		<title>Using Python to fix my broken Spotify account by cleaning out Liked Songs</title>
		<link>https://fightwithtools.dev/posts/writing/fixing-spotify-slowdowns-with-python/?source=rss</link>
		<pubDate>Thu, 30 May 2024 20:30:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/writing/fixing-spotify-slowdowns-with-python/</guid>
		<description>Grabbed some open source code and made a few modifications that let me use Spotipy to archive my Liked Songs into another playlist.</description>
		<content:encoded><![CDATA[<p>So a few years back, I noticed that my Spotify mobile app (Android) seemed to really be struggling. I am a pretty heavy Spotify user and I listen to a lot of different music so even slight slowdowns really annoy me. I went back and forth with Spotify Support a bit but the whole thing was some weird mystery.</p>
<h2 id="the-first-time" tabindex="-1">The first time</h2>
<p>I tried app settings, I tried reinstalling, I tried all sorts of stuff and, to Spotify's credit, they were really helpful. But none of it worked.</p>
<p>Then I wondered: could it be the <em>amount</em> of music I've liked? I don't know how Spotify uses the liked/saved songs, but presumably they have something to do with how it decides to recommend things to me. I imagine that, especially with the Smart Shuffle feature, if I was going to have quick, easy recommendations for users--even when they were offline--the Liked Songs list might come in handy, I might want to preload it, or query it occasionally, or in some other way process that list.</p>
<p>Now, I don't know if that's what was happening on my app, but I do know one thing: the minute I dropped a few thousand songs off my Liked List, dropping it below six thousand, the app started speeding up. All the connection problems, slow loading, and inability to access other Spotify-enabled devices? Gone like magic. (And no, it isn't because I had my Liked Songs list downloaded and it was taking up too much memory, I don't download that list.)</p>
<p>Whatever the reason, clearly the size of the Liked Songs list has some impact on the performance of the Android app. So I kept cleaning it up by making a copy of the list into a named playlist and deleting a bunch of songs off the Liked list.</p>
<h2 id="the-second-time" tabindex="-1">The second time</h2>
<p>Then I forgot to do it for a while. Then something changed in the Spotify app. I could no longer make a copy of my Liked list easily, I couldn't select large swaths of it and copy them and I couldn't Ctrl-A select all and copy that to a different playlist. It seemed that with my Liked Songs list over 10,000 tracks it was just beyond Spotify's ability to handle playlist operations.</p>
<p>The app was slowed down again, and I couldn't do the needed cleanup without permanently losing the record of songs I had liked!</p>
<h2 id="open-source-salvation" tabindex="-1">Open source salvation</h2>
<p>In comes <a href="https://herbort.me/" target="_blank">Alberto Redondo</a>.</p>
<p>I was searching for ways to use the Spotify API to solve this problem, which I suspected was related to the way the UI lazy-loads track items. I couldn't find much help in the forums, but <a href="https://github.com/albertored11/spotipy-scripts" target="_blank">I did find Alberto's <code>spotipy-scripts</code> repository</a>, thanks to its well put-together README, which wrapped the Python Spotify API tool <a href="https://spotipy.readthedocs.io/en/2.24.0/" target="_blank">Spotipy</a> with a few useful utility scripts.</p>
<p>I got it working in my terminally misconfigured local Python environment and pulled new env variables in for a new Spotify app. Then I was able to use their scripts easily and, after a bit of digging around I found out that Spotipy did support accessing the Liked Songs list.</p>
<p>There were a few trip-ups:</p>
<ul>
<li>I needed to request an additional role</li>
<li>Playlists normally allow you to query 100 items, but the Liked Songs list seems to limit you to 50.</li>
<li>Spotipy has a unique function of <code>current_user_saved_tracks</code> for accessing Liked Songs mirroring Spotify's unique API endpoint for that list.</li>
<li>I did end up hitting an API limit hand having to back off for a little bit.</li>
</ul>
<p>But after I had that all figured out, I was able to create a new playlist in Spotify and copy all the Liked Songs into that playlist!</p>
<p>After that I was able to remove a few thousand tracks from my Liked Songs list and as soon as I did my app was working nicely again.</p>
<h2 id="contributing-my-work-back-to-the-project" tabindex="-1">Contributing my work back to the project</h2>
<p>I put my function up on <a href="https://github.com/AramZS/spotipy-scripts/tree/archive-saved" target="_blank">a branch</a> in my own GitHub (along with documentation) as <a href="https://github.com/AramZS/spotipy-scripts" target="_blank">a forked repo</a> and <a href="https://github.com/albertored11/spotipy-scripts/pull/2" target="_blank">opened a PR against Alberto's repository</a>. Hopefully they'll find it useful and accept it. In any case, I have a tool now to solve this in the future.</p>
<h2 id="see-it-for-yourself" tabindex="-1">See it for yourself</h2>
<p>You can see how <a href="https://github.com/albertored11/spotipy-scripts/pull/2/files" target="_blank">it works in the PR's code</a>. You can <a href="https://github.com/AramZS/spotipy-scripts/tree/archive-saved" target="_blank">pull my version from my fork</a>.</p>
<p>After I exported the environment variables as specified in the README, all I had to do was run: <code>python3 scripts/copy_saved_to_playlist.py playlist-id-goes-here</code>. It took a few minutes to run, but it was able to work with no issues!</p>
<h2 id="spotify-how-does-it-work" tabindex="-1">Spotify, how does it work?</h2>
<p>I don't know how the Liked Songs list works, or why this fixes my app, but I have my suspicions. Judging by the impact on speed and how it only happens when I open the app, I think that it is likely that the Spotify app does some sort of check or operation on the Liked Songs list when it starts up or regains focus. If so, then yeah, slimming that list down would have a big impact.</p>
<p>Previously, <a href="https://aramzs.github.io/fun/2020/11/09/spotify-asks-listeners-to-hack-its-algorithm.html?ab=123213" target="_blank">I explored how to get the most out of Spotify's recommendations</a>.</p>
]]></content:encoded>
	</item>
	
	<item>
		<title>XYZ Site - Day 4 - Parsing Letterboxd data exports</title>
		<link>https://fightwithtools.dev/posts/projects/aramzsxyz/day-4-getting-films-working/?source=rss</link>
		<pubDate>Sun, 12 May 2024 14:59:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/projects/aramzsxyz/day-4-getting-films-working/</guid>
		<description>I like collecting color combinations for future projects but I want to make sure they are a11y AAA contrasts for accessible readability.</description>
		<content:encoded><![CDATA[<h2 id="project-scope-and-todos" tabindex="-1">Project Scope and ToDos</h2>
<ol>
<li>Create a versatile blog site</li>
<li>Create a framework that makes it easy to add external data to the site</li>
</ol>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Give the site the capacity to replicate the logging and rating I do on Serialized and Letterboxd.</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Be able to pull down RSS feeds from other sites and create forward links to my other sites</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Create forward links to sites I want to post about.</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Create a way to pull in my Goodreads data and display it on the site</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Create a way to automate pulls from other data sources</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Combine easy inputs like text lists and JSON data files with markdown files that I can build on top of.</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Add a TMDB credit to footer in base.njk</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Make sure tags do not repeat in the displayed tag list.</li>
</ul>
<h2 id="day-4" tabindex="-1">Day 4</h2>
<p>One of the things I wanted to accomplish here is have this site host my reviews and ratings from Letterboxd. I've pulled a data export from them and it has given me a bunch of CSVs.</p>
<p>I pulled in the <code>reviews.csv</code> file without any issues. A film I reviewed and rated will show up in multiple CSVs however. So I need to import them in an order where the most information comes first. Reviews first, then <code>ratings.csv</code> and then, if I want to pull them in, <code>watched.csv</code> which may include some films that I didn't review or rate but still watched.</p>
<p>However, this appears to have crashed the build process. I rolled it back. I've made some changes and run an import again and it seems to be working. Last time I did <code>watched</code> first, but that won't work. I'll start with <code>ratings</code>.</p>
<p>An important note is that I need to have Markdown files include <em>some</em> content, even if it is an empty string. Otherwise, the build process will crash. Doing that fixes the mysterious <code>Cannot read properties of undefined (reading 'includes') (via TypeError)</code> error I was getting during the Eleventy build process.</p>
<p>Hmmm, it doesn't seem like that has worked. There must be an error in another file.</p>
<p>I'll adjust my glob ignore for local development until I identify the file.</p>
<p>Looks like there is something in the 'b's. Let's go deeper:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/aramzsxyz/day-4-getting-films-working/#code-skip-day-4-getting-films-working-2" id="skip-to-code-skip-day-4-getting-films-working-2" class="skip-link">Skip code block ▼</a></p>
<pre class="language-js"><code class="language-js">  <span class="token comment">// Dev Time Build Ignores</span><br />  <span class="token keyword">if</span> <span class="token punctuation">(</span>process<span class="token punctuation">.</span>env<span class="token punctuation">.</span><span class="token constant">IS_LOCAL</span> <span class="token operator">===</span> <span class="token string">"true"</span><span class="token punctuation">)</span><span class="token punctuation">{</span><br />    eleventyConfig<span class="token punctuation">.</span>ignores<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span><span class="token string">"src/content/amplify/2023**"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />    eleventyConfig<span class="token punctuation">.</span>ignores<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span><span class="token string">"src/content/amplify/2024-01**"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />    eleventyConfig<span class="token punctuation">.</span>ignores<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span><span class="token string">"src/content/amplify/2024-02**"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />    eleventyConfig<span class="token punctuation">.</span>ignores<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span><span class="token string">"src/content/amplify/2024-03**"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />    eleventyConfig<span class="token punctuation">.</span>ignores<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span><span class="token string">"src/content/resources/film/[c-z]**"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />    eleventyConfig<span class="token punctuation">.</span>ignores<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span><span class="token string">"src/content/resources/film/b[j-z]**"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />    eleventyConfig<span class="token punctuation">.</span>ignores<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span><span class="token string">"src/content/resources/film/t**"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />  <span class="token punctuation">}</span></code></pre>
<p id="code-skip-day-4-getting-films-working-2">Ok, let's go forward to bp. That works. We'll have to move forward again!</p>
<p>Oh, there's a TV show in here that the TMDB API doesn't like. As a result it doesn't have any of the usual metadata, especially tags. That seems to have been what caused the problem.</p>
<p>Looks like there are a few of those I can find by searching for</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/aramzsxyz/day-4-getting-films-working/#code-skip-day-4-getting-films-working-1" id="skip-to-code-skip-day-4-getting-films-working-1" class="skip-link">Skip code block ▼</a></p>
<pre><code>rating: false
title:
</code></pre>
<p id="code-skip-day-4-getting-films-working-1">I think I can just add tags to fix this as well? Yeah, that does seem to work. I'll also add something in the film-making script to avoid this problem.</p>
<p><a target="_blank" href="https://github.com/AramZS/aramzs.xyz/commit/db1541df0f72c11e5969627800506051f2736ec8" class="git-commit-link"><code>git commit -am &quot;bugfix: Don't write film files with no tags&quot;</code></a></p>
<p>Looks like it is building now!</p>
<p>But hmmm, it looks like the date sort isn't working for the <code>film-and-tv</code> page.</p>
<p>Ah, I didn't pick the <code>data</code> object to get the key for sorting from. I can fix that.</p>
<p><a target="_blank" href="https://github.com/AramZS/aramzs.xyz/commit/d5e0d09a277f579dd1a40d64aa5e875f07ca4e10" class="git-commit-link"><code>git commit -am &quot;End the movies data file and use md files only.&quot;</code></a></p>
]]></content:encoded>
	</item>
	
	<item>
		<title>XYZ Site - Day 3 - Getting a npm module client side to measure contrasts</title>
		<link>https://fightwithtools.dev/posts/projects/aramzsxyz/day-3-building-and-measuring-color-contrasts/?source=rss</link>
		<pubDate>Sat, 06 Apr 2024 14:59:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/projects/aramzsxyz/day-3-building-and-measuring-color-contrasts/</guid>
		<description>I like collecting color combinations for future projects but I want to make sure they are a11y AAA contrasts for accessible readability.</description>
		<content:encoded><![CDATA[<h2 id="project-scope-and-todos" tabindex="-1">Project Scope and ToDos</h2>
<ol>
<li>Create a versatile blog site</li>
<li>Create a framework that makes it easy to add external data to the site</li>
</ol>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Give the site the capacity to replicate the logging and rating I do on Serialized and Letterboxd.</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Be able to pull down RSS feeds from other sites and create forward links to my other sites</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Create forward links to sites I want to post about.</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Create a way to pull in my Goodreads data and display it on the site</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Create a way to automate pulls from other data sources</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Combine easy inputs like text lists and JSON data files with markdown files that I can build on top of.</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Add a TMDB credit to footer in base.njk</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Make sure tags do not repeat in the displayed tag list.</li>
</ul>
<h2 id="day-3" tabindex="-1">Day 3</h2>
<p>I frequently will bookmark or reblog particularly interesting images that I think will provide a good mix of colors I could use in a different project. I'm not much of a designer, so this is a good way to bootstrap a website into looking good. It's how I decided on the <a href="https://songobsessed.com/" target="_blank">Song Obsessed</a> color scheme for instance.</p>
<p>I want to put a page in this site that includes that and I want to be able to compare the colors' contrasts in order to make sure they are accessible. I found a <a href="https://www.npmjs.com/package/get-contrast" target="_blank">npm module called <code>get-contrast</code></a> that will do this for me. But I want to use it based on clicks on the contrast page, which means making it work client side.</p>
<p>I'll take a look at rollup, but it seems to complex for this. In theory eslint should do the trick, and it has a nice convenient API I can leverage in a JS file to run it as part of 11ty's build process. It isn't working though and eslint's documentation is--as always--a painful read. It's been a long time since I last used Browserify, so let's try that.</p>
<p>Ok, this looks promising! I think I need to import it into the JS file I want to build like so:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/aramzsxyz/day-3-building-and-measuring-color-contrasts/#code-skip-day-3-building-and-measuring-color-contrasts-3" id="skip-to-code-skip-day-3-building-and-measuring-color-contrasts-3" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> contrast <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'get-contrast'</span><span class="token punctuation">)</span><br /><br />window<span class="token punctuation">.</span>contrast <span class="token operator">=</span> contrast<span class="token punctuation">;</span></code></pre>
<p id="code-skip-day-3-building-and-measuring-color-contrasts-3">I can either set it to the <code>window</code> object like this or set up my code in that file I think. To get the result running client side, it looks like I need to place it as a module like so:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/aramzsxyz/day-3-building-and-measuring-color-contrasts/#code-skip-day-3-building-and-measuring-color-contrasts-2" id="skip-to-code-skip-day-3-building-and-measuring-color-contrasts-2" class="skip-link">Skip code block ▼</a></p>
<pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>script</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>module<span class="token punctuation">"</span></span> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>/scripts/contrast-ratio.js<span class="token punctuation">"</span></span> <span class="token attr-name">async</span><span class="token punctuation">></span></span><span class="token script"></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>script</span><span class="token punctuation">></span></span></code></pre>
<p data-wordfix="true" id="code-skip-day-3-building-and-measuring-color-contrasts-2">It seems to work! Now to make it build with Eleventy. I don't see docs on a javascript API for Browserify. I'll take my command line script and use <code>exec</code> from Node to run it in <code>eleventy.before</code>.</p>
<p>Looks good in theory, but isn't working on the actual built site.</p>
<p data-wordfix="true">It appears like there is a race condition where Eleventy is copying over the script before Browserify finishes building it. I need to make it wait and exec doesn't have a built-in promise. I can use <code>util.promisify</code> <a href="https://stackoverflow.com/questions/30763496/how-to-promisify-nodes-child-process-exec-and-child-process-execfile-functions" target="_blank">from node to make it work I think</a>.</p>
<p>And yes, now it does!</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/aramzsxyz/day-3-building-and-measuring-color-contrasts/#code-skip-day-3-building-and-measuring-color-contrasts-1" id="skip-to-code-skip-day-3-building-and-measuring-color-contrasts-1" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript">eleventyConfig<span class="token punctuation">.</span><span class="token function">on</span><span class="token punctuation">(</span><br />		<span class="token string">"eleventy.before"</span><span class="token punctuation">,</span><br />		<span class="token keyword">async</span> <span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> dir<span class="token punctuation">,</span> runMode<span class="token punctuation">,</span> outputMode <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />			<span class="token comment">// Run me before the build starts</span><br />			console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">"Before Build"</span><span class="token punctuation">,</span> dir<span class="token punctuation">,</span> runMode<span class="token punctuation">,</span> outputMode<span class="token punctuation">)</span><span class="token punctuation">;</span><br />      <span class="token keyword">const</span> util <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'util'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />      <span class="token keyword">const</span> exec <span class="token operator">=</span> util<span class="token punctuation">.</span><span class="token function">promisify</span><span class="token punctuation">(</span><span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'node:child_process'</span><span class="token punctuation">)</span><span class="token punctuation">.</span>exec<span class="token punctuation">)</span><span class="token punctuation">;</span><br />      <span class="token keyword">await</span> <span class="token function">exec</span><span class="token punctuation">(</span><span class="token string">'npx browserify ./public/scripts/contrast-calc.js > ./public/scripts/contrast-ratio.js'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p id="code-skip-day-3-building-and-measuring-color-contrasts-1"><a target="_blank" href="https://github.com/AramZS/aramzs.xyz/commit/66ed8d77ecbee40e30c6f1ac0fc873b0324e6eb7" class="git-commit-link"><code>git commit -am &quot;Get a contrast checker npm module client side&quot;</code></a></p>
<p>Not the cleanest solution, but it works. Now let's see if I can get my functionality for interacting with the colors working.</p>
<p>I really want to compare two colors of any type, but that's a little much for now. I think I'll just click a foreground color and compare it to the background color. This seems good.</p>
<p>How do I want to grab the results? I think I can fix a div to the top of the page and output it there. That works well, though I'll need to mod some pixels widths and background colors to make the text persistently displayable and make the whole thing work on mobile.</p>
<p>I can select IDs and use those to easy swap in values where needed for now.</p>
<p><a target="_blank" href="https://github.com/AramZS/aramzs.xyz/commit/ff688e9bb9069cbb9426deaaf1da2721919a99dd" class="git-commit-link"><code>git commit -am &quot;Contrast interactives working&quot;</code></a></p>
]]></content:encoded>
	</item>
	
	<item>
		<title>XYZ Site - Day 2 - Site exports to markdown blogposts</title>
		<link>https://fightwithtools.dev/posts/projects/aramzsxyz/day-2-parsing-data-sources/?source=rss</link>
		<pubDate>Mon, 18 Mar 2024 02:59:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/projects/aramzsxyz/day-2-parsing-data-sources/</guid>
		<description>Getting my various content about books exported and into this site.</description>
		<content:encoded><![CDATA[<h2 id="project-scope-and-todos" tabindex="-1">Project Scope and ToDos</h2>
<ol>
<li>Create a versatile blog site</li>
<li>Create a framework that makes it easy to add external data to the site</li>
</ol>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Give the site the capacity to replicate the logging and rating I do on Serialized and Letterboxd.</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Be able to pull down RSS feeds from other sites and create forward links to my other sites</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Create forward links to sites I want to post about.</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Create a way to pull in my Goodreads data and display it on the site</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Create a way to automate pulls from other data sources</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Combine easy inputs like text lists and JSON data files with markdown files that I can build on top of.</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Add a TMDB credit to footer in base.njk</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Make sure tags do not repeat in the displayed tag list.</li>
</ul>
<h2 id="day-2" tabindex="-1">Day 2</h2>
<p>I've decided that I really want to make this site a repository of my site export data. I'll start with manual exports first. I've pulled my data from JustWatch on TV shows, I got an export from Letterboxd and now I'm working through my previously treated data from a Goodreads export. I'll likely end on my <a href="https://support.mozilla.org/en-US/kb/exporting-your-pocket-list" target="_blank">Pocket</a> data for dealing with exports. The next step will be moving over content automatically as I update the other sites. But that's for another day.</p>
<p>As I was exploring the options for an up to date dump of my GoodReads data, I found that they killed their API making this whole process a little more difficult to the future. I also realized that, although my Kindle book highlights and quotes are visible in Goodreads, they aren't in the export and I can't find any official way to export them. So I found a site called <a href="https://clippings.io/" target="_blank">Clippings.io</a> that can get the quotes and deliver them to me in a JSON file. I had to pay a monthly fee to get the big features on the site, but it was pretty reasonable so I don't mind. I should try and remember to turn it off in the future.</p>
<p>For each of these exports I've been processing I've tried to set up a standalone package.json script, and once they're working I can incorporate them into the build process (if I want). I've set one up to test quotes import and see how it works. It pulls from the data file, which itself pulls from a sources JSON I set up when I was thinking of writing these all to a JSON file, but I've decided to write them to Markdown instead, like all the rest of these. I just like the idea of individual pages being mapped to individual files and long JSON files that have no limit just seem like a recipe for disaster.</p>
<p><a target="_blank" href="https://github.com/AramZS/aramzs.xyz/commit/5df4fb7048913797221dd2bdc5cdbfcc7cf57844" class="git-commit-link"><code>git commit -am &quot;Adding media template and setting up for quotes&quot;</code></a></p>
<p>The resulting file will give me a lot more data than I need at this moment, but I don't mind. But it is a lot of disorganized files. I wonder if I should folder them by book, or organize the file names by date to make it a little more parsable. Considering how I dip in and out of books I don't think organizing by date is the right way. I can slug from the <code>sourceTitle</code> and use that to add to the file path I'm sending into <code>processObjectToMarkdown</code>.</p>
<p>I'll have to figure out how to make source specific pages later.</p>
<p>Hmmm, I'm seeing a rather unhelpful error:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/aramzsxyz/day-2-parsing-data-sources/#code-skip-day-2-parsing-data-sources-3" id="skip-to-code-skip-day-2-parsing-data-sources-3" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript"><span class="token punctuation">[</span>11ty<span class="token punctuation">]</span> Problem writing Eleventy templates<span class="token operator">:</span> <span class="token punctuation">(</span>more <span class="token keyword">in</span> <span class="token constant">DEBUG</span> output<span class="token punctuation">)</span><br /><span class="token punctuation">[</span>11ty<span class="token punctuation">]</span> Cannot use <span class="token string">'in'</span> operator to search <span class="token keyword">for</span> <span class="token string">'date'</span> <span class="token keyword">in</span> <span class="token number">43</span> <span class="token punctuation">(</span>via TypeError<span class="token punctuation">)</span><br /><span class="token punctuation">[</span>11ty<span class="token punctuation">]</span><br /><span class="token punctuation">[</span>11ty<span class="token punctuation">]</span> Original error stack trace<span class="token operator">:</span> TypeError<span class="token operator">:</span> Cannot use <span class="token string">'in'</span> operator to search <span class="token keyword">for</span> <span class="token string">'date'</span> <span class="token keyword">in</span> <span class="token number">43</span><br /><span class="token punctuation">[</span>11ty<span class="token punctuation">]</span>     at Template<span class="token punctuation">.</span><span class="token function">addPageDate</span> <span class="token punctuation">(</span><span class="token operator">...</span><span class="token operator">/</span>node_modules<span class="token operator">/</span>@11ty<span class="token operator">/</span>eleventy<span class="token operator">/</span>src<span class="token operator">/</span>Template<span class="token punctuation">.</span>js<span class="token operator">:</span><span class="token number">405</span><span class="token operator">:</span><span class="token number">34</span><span class="token punctuation">)</span><br /><span class="token punctuation">[</span>11ty<span class="token punctuation">]</span>     at <span class="token keyword">async</span> Template<span class="token punctuation">.</span><span class="token function">getData</span> <span class="token punctuation">(</span><span class="token operator">...</span><span class="token operator">/</span>node_modules<span class="token operator">/</span>@11ty<span class="token operator">/</span>eleventy<span class="token operator">/</span>src<span class="token operator">/</span>Template<span class="token punctuation">.</span>js<span class="token operator">:</span><span class="token number">390</span><span class="token operator">:</span><span class="token number">18</span><span class="token punctuation">)</span><br /><span class="token punctuation">[</span>11ty<span class="token punctuation">]</span>     at <span class="token keyword">async</span> TemplateMap<span class="token punctuation">.</span><span class="token function">add</span> <span class="token punctuation">(</span><span class="token operator">...</span><span class="token operator">/</span>node_modules<span class="token operator">/</span>@11ty<span class="token operator">/</span>eleventy<span class="token operator">/</span>src<span class="token operator">/</span>TemplateMap<span class="token punctuation">.</span>js<span class="token operator">:</span><span class="token number">65</span><span class="token operator">:</span><span class="token number">16</span><span class="token punctuation">)</span><br /><span class="token punctuation">[</span>11ty<span class="token punctuation">]</span>     at <span class="token keyword">async</span> Promise<span class="token punctuation">.</span><span class="token function">all</span> <span class="token punctuation">(</span>index <span class="token number">381</span><span class="token punctuation">)</span><br /><span class="token punctuation">[</span>11ty<span class="token punctuation">]</span>     at <span class="token keyword">async</span> TemplateWriter<span class="token punctuation">.</span><span class="token function">_createTemplateMap</span> <span class="token punctuation">(</span><span class="token operator">...</span><span class="token operator">/</span>node_modules<span class="token operator">/</span>@11ty<span class="token operator">/</span>eleventy<span class="token operator">/</span>src<span class="token operator">/</span>TemplateWriter<span class="token punctuation">.</span>js<span class="token operator">:</span><span class="token number">325</span><span class="token operator">:</span><span class="token number">5</span><span class="token punctuation">)</span><br /><span class="token punctuation">[</span>11ty<span class="token punctuation">]</span>     at <span class="token keyword">async</span> TemplateWriter<span class="token punctuation">.</span><span class="token function">generateTemplates</span> <span class="token punctuation">(</span><span class="token operator">...</span><span class="token operator">/</span>node_modules<span class="token operator">/</span>@11ty<span class="token operator">/</span>eleventy<span class="token operator">/</span>src<span class="token operator">/</span>TemplateWriter<span class="token punctuation">.</span>js<span class="token operator">:</span><span class="token number">360</span><span class="token operator">:</span><span class="token number">5</span><span class="token punctuation">)</span><br /><span class="token punctuation">[</span>11ty<span class="token punctuation">]</span>     at <span class="token keyword">async</span> TemplateWriter<span class="token punctuation">.</span><span class="token function">write</span> <span class="token punctuation">(</span><span class="token operator">...</span><span class="token operator">/</span>node_modules<span class="token operator">/</span>@11ty<span class="token operator">/</span>eleventy<span class="token operator">/</span>src<span class="token operator">/</span>TemplateWriter<span class="token punctuation">.</span>js<span class="token operator">:</span><span class="token number">407</span><span class="token operator">:</span><span class="token number">23</span><span class="token punctuation">)</span><br /><span class="token punctuation">[</span>11ty<span class="token punctuation">]</span>     at <span class="token keyword">async</span> Eleventy<span class="token punctuation">.</span><span class="token function">executeBuild</span> <span class="token punctuation">(</span><span class="token operator">...</span><span class="token operator">/</span>node_modules<span class="token operator">/</span>@11ty<span class="token operator">/</span>eleventy<span class="token operator">/</span>src<span class="token operator">/</span>Eleventy<span class="token punctuation">.</span>js<span class="token operator">:</span><span class="token number">1191</span><span class="token operator">:</span><span class="token number">13</span><span class="token punctuation">)</span><br /><span class="token punctuation">[</span>11ty<span class="token punctuation">]</span>     at <span class="token keyword">async</span> Eleventy<span class="token punctuation">.</span><span class="token function">watch</span> <span class="token punctuation">(</span><span class="token operator">...</span><span class="token operator">/</span>node_modules<span class="token operator">/</span>@11ty<span class="token operator">/</span>eleventy<span class="token operator">/</span>src<span class="token operator">/</span>Eleventy<span class="token punctuation">.</span>js<span class="token operator">:</span><span class="token number">1014</span><span class="token operator">:</span><span class="token number">18</span><span class="token punctuation">)</span></code></pre>
<p id="code-skip-day-2-parsing-data-sources-3">Seems like it is a template rendering problem. I've added some data properties to help me debug this sort of thing so I can more easily see the possible templates having a problem:</p>
<ul>
<li><code>src/_includes/layouts/page.njk</code></li>
<li><code>src/resources/types.njk</code></li>
<li><code>src/_includes/layouts/page-resource.njk</code></li>
</ul>
<p>Of those three, the only concern is on page-resource.njk. I'll start there. This code appears to be the problem, as it assumes a date value, and there should be one on all of these.</p>
<p>(remove backslashes)</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/aramzsxyz/day-2-parsing-data-sources/#code-skip-day-2-parsing-data-sources-2" id="skip-to-code-skip-day-2-parsing-data-sources-2" class="skip-link">Skip code block ▼</a></p>
<pre class="language-liquid"><code class="language-liquid">{\% set subTitle %\}<br />    posted on <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>time</span> <span class="token attr-name">datetime</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>{\{ page.date.toISOString() }\}<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>{\{ page.date | dateToFormat("DDD") }\}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>time</span><span class="token punctuation">></span></span> in: {\% include "../components/tag-list.njk" %\}.<br />{\% endset %\}</code></pre>
<p data-wordfix="true" id="code-skip-day-2-parsing-data-sources-2">The error seems to be coming from this area in particular in the Eleventy core code:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/aramzsxyz/day-2-parsing-data-sources/#code-skip-day-2-parsing-data-sources-1" id="skip-to-code-skip-day-2-parsing-data-sources-1" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript">  <span class="token keyword">async</span> <span class="token function">addPageDate</span><span class="token punctuation">(</span><span class="token parameter">data</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span><span class="token punctuation">(</span><span class="token string">"page"</span> <span class="token keyword">in</span> data<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />      data<span class="token punctuation">.</span>page <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">;</span><br />    <span class="token punctuation">}</span><br /><br />    <span class="token keyword">let</span> newDate <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">getMappedDate</span><span class="token punctuation">(</span>data<span class="token punctuation">)</span><span class="token punctuation">;</span><br />    console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>data<span class="token punctuation">.</span>page<span class="token punctuation">)</span><span class="token punctuation">;</span><br />    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token string">"page"</span> <span class="token keyword">in</span> data <span class="token operator">&amp;&amp;</span> <span class="token string">"date"</span> <span class="token keyword">in</span> data<span class="token punctuation">.</span>page<span class="token punctuation">)</span> <span class="token punctuation">{</span><br />      <span class="token function">debug</span><span class="token punctuation">(</span><br />        <span class="token string">"Warning: data.page.date is in use (%o) will be overwritten with: %o"</span><span class="token punctuation">,</span><br />        data<span class="token punctuation">.</span>page<span class="token punctuation">.</span>date<span class="token punctuation">,</span><br />        newDate<br />      <span class="token punctuation">)</span><span class="token punctuation">;</span><br />    <span class="token punctuation">}</span><br /><br />    data<span class="token punctuation">.</span>page<span class="token punctuation">.</span>date <span class="token operator">=</span> newDate<span class="token punctuation">;</span><br /><br />    <span class="token keyword">return</span> data<span class="token punctuation">;</span><br />  <span class="token punctuation">}</span></code></pre>
<p data-wordfix="true" id="code-skip-day-2-parsing-data-sources-1">But I'm not sure <em>why</em>. I've tried removing the date property, but that's not working. But it is definitely the quote md files causing the issue, because removing them stops the error.</p>
<p>Oh, my Quote posts have their own <code>page</code> property (the page the quote was on) and that is conflicting with how <code>page</code> objects work in Eleventy. Apparently this is sort of a protected property, but not in a way that it emits a useful warning &gt;.&lt;. I'll replace it with <code>pageNum</code> as the property.</p>
<p><a target="_blank" href="https://github.com/AramZS/aramzs.xyz/commit/fd74e2c56e30bfd316a82e793441c63362295cc7" class="git-commit-link"><code>git commit -am &quot;Get quotes working by avoiding conflict with the page object&quot;</code></a></p>
<p>Ok, that looks good. Still getting a conflict, this time with my custom slugs not passing through. It looks like the logic for resource pages doesn't include a slug if I set one in the post. I can correct it to check for the <code>slug</code> field.</p>
<p>Looking good, I now have to deal with the quote files that have <code>publish: false</code> attached to them. This <a href="https://github.com/11ty/eleventy/issues/188" target="_blank">isn't a 11ty</a> <a href="https://github.com/11ty/eleventy/issues/2060" target="_blank">native concept</a>, so I'll have to build some logic in to keep them out of the flow.</p>
<p>I'm going to adapt the approach in the <a href="https://github.com/11ty/eleventy-base-blog/blob/main/eleventy.config.drafts.js" target="_blank">Eleventy Base Blog</a>.</p>
<p>Ok, so after some experimentation, I don't think this is working, though <a href="https://github.com/11ty/eleventy-base-blog/issues/173" target="_blank">I'm not sure why</a>.</p>
<p>I'm not entirely sure what the issue was, but I've solved it by adding new logic on filtering into the file at <code>lib/collections.js</code> to filter the default inclusion logic for the <code>post</code> collection. This seems to have worked even where a file might be in another collection. I guess no collection gets made that isn't made through that file, so it has total control. Good to know. In any case, my new more extensive draft logic does seem to work now.</p>
<p>I've added an additional control to by dotenv file <code>DRAFT_FREE=&quot;false&quot;</code> to allow me to turn off drafts, even in the local development environment. This also means that I'll be draft free by default in my dev env. I know a lot of folks manage drafts more actively looking at them in the built site, but I'm not currently doing that. Maybe if I start, I'll have to figure out some more elaborate logic. The template does support that flow by showing draft posts in place with <code>(D) </code> in red before the title. That's pretty cool, even if I'm not planning to use it!</p>
<p><a target="_blank" href="https://github.com/AramZS/aramzs.xyz/commit/dfbac9c96e20d8a57e32f39f1c1704dd309af938" class="git-commit-link"><code>git commit -am &quot;Add logic to manage draft mode and a no-publish mode&quot;</code></a></p>
]]></content:encoded>
	</item>
	
	<item>
		<title>XYZ Site - Day 1 - Working through a new 11ty build</title>
		<link>https://fightwithtools.dev/posts/projects/aramzsxyz/day-1-working-through-a-new-11ty-build/?source=rss</link>
		<pubDate>Sun, 25 Feb 2024 02:59:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/projects/aramzsxyz/day-1-working-through-a-new-11ty-build/</guid>
		<description>Trying out someone else's approach to 11ty.</description>
		<content:encoded><![CDATA[<h2 id="project-scope-and-todos" tabindex="-1">Project Scope and ToDos</h2>
<ol>
<li>Create a versatile blog site</li>
<li>Create a framework that makes it easy to add external data to the site</li>
</ol>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Give the site the capacity to replicate the logging and rating I do on Serialized and Letterboxd.</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Be able to pull down RSS feeds from other sites and create forward links to my other sites</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Create forward links to sites I want to post about.</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Create a way to pull in my Goodreads data and display it on the site</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Create a way to automate pulls from other data sources</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Combine easy inputs like text lists and JSON data files with markdown files that I can build on top of.</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Add a TMDB credit to footer in base.njk</li>
</ul>
<h2 id="day-1" tabindex="-1">Day 1</h2>
<p>I've branched the work from <a href="https://photogabble.co.uk/about/" target="_blank">Simon Dann</a> <small>(<a target="_blank" href="https://notacult.social/@carbontwelve">@carbontwelve@notacult.social</a>)</small> whose blog I really liked. I reached out and <a href="https://notacult.social/@carbontwelve/111568182431303826" target="_blank">got the ok to adapt the site</a> to my own site. So that's what I'm trying to do now. I've been fiddling around to try and figure out how it all works, and it's pretty cool!</p>
<p>One of the things I want to do is be able to contribute back to Dann's site if I have useful improvements. I also did some work that will make a hard split from the origin make sense. So I'm not working on the site as a branch, but I should be able to sync back from and potentially into the original repository. I'm going to add it as an origin I can interact with:</p>
<p><code>git remote add upstream git@github.com:photogabble/website.git</code></p>
<p>Let's see if that works.</p>
<p>It does! It allows me to cherry-pick improvements from the remote. That's useful, because they've added a lot of updates <a href="https://github.com/photogabble/website/commit/c7bf2e5848d46dbecf9772a1a677535630f3c879" target="_blank">since I branched</a>. We'll see later if I have useful things to contribute back.</p>
<p data-wordfix="true">Now I want to try and get my TV lists working. I've been playing around with using a text list I pulled from JustWatch activity. I then crawl that and pull metadata and images out of <a href="https://developer.themoviedb.org/reference/intro/getting-started" target="_blank">The Movie DB</a>. I want to combine it or interact with the movie data that is in the <code>data</code> folder for global data. But I have to admit, I'm not really clear with how Dann set up processing that into the particular template that shows it. The result is that by using the list mechanism in the site I've ended up having both the TV markdown files I created and the data file writing to the same place. I've got to fix that, but to do that I need a better grasp on what is going on with how the site interacts with the data objects. Dann has made some pretty different structural choices around how to build and Eleventy site than any of mine (that's one of the reasons I wanted to work with this code) but it means I'm pretty confused about some of the pages and how they pop into existence at build. That's fine, I want to learn.</p>
<p data-wordfix="true">Part of the confusion is that Dann has really leaned into some of the Nunjucks Eleventy hierarchy for rendering that really got me mixed up the first time around I used it for an Eleventy site. I think that it seems the site is just tapping that data object directly into the template. Whereas I can try and change the template to combine the two with a custom layout in the <code>layouts</code> folder I think. To combine the two data sources, I'm going to <a href="https://dev.to/giulia_chiola/add-items-to-an-array-in-nunjucks-482e" target="_blank">try a technique I found on Dev.to from Giulia Chiola</a>.</p>
<p>The key to getting the page to display right is to also have some information in the <code>src/_data/lists-meta.js</code> file. I actually think I could have put the layout into that file, but I've had my automated process put it into the actual generated MD files for now. Let's see how it goes.</p>
<p>Ok, I've been able to generate the file using my new template, but it doesn't have the new data I put in.</p>
<p data-wordfix="true">The one issue is the item/post format from Eleventy is a lot more complicated than the content from the JS files. Not only that, but I'll need to sort the two together. I know, I'll build a filter! That way I can transform the posts to the simpler format and also handle the date sort.</p>
<p>Dann's project makes it easy to add new filters. I can just add to <code>lib/filters.js</code>.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/aramzsxyz/day-1-working-through-a-new-11ty-build/#code-skip-day-1-working-through-a-new-11ty-build-1" id="skip-to-code-skip-day-1-working-through-a-new-11ty-build-1" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> <span class="token function-variable function">dateSort</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">arrayOfObjects<span class="token punctuation">,</span> key</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />	arrayOfObjects<span class="token punctuation">.</span><span class="token function">sort</span><span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">a<span class="token punctuation">,</span> b</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />		<span class="token comment">// Turn your strings into dates, and then subtract them</span><br />		<span class="token comment">// to get a value that is either negative, positive, or zero.</span><br />		<span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span>b<span class="token punctuation">[</span>key<span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token operator">-</span> <span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span>a<span class="token punctuation">[</span>key<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token keyword">return</span> arrayOfObjects<span class="token punctuation">;</span><br /><span class="token punctuation">}</span><span class="token punctuation">;</span><br /><br /><span class="token keyword">const</span> <span class="token function-variable function">mixedDataSortWatchedMedia</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">arrayOfObjects</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />	<span class="token keyword">let</span> standardizedArrayOfObjects <span class="token operator">=</span> arrayOfObjects<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">item</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />		<span class="token keyword">if</span> <span class="token punctuation">(</span>item<span class="token punctuation">.</span>data<span class="token punctuation">)</span> <span class="token punctuation">{</span><br />			<span class="token keyword">let</span> newObject <span class="token operator">=</span> <span class="token punctuation">{</span><br />				<span class="token operator">...</span>item<span class="token punctuation">.</span>data<span class="token punctuation">,</span><br />				<span class="token literal-property property">content</span><span class="token operator">:</span> item<span class="token punctuation">.</span>content<span class="token punctuation">,</span><br />				<span class="token literal-property property">date</span><span class="token operator">:</span> item<span class="token punctuation">.</span>date<span class="token punctuation">,</span><br />			<span class="token punctuation">}</span><span class="token punctuation">;</span><br />			<span class="token keyword">return</span> newObject<span class="token punctuation">;</span><br />		<span class="token punctuation">}</span><br />		<span class="token keyword">return</span> item<span class="token punctuation">;</span><br />	<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token keyword">const</span> sorted <span class="token operator">=</span> <span class="token function">dateSort</span><span class="token punctuation">(</span>standardizedArrayOfObjects<span class="token punctuation">,</span> <span class="token string">"watchedDate"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />	console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">"mixedDataSortWatchedMedia sorted"</span><span class="token punctuation">,</span> sorted<span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token keyword">return</span> sorted<span class="token punctuation">;</span><br /><span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
<p id="code-skip-day-1-working-through-a-new-11ty-build-1">That takes care of it!</p>
]]></content:encoded>
	</item>
	
	<item>
		<title>Aggregation, Amplification, and Archiving | Fellowship of the Link</title>
		<link>https://fightwithtools.dev/posts/writing/aggregation-amplification-and-archiving/?source=rss</link>
		<pubDate>Wed, 31 Jan 2024 17:30:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/writing/aggregation-amplification-and-archiving/</guid>
		<description>What can neobooks tell us about a future robust eternal web?</description>
		<content:encoded><![CDATA[<p>I've been meeting with the <a href="https://www.fellowshipofthelink.org/" target="_blank">Fellowship of the Link</a> for a while now and a lot of what we've discussed has inspired some of the choices, considerations or directions I've gone on with my projects.</p>
<h2 id="neobooks" tabindex="-1">Neobooks</h2>
<p>We had a recent discussion on the 24th of January, 2024, where we discussed the idea of <a href="https://anagora.org/co-write-a-neobook" target="_blank">neobooks</a> and the assembly of parts into whole publications that reminded me a lot of the <a href="http://proceedings.thatcamp.org/about/index.html" target="_blank">Proceedings of THATCamp</a> project I worked on a while back. I think that leads me to think a little more about nuggets of data and content and how their assembly can be leveraged to their benefit and to create useful things. The idea of a book artifact at the end of the process is, I think, a good one. But, building on some of our previous discussions, I'm particularly interested in how these online neobooks, as artifacts of an aggregation process, provide other properties.</p>
<h2 id="transclusion" tabindex="-1">Transclusion</h2>
<p>We've talked a lot about the power of linking, <a href="https://www.technologyreview.com/2020/09/03/1007716/digital-gardens-let-you-cultivate-your-own-little-bit-of-the-internet/" target="_blank">digital gardens</a>, and more recently about approaches to transclusion, especially in <a href="https://medium.com/workings/true-transclusion-in-obsidian-6d2e05235bd" target="_blank">Obsidian</a>. Transclusion is, I think, an important element in this, especially depending on the variety of ways something might be considered transcluded.</p>
<p>Transclusion could be, mechanically, an iframe, a replica, something that looks like a more traditional reference or perhaps something like I do with archiving on <a href="https://pressforward.org/" target="_blank">PressForward</a> sites and the <a href="https://context.center/" target="_blank">Context.Center</a>.</p>
<h2 id="amplification" tabindex="-1">Amplification</h2>
<p>On the web, depending on how we process it, there's an opportunity (and for me, a preference) for any composed or aggregated element to be both archive, and aggregation. There's even ways that can leverage structured data, using <a href="https://schema.org/hasPart" target="_blank"><code>hasPart</code></a> for the overall document and <a href="https://schema.org/isPartOf" target="_blank"><code>isPartOf</code></a> for nugget-documents to clearly link them all together. Once these different elements have clear links to each other, both through metadata and on-page linking, they naturally amplify each other. Crawlers will examine all parts and connect them to each other in a number of contexts, and the reinforcing links back and forth will raise the &quot;link juice&quot; of each part. Making sure that the parts note their relationship to the whole, and the whole to the parts, is a key part of this. I'd have to double check but, beyond using canonical tagging, we'd likely want to use the <a href="https://schema.org/sameAs" target="_blank"><code>sameAs</code></a> property to make sure that the area where the parts are assembled doesn't look like replication to any machines. Having prominent linking between the two that is human visible will also be helpful. We talked about webmentions for this and, though I have some misgivings at the implementation level, I agree that's the best way to automate this.</p>
<h2 id="the-eternal-web-and-agility" tabindex="-1">The Eternal Web and Agility</h2>
<p>Does crawling even matter is the obvious question. Some participants will almost certainly reject the primacy of Google (even if I believe it is unavoidable) and ask -- why bother? I think the answer here is that more entities crawl than Google. I have been thinking a lot about the question of what makes for a long-lasting web, what fights effectively not just against linkrot, but against corporate rot. We can't really depend on any system we don't own to last, but also we can't depend on our own systems to last. One day we die and the domains we use will stop getting paid for and the links will die. There has to be some hybrid between the two. I've been thinking about this as &quot;The Eternal Web&quot;, a future state where what we put online can absolutely outlast us.</p>
<p>This has driven a lot of my movement towards static site generators; as well as the use of the <a href="https://archive.org/" target="_blank">Internet Archive</a> and <a href="https://webrecorder.io/" target="_blank">Webrecorder</a>. Static sites and their content have an intrinsic portability that anything database driven lacks. I think a good indication of that is the cost of <a href="https://wordpress.com/100-year/" target="_blank">100-year WordPress</a>. It's a cool idea but the difficulty of maintaining and securing WordPress makes a long lasting iteration of a WordPress site a difficult proposition. I think we can take as an absolute: if it has to query a database to load the page, it will one day fail to work at all. But even when my domains fail, my sites will continue to be accessible through GitHub, along with all the information on it. When GitHub dies there is still the possibility that my sites can be maintained by interested parties without too much work. The sites are all static HTML and therefore inherently portable.</p>
<h3 id="own-your-archive" tabindex="-1">Own Your Archive</h3>
<p>This gets to the importance of agility in this process. The work of assembly has to be fast, quick, and detachable. The other guarantee for long lasting life for a website is when it is replicated. So we should have fast, paired, process of aggregation and archiving. The best way to really keep the web alive is not just to depend on the Internet Archive, which may one day fail, or be sued out of existence, but to make sure that everyone has their own copy of the parts of the web they think are important.</p>
<p>We often talk of the importance of owning your own platform, but I think it is equally important to own your own archive. As we look towards an increasingly unsure future, what we can guarantee of the web is the parts of it we keep near to us. I imagine a world where a layer lives between us and the wider web that requires less energy to access, less data to absorb and can easily be shared with those physically near us. This will also be a kind of amplification.</p>
<p>To reach this end, our approach has to be agile. Assembly of nuggets should include automatically the means of amplification and archiving. The goal should be to make this all quick, easy, and also easy to access purely locally, without a connection to anything but a local network. The best web is one that is massively replicated and this seems a clear path towards that practice.</p>
<h2 id="the-long-watch" tabindex="-1">The Long Watch</h2>
<p><a href="https://en.wikipedia.org/wiki/Long_Now_Foundation" target="_blank">The Long Now</a> project, with its tendency towards conservatism, it's bias towards corporate entities as reservoirs of knowledge and practice (even though every example we have shows that not to be a reliable approach) and it's insistence on a money basis makes its sustainability goals questionable, and the world they might create if they did succeed even more so. It will never be capable of creating a truly useful archive or system of civilization amplification because both require the type of aggregation that is inherently disruptive of the present systems of copyright and intellectual property in a way that its libertarian capitalist leanings forbid it from pursuing.</p>
<p>Instead of a top-down, hierarchical, corporate idea of preservation and future building, I think we need to consider a community approach, one highly decentralized that can also be worked with locally.</p>
<p>We should consider even more broadly than we have thus far: what does it mean to have a community-first web, a localized library archive of the things that matter, and how can we build it together. Where we need to go is towards a type of toolset that can let anyone stand watch over the web and preserve it, not just centrally, but for themselves and the people around them. But also one that can connect with any other such system, build links of replication and amplification, and provide a web that doesn't require any central authority to last forever.</p>
<p><strong>This is an early draft</strong></p>
]]></content:encoded>
	</item>
	
	<item>
		<title>Day 45 - Comments as simply as possible</title>
		<link>https://fightwithtools.dev/posts/projects/devblog/hello-day-45/?source=rss</link>
		<pubDate>Thu, 18 Jan 2024 02:59:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/projects/devblog/hello-day-45/</guid>
		<description>How little server can I involve in giving myself a commenting system?</description>
		<content:encoded><![CDATA[<h2 id="project-scope-and-todos" tabindex="-1">Project Scope and ToDos</h2>
<ol>
<li>Static Site Generator that can build the blog and let me host it on Github Pages</li>
<li>I want to write posts in Markdown because I'm lazy, it's easy, and it is how I take notes now.</li>
<li>I don't want to spend a ton of time doing design work. I'm doing complicated designs for other projects, so I want to pull a theme I like that I can rely on someone else to keep up.</li>
<li>Once it gets going, I want template changes to be easy.</li>
<li>It should be as easy as Jekyll, so I need to be able to build it using GitHub Actions, where I can just commit a template change or Markdown file and away it goes. If I can't figure this out than fk it, just use Jekyll.</li>
<li>I require it to be used by a significant percent of my professional peers so I can get easy answers when something goes wrong.</li>
<li>I want source maps. This is a dev log site which means whatever I do with it should be easy for other developers to read.</li>
</ol>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Also <a href="https://www.npmjs.com/package/@quasibit/eleventy-plugin-sitemap" target="_blank">the sitemap plugin</a> looks cool. Should grab that later.</li>
</ul>
<s>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> So does the <a href="https://www.npmjs.com/package/eleventy-plugin-reading-time" target="_blank">reading time one</a>.</li>
</ul>
</s>
<ul class="task-list">
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Also <a href="https://github.com/jdsteinbach/eleventy-plugin-toc/" target="_blank">this TOC plugin</a> mby?</p>
</li>
<li class="task-list-item">
<p data-wordfix="true"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Use <a href="https://www.11ty.dev/docs/data-deep-merge/" target="_blank">Data Deep Merge</a> in this blog.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Decide if I want to render the CSS fancier than just a base file and do per-template splitting.</p>
</li>
</ul>
<s>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Can I use the template inside of dinky that already exists instead of copy/pasting it?</li>
</ul>
</s>
<s>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Is there a way to have permalinks to posts contain metadata without organizing them into subfolders?</li>
</ul>
</s>
<ul class="task-list">
<li class="task-list-item">
<p data-wordfix="true"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> How do I cachebreak files on the basis of new build events? Datetime? <code>site.github.build_revision</code> is <a href="https://github.com/jekyll/github-metadata/blob/master/docs/site.github.md" target="_blank">how Jekyll accomplishes this</a>, but is there a way to push <a href="https://docs.github.com/en/actions/reference/context-and-expression-syntax-for-github-actions#github-context" target="_blank">that</a> <a href="https://stackoverflow.com/questions/54310050/how-to-version-build-artifacts-using-github-actions" target="_blank">into the build process</a> for Eleventy?</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Make link text look less shitty. It looks like it is a whole, lighter, font.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Code blocks do not have good syntax highlighting. I want good syntax highlighting.</p>
</li>
<li class="task-list-item">
<p data-wordfix="true"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Build a Markdown-it plugin to take my typing shortcuts <code>[prob, b/c, ...?]</code> and expand them on build.</p>
</li>
</ul>
<s>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> See if we can start Markdown's interpretation of H tags to <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/Heading_Elements#multiple_h1" target="_blank">start at 2, since H1</a> is always pulled from the page title metadata. If it isn't easy, I just have to change my pattern of writing in the MD documents.</li>
</ul>
</s>
<ul class="task-list">
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Should I <a href="https://www.madebymike.com.au/writing/11ty-filters-data-shortcodes/" target="_blank">explore some shortcodes</a>?</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Order projects listing by last posted blog in that project</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Limit the output of home page post lists to a specific number of posts</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Show the latest post below the site intro on the homepage.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Tags pages with Pagination</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Posts should be able to support a preview header image that can also be shown on post lists.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Create a Markdown-It plugin that reads the project's repo URL off the folder data file and renders commit messages with <a href="https://stackoverflow.com/questions/15919635/on-github-api-what-is-the-best-way-to-get-the-last-commit-message-associated-w" target="_blank">links to the referenced commit</a>. (Is this even possible?) (Is there a way to do it with eleventy instead?)</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Create Next Day/Previous Day links on each post / Next/Previous post on post templates from projects</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Tags should be in the sidebar of articles and link to tag pages</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Create a skiplink for the todo section (or would this be better served with the ToC plugin?) - Yes it would be!</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Add a Things I Learned section to the project pages that are the things I learned from that specific project.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Add a technical reading log to the homepage</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/:empty" target="_blank">Hide</a> empty sections.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Add byline to post pages</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Have table of contents attach to sidebar bottom on mobile</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Support dark mode</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Social Icons</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> SEO/Social/JSON-LD HEAD data</p>
</li>
</ul>
<h2 id="day-45" tabindex="-1">Day 45</h2>
<p>I want to try a way to add comments to this blog. I want something where I have a good degree of ownership over the comments, so I took a look at <a href="https://lisakov.com/projects/open-source-comments/" target="_blank">some options</a>. Mainly, I'm hoping I don't have to host a server.</p>
<p>I took a look at a whole bunch of interesting options:</p>
<ul>
<li><a href="https://docs.commento.io/" target="_blank">Introduction · Commento</a></li>
<li><a href="https://webmention.io/" target="_blank">Webmention.io</a></li>
<li><a href="https://csarven.ca/linked-data-notifications#protocol" target="_blank">Linked Data Notifications</a></li>
<li><a href="https://github.com/coralproject/talk" target="_blank">GitHub - coralproject/talk: A better commenting experience from Vox Media</a></li>
<li><a href="https://github.com/discourse/discourse" target="_blank">GitHub - discourse/discourse: A platform for community discussion. Free, open, simple.</a></li>
<li><a href="https://github.com/posativ/isso" target="_blank">Isso</a></li>
<li><a href="https://github.com/djyde/cusdis" target="_blank">GitHub - djyde/cusdis: lightweight, privacy-friendly alternative to Disqus.</a></li>
<li><a href="https://github.com/eduardoboucas/staticman" target="_blank">GitHub - eduardoboucas/staticman: 💪 User-generated content for Git-powered websites</a>
<ul>
<li><a href="https://travisdowns.github.io/blog/2020/02/05/now-with-comments.html" target="_blank">Adding Staticman Comments</a></li>
<li><a href="https://eduardoboucas.com/blog/2016/08/10/staticman.html" target="_blank">Adding user-generated content to a static site using Staticman</a></li>
</ul>
</li>
<li><a href="https://pknopf.com/post/2018-10-13-comments-for-static-sites-using-github-issues/" target="_blank">Comments for static websites, using GitHub Issues.</a></li>
</ul>
<p>I'm going to try <a href="https://utteranc.es/" target="_blank">utterances</a>. It's a GitHub Issues based comment system that looks like it just needs a GitHub app and some JS.</p>
<p>I suppose the GitHub App could break and that would screw me, but I'd still have the comments and I could always pull them in some other way if needed. The one downside is that they aren't really static in my code for this site. But let's give it a try. Staticman seems like it is closer to what I want, but I don't want to have to care for some tiny server, which seems a requirement.</p>
<p>Seems to work fine. I guess... I'll try it out? Sure, why not!</p>
]]></content:encoded>
	</item>
	
	<item>
		<title>Trying HTMX</title>
		<link>https://fightwithtools.dev/posts/writing/trying-htmx/?source=rss</link>
		<pubDate>Sat, 21 Oct 2023 20:30:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/writing/trying-htmx/</guid>
		<description>Doing some testing around trying out HTMX for other projects.</description>
		<content:encoded><![CDATA[<h2 id="what-is-htmx" tabindex="-1">What is HTMX?</h2>
<p>From it's <a href="https://htmx.org/" target="_blank">website</a>:</p>
<blockquote>
<p>htmx gives you access to AJAX, CSS Transitions, WebSockets and Server Sent Events directly in HTML, using attributes, so you can build modern user interfaces with the simplicity and power of hypertext</p>
</blockquote>
<h2 id="why-htmx" tabindex="-1">Why HTMX?</h2>
<p>It has been recommended to me a few times and I'm pretty interested in what appears to be a pretty simple way to do single-page-app style behavior without a ton of complex and overly heavy javasscript.</p>
<h2 id="step-one:-the-basics" tabindex="-1">Step one: the basics</h2>
<p>I'm going to <a href="https://htmx-preview-one.glitch.me/" target="_blank">use Glitch to set up a basic HTMX website</a> where I can play around with some of the core concepts, the ability to swap out content, and gain a better understanding of how to work HTMX.</p>
<p>As I'd hoped, it's pretty straightforward. I can identify basic things to swap, events that cause swapping and even elements that I can replace in response to the swap to allow one page to provide updates to different areas of the page separately.</p>
<p><code>hx-get</code>, <code>hx-swap</code>, and <code>hx-swap-oob</code> all seem to work really clearly and as expected.</p>
<p><code>hx-get</code> creates a GET request to a URL (relative to the site domain, not the local path, as far as I've been able to tell thus far.) and swaps in the retrieved HTML with the current element (the method can also be <code>hx-post</code>). It can instructed how it swaps in the content wtih <code>hx-swap</code> and <code>hx-swap-oob</code>.</p>
<p>This is pretty cool, and is promising for some things I want to try out.</p>
<h2 id="step-two:-media-navigation" tabindex="-1">Step two: media navigation</h2>
<p>One of the key things I want to accomplish is to be able to navigate around a site while a piece of media stays in place and can play uninterrupted. Let's try that.</p>
<p>First I'll set up some basic navigation tests. Good to note that <code>hx-push-url</code> is relative to the core domain, not the local path. So if you're on <code>/test</code> and you want to go to <code>/test/2</code> you need to use <code>hx-push-url=&quot;/test/2&quot;</code> not <code>hx-push-url=&quot;/2&quot;</code>. It also looks like it automatically picks up the <code>&lt;title&gt;&lt;/title&gt;</code> tag. I wonder if it picks up everything else that can be in there? I'll have to test it out.</p>
<p>Ok, it requires some hacking on to the process, you have to essentially create a space outside the elements changed by HTMX and then modify it depending on pulling in particular script tags. But it does work! This seems to be the way to go. The other thing I'll have to do is figure out how to queue up separate videos / audio tags  and then swap them in on complete for each video / audio file. It seems like this is the way to go though! I think I can do one more test, to try to make the player queue more complex. If I can do that, and also make it so playing media goes <em>into</em> the preserved element from elsewhere on the page, then this will be my solve for a bunch of projects I'd like to try out.</p>
<h2 id="step-three:-multi-play" tabindex="-1">Step three: multi-play</h2>
<p>I think I can make it a better organized multi-play system with a custom HTML element. Let's <a href="https://web.dev/articles/custom-elements-v1" target="_blank">remind</a> <a href="https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements" target="_blank">ourselves</a> of how that works.</p>
<p>I can even use the custom element mount events to inform the page it is ready to receive a playlist item and back it with a timeout if needed. Then I can push stuff to the playlist element and it will have an array to work through.</p>
<p>I'll also have to check the iframe for YouTube's status. Here's <a href="https://stackoverflow.com/questions/7853904/how-to-detect-when-a-youtube-video-finishes-playing" target="_blank">one way to do so</a> and a <a href="https://developers.google.com/youtube/iframe_api_reference" target="_blank">reference</a>. That'll be the next step. However, so testing around how I can add things in seems to indicate it can work. Just placing a script tag in an HTMX loaded element that does the work of pushing into a playlist seems like it can do the trick. I think I'll base it on user action in the actual sites I'm working on though.</p>
]]></content:encoded>
	</item>
	
	<item>
		<title>Context Center Timelines - Day 23 - Fix Context Center Deploy action</title>
		<link>https://fightwithtools.dev/posts/projects/context-timelines/day-23-fixing-deploy-action/?source=rss</link>
		<pubDate>Sat, 23 Sep 2023 02:59:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/projects/context-timelines/day-23-fixing-deploy-action/</guid>
		<description>Let's try the timeline plugin using a new site.</description>
		<content:encoded><![CDATA[<h2 id="project-scope-and-todos" tabindex="-1">Project Scope and ToDos</h2>
<ol>
<li>Create timeline pages where one can see the whole timeline of a particular event</li>
<li>Give timeline items type or category icons so that you can easily scan what is happening.</li>
<li>Allow the user to enter the timeline at any individually sharable link of an event and seamlessly scroll up and down</li>
</ol>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Deliver timelines as a plugin that can be extended by other Eleventy users</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Auto-create social-media-ready screenshots of a timeline item</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Integrate with Contexter to have context-full link cards in the timeline</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Leverage the Live Blog format of Schema dot org</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Allow each entry to be its own Markdown file</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Handle SASS instead of CSS</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Fast Scroller by Month and Year</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Add timelines and individual timeline items to the sitemap</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Generate images more efficiently.</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Support a counter that can increment depending on where you are on the timeline.</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Generate QR codes / Stickers for each timeline</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> /raw/md returns a raw version of a topic (in markdown)</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> /raw/md includes a YAML header with relevant information</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> /raw/json returns a JSON version of a topic</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> /feed/ returns a latest links feed of a topic</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> RSS feed of links</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> RSS feed of new links per topic / timeline</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Support a header image.</li>
</ul>
<h2 id="day-23" tabindex="-1">Day 23</h2>
<p>I had my site stop deploying. It looked like some problem having to do with my deploy action and when I went for support to <a href="https://github.com/peaceiris/actions-gh-pages" target="_blank">the repo for the action</a> I was using it sent me to <a href="https://github.blog/2022-08-10-github-pages-now-uses-actions-by-default/" target="_blank">GitHub Actions</a>.</p>
<p>I read it, seems straighforward, looked at the <a href="https://github.com/actions/starter-workflows/tree/main/pages" target="_blank">examples</a>. There isn't one for Eleventy, so I decided to stitch together the <a href="https://github.com/actions/starter-workflows/blob/main/pages/nextjs.yml" target="_blank">Next</a> and <a href="https://github.com/actions/starter-workflows/blob/main/pages/static.yml" target="_blank">Static</a> workflows. Still didn't quite work.</p>
<p>I ended up pulling together a few of the actions as anticipated, but also having to update some packages and fiddle around with the process. A big tripping point was that, for some reason, I needed to make the deploy step (with the deploy action) a separate job. I'm not sure why.</p>
<p>Even then it didn't work. But it did tell me that I could only deploy from the <code>gh-pages</code> branch. Ok, weird.</p>
<p>Well, it turned out I had one last step to take. I had to tell GitHub to use Actions instead of deploying from the branch by going to Settings &gt; Pages and finding the Source pulldown and changing it to &quot;GitHub Actions&quot;. Once I did that the build worked! Deployment worked! I could even, at last, delete the old <code>gh-pages</code> branch. Everything is working and deploying now .</p>
<p><a href="https://github.com/AramZS/context-center/commit/80fbcc073e1131b0a3d9f785eba8bbba4e6b0857" target="_blank">Check out the new workflow!</a></p>
<p>Here's <a href="https://github.com/AramZS/context-center/blob/main/.github/workflows/eleventy_build.yml" target="_blank">the final file</a></p>
]]></content:encoded>
	</item>
	
	<item>
		<title>Context Center Timelines - Day 22 - Test it to death</title>
		<link>https://fightwithtools.dev/posts/projects/context-timelines/day-22-trying-to-put-together-a-standalone-site/?source=rss</link>
		<pubDate>Mon, 14 Aug 2023 02:59:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/projects/context-timelines/day-22-trying-to-put-together-a-standalone-site/</guid>
		<description>Let's try the timeline plugin using a new site.</description>
		<content:encoded><![CDATA[<h2 id="project-scope-and-todos" tabindex="-1">Project Scope and ToDos</h2>
<ol>
<li>Create timeline pages where one can see the whole timeline of a particular event</li>
<li>Give timeline items type or category icons so that you can easily scan what is happening.</li>
<li>Allow the user to enter the timeline at any individually sharable link of an event and seamlessly scroll up and down</li>
</ol>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Deliver timelines as a plugin that can be extended by other Eleventy users</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Auto-create social-media-ready screenshots of a timeline item</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Integrate with Contexter to have context-full link cards in the timeline</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Leverage the Live Blog format of Schema dot org</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Allow each entry to be its own Markdown file</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Handle SASS instead of CSS</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Fast Scroller by Month and Year</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Add timelines and individual timeline items to the sitemap</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Generate images more efficiently.</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Support a counter that can increment depending on where you are on the timeline.</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Generate QR codes / Stickers for each timeline</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> /raw/md returns a raw version of a topic (in markdown)</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> /raw/md includes a YAML header with relevant information</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> /raw/json returns a JSON version of a topic</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> /feed/ returns a latest links feed of a topic</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> RSS feed of links</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> RSS feed of new links per topic / timeline</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Support a header image.</li>
</ul>
<h2 id="day-22" tabindex="-1">Day 22</h2>
<p>Ok, I want to try and <a href="https://github.com/AramZS/politicians-center" target="_blank">set up a new site</a> with the Timelinety plugin. I've been able to get it mostly working, but there is a lot of extra setup. I want to see if I can make time-to-start shorter by incorporating more initial templates in the plugin itself.</p>
<p>Right now, the user who wants to create a site with Timelinety has to do so by creating at least 4 pages outside of the actual timeline items.</p>
<p>The question is, can I add additional input directories to the Eleventy config?</p>
<p>Oh, <a href="https://github.com/11ty/eleventy/issues/2353" target="_blank">looks like... no</a>. I can add the files maybe? Can I get inputs and outputs for Eleventy in the plugin? <a href="https://github.com/11ty/eleventy/discussions/2483" target="_blank">I think so</a>!</p>
<p>Ok, so I can set it up to copy over the setup files. I think this will work:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/context-timelines/day-22-trying-to-put-together-a-standalone-site/#code-skip-day-22-trying-to-put-together-a-standalone-site-1" id="skip-to-code-skip-day-22-trying-to-put-together-a-standalone-site-1" class="skip-link">Skip code block ▼</a></p>
<pre class="language-js"><code class="language-js"><span class="token keyword">if</span> <span class="token punctuation">(</span>pluginConfig<span class="token punctuation">.</span>addBaseFiles<span class="token punctuation">)</span> <span class="token punctuation">{</span><br />	eleventyConfig<span class="token punctuation">.</span><span class="token function">on</span><span class="token punctuation">(</span><span class="token string">"eleventy.before"</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />		<span class="token keyword">let</span> copyFileTo <span class="token operator">=</span> path<span class="token punctuation">.</span><span class="token function">normalize</span><span class="token punctuation">(</span>path<span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span>process<span class="token punctuation">.</span><span class="token function">cwd</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token string">"src"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />		<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">typeof</span> pluginConfig<span class="token punctuation">.</span>addBaseFiles <span class="token operator">==</span> <span class="token string">"string"</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />			copyFileTo <span class="token operator">=</span> pluginConfig<span class="token punctuation">.</span>addBaseFiles<span class="token punctuation">;</span><br />		<span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span><br />			copyFileTo <span class="token operator">=</span> path<span class="token punctuation">.</span><span class="token function">normalize</span><span class="token punctuation">(</span><br />				path<span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span>process<span class="token punctuation">.</span><span class="token function">cwd</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> eleventyConfig<span class="token punctuation">.</span>dir<span class="token punctuation">.</span>input<span class="token punctuation">)</span><br />			<span class="token punctuation">)</span><span class="token punctuation">;</span><br />		<span class="token punctuation">}</span><br />		<span class="token keyword">const</span> copyFromPath <span class="token operator">=</span> path<span class="token punctuation">.</span><span class="token function">normalize</span><span class="token punctuation">(</span><br />			path<span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span>__dirname<span class="token punctuation">,</span> <span class="token string">"src/pages"</span><span class="token punctuation">)</span><br />		<span class="token punctuation">)</span><span class="token punctuation">;</span><br />		<span class="token punctuation">[</span><br />			<span class="token string">"timeline.md"</span><span class="token punctuation">,</span><br />			<span class="token string">"timelines.md"</span><span class="token punctuation">,</span><br />			<span class="token string">"timeline-endpoints.md"</span><span class="token punctuation">,</span><br />			<span class="token string">"timeline-pages.md"</span><span class="token punctuation">,</span><br />		<span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">file</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />			<span class="token keyword">const</span> timelineMDFile <span class="token operator">=</span> path<span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span>copyFromPath<span class="token punctuation">,</span> file<span class="token punctuation">)</span><span class="token punctuation">;</span><br />			<span class="token keyword">const</span> targetMDFile <span class="token operator">=</span> path<span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span>copyFileTo<span class="token punctuation">,</span> file<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br />			<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>fs<span class="token punctuation">.</span><span class="token function">existsSync</span><span class="token punctuation">(</span>targetMDFile<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />				console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><br />					<span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">Eleventy copy from </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>timelineMDFile<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> to </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>targetMDFile<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><br />				<span class="token punctuation">)</span><span class="token punctuation">;</span><br />				console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">"File does not already exist, copy it over"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />				fs<span class="token punctuation">.</span><span class="token function">copyFileSync</span><span class="token punctuation">(</span><br />					timelineMDFile<span class="token punctuation">,</span><br />					targetMDFile<span class="token punctuation">,</span><br />					fs<span class="token punctuation">.</span>constants<span class="token punctuation">.</span><span class="token constant">COPYFILE_EXCL</span><br />				<span class="token punctuation">)</span><span class="token punctuation">;</span><br />			<span class="token punctuation">}</span><br />		<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span></code></pre>
<p id="code-skip-day-22-trying-to-put-together-a-standalone-site-1">I think I want to make sure the file copy happens before the build. I can use <code>eleventyConfig.on('eleventy.before', () =&gt; ());</code> for that.</p>
<p>Ok, that copies it over. Does it work with the build timing? Yes, it does! <a href="https://github.com/AramZS/politicians-center/commit/fe6cd0f2b2a15e0c10e91ff006e7b583d71ee361" target="_blank">Awesome</a>.</p>
<p>Ok. Now I need to make sure that I actually have the minimum timeline CSS files.</p>
<p>Ok, the stuff in <code>template-timeline.sass</code> is good to do without.</p>
<p>I don't need my <code>reset.sass</code>.</p>
<p>Ok, looks like it is working.</p>
<p>I think things look like they are working, but there is a problem with the JSON response from Timelinety. It isn't working when there is no content value for a Timeline entry. I'll need to add another filter I think. Oh no, I need a different thing, <a href="https://github.com/AramZS/politicians-center/commit/93af4bcd2184e662f59b46e9a7b5bde8e7b6c9c5" target="_blank">I need a false state</a>.</p>
<p>Ok, I think this is ready to be a package now. <a href="https://github.com/AramZS/timelinety" target="_blank">Let's set up a repo</a>.</p>
<p>We add the <code>.npmignore</code> file. Then we can publish it.</p>
<p><a href="https://www.npmjs.com/package/timelinety" target="_blank">It is out as a package</a>!</p>
<p>Ok, let's try switching to using this package in the new site.</p>
<p data-wordfix="true">It mostly seems to work. The one downside is that I can't use <code>extends</code> the way I had hoped. I end up having to use {% extends &quot;../../node_modules/timelinety/src/layouts/timeline-wrapper.njk&quot; %}. <code>extends</code> doesn't use the Eleventy layout alias systems so I can't use it exactly as I had hoped. But other than that, it works!</p>
]]></content:encoded>
	</item>
	
	<item>
		<title>Day 7 - Process YAML to decide if the file is public.</title>
		<link>https://fightwithtools.dev/posts/projects/notebook/day-7-process-a-bunch-of-files/?source=rss</link>
		<pubDate>Wed, 21 Jun 2023 02:59:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/projects/notebook/day-7-process-a-bunch-of-files/</guid>
		<description>Let's play with using Rust to process private to public notes.</description>
		<content:encoded><![CDATA[<h2 id="project-scope-and-todos" tabindex="-1">Project Scope and ToDos</h2>
<ol>
<li>Pull public-marked notes from the notebook to the new repo</li>
<li>Create website that treats them like a wiki and links pages together</li>
<li>Support the basic YAML in <a href="https://github.com/AramZS/notebook/blob/main/README.md" target="_blank">https://github.com/AramZS/notebook/blob/main/README.md</a></li>
</ol>
<h2 id="day-7" tabindex="-1">Day 7</h2>
]]></content:encoded>
	</item>
	
	<item>
		<title>Day 6 - Process YAML to decide if the file is public.</title>
		<link>https://fightwithtools.dev/posts/projects/notebook/day-6-process-file/?source=rss</link>
		<pubDate>Wed, 21 Jun 2023 02:59:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/projects/notebook/day-6-process-file/</guid>
		<description>Let's play with using Rust to process private to public notes.</description>
		<content:encoded><![CDATA[<h2 id="project-scope-and-todos" tabindex="-1">Project Scope and ToDos</h2>
<ol>
<li>Pull public-marked notes from the notebook to the new repo</li>
<li>Create website that treats them like a wiki and links pages together</li>
<li>Support the basic YAML in <a href="https://github.com/AramZS/notebook/blob/main/README.md" target="_blank">https://github.com/AramZS/notebook/blob/main/README.md</a></li>
</ol>
<h2 id="day-6" tabindex="-1">Day 6</h2>
<p>Ok I want to try out my new function. That means getting everything up and running. Looks like I have one issue, my use of the new <code>md_file_transformer</code> function isn't working for my processing. I have to deal with turning the <code>PathBuf</code> output I'm getting from the directory walk into a string I can process. I thought I could use <code>to_str</code> but I guess not. Let's take a look at <a href="https://doc.rust-lang.org/std/path/struct.PathBuf.html" target="_blank">PathBuf</a>. Huh. Docs say <code>to_str</code> should work. Yet, the Rust compiler isn't working. Hmmm, it says <code>expected struct &quot;std::string::String&quot; found enum &quot;Option&lt;&amp;str&gt;&quot;</code>.</p>
<p>Ok, so I need to transform it into a string. Looks like <a href="https://stackoverflow.com/questions/37388107/how-to-convert-the-pathbuf-to-string" target="_blank">there are a few options</a>. I'll use <code>path.into_os_string().into_string().unwrap()</code>. It doesn't look like the best way to do it, especially if the user is on a Windows machine, but I'm not sure what the best alternative is. I suspect there is a way to pass the <code>PathBuf</code> direction into <code>read_to_string</code> in <code>fs</code>. But I can fiddle with that later, I'd like to move on from this for now.</p>
<p>Ok, that got me to the next problem. <code>if !keycheck || false == yamlObj[&quot;public&quot;].as_bool().unwrap() {</code> doesn't work if the value isn't a boolean. Oh yeah, I could use a <code>match</code> process, similar to Javascript <code>switch</code>. Ok, I want to further symplify it a bit. I'll set up another function to do the actual writing of the file in the <code>match</code>.</p>
<p>Ok, I think I've gotten it working:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/notebook/day-6-process-file/#code-skip-day-6-process-file-1" id="skip-to-code-skip-day-6-process-file-1" class="skip-link">Skip code block ▼</a></p>
<pre class="language-rust"><code class="language-rust"><span class="token keyword">let</span> keycheck <span class="token operator">=</span> yamlHashmap<span class="token punctuation">.</span><span class="token function">contains_key</span><span class="token punctuation">(</span><span class="token operator">&amp;</span><span class="token class-name">Yaml</span><span class="token punctuation">::</span><span class="token function">from_str</span><span class="token punctuation">(</span><span class="token string">"public"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token comment">// as_hash().unwrap().contains_key("public");</span><br /><span class="token macro property">dbg!</span><span class="token punctuation">(</span><span class="token operator">&amp;</span>yamlObj<span class="token punctuation">[</span><span class="token string">"public"</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br /><span class="token comment">// Check if variable is true</span><br /><span class="token keyword">if</span> <span class="token operator">!</span>keycheck <span class="token punctuation">{</span><br />	<span class="token comment">// Not a public ready file.</span><br /><span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span><br />	<span class="token keyword">match</span> yamlObj<span class="token punctuation">[</span><span class="token string">"public"</span><span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">as_str</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">unwrap</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />		<span class="token string">"true"</span> <span class="token operator">=></span> <span class="token function">public_file_transform</span><span class="token punctuation">(</span>single_file_path<span class="token punctuation">,</span> markdown_input<span class="token punctuation">,</span> <span class="token string">"public"</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br />		<span class="token string">"partial-public"</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />			<span class="token function">public_file_transform</span><span class="token punctuation">(</span>single_file_path<span class="token punctuation">,</span> markdown_input<span class="token punctuation">,</span> <span class="token string">"partial-public"</span><span class="token punctuation">)</span><br />		<span class="token punctuation">}</span><br />		<span class="token string">"partial-private"</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />			<span class="token function">public_file_transform</span><span class="token punctuation">(</span>single_file_path<span class="token punctuation">,</span> markdown_input<span class="token punctuation">,</span> <span class="token string">"partial-private"</span><span class="token punctuation">)</span><br />		<span class="token punctuation">}</span><br />		<span class="token string">"false"</span> <span class="token operator">=></span> <span class="token macro property">println!</span><span class="token punctuation">(</span><span class="token string">"Public is false"</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br />		_ <span class="token operator">=></span> <span class="token macro property">println!</span><span class="token punctuation">(</span><span class="token string">"Public is not an expected value"</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br />	<span class="token punctuation">}</span><br /><span class="token punctuation">}</span></code></pre>
<p id="code-skip-day-6-process-file-1">Now I'll have to build out <code>public_file_transform</code> to do the actual work of processing and copying the file. I'm not sure it makes sense to pass the markdown value for the public argument in this way. It might be a bit repetitive, after all I have to do a bunch of processing of the YAML data anyway inside the function. At the very least perhaps I should pass the YAML object into <code>public_file_transform</code>? I'll have to think if this is the best way to handle it. Perhaps I should just set a variable to the value of public after I've decided to continue and otherwise return early? I'll have to fiddle with it later.</p>
<p><code>git commit -am &quot;Continue setting up decision-making if file is public&quot;</code></p>
]]></content:encoded>
	</item>
	
	<item>
		<title>Update build process to Node 16.</title>
		<link>https://fightwithtools.dev/posts/projects/devblog/update-to-node-16/?source=rss</link>
		<pubDate>Mon, 19 Jun 2023 02:59:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/projects/devblog/update-to-node-16/</guid>
		<description>Keeping this thing up to date</description>
		<content:encoded><![CDATA[<h2 id="project-scope-and-todos" tabindex="-1">Project Scope and ToDos</h2>
<ol>
<li>Static Site Generator that can build the blog and let me host it on Github Pages</li>
<li>I want to write posts in Markdown because I'm lazy, it's easy, and it is how I take notes now.</li>
<li>I don't want to spend a ton of time doing design work. I'm doing complicated designs for other projects, so I want to pull a theme I like that I can rely on someone else to keep up.</li>
<li>Once it gets going, I want template changes to be easy.</li>
<li>It should be as easy as Jekyll, so I need to be able to build it using GitHub Actions, where I can just commit a template change or Markdown file and away it goes. If I can't figure this out than fk it, just use Jekyll.</li>
<li>I require it to be used by a significant percent of my professional peers so I can get easy answers when something goes wrong.</li>
<li>I want source maps. This is a dev log site which means whatever I do with it should be easy for other developers to read.</li>
</ol>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Also <a href="https://www.npmjs.com/package/@quasibit/eleventy-plugin-sitemap" target="_blank">the sitemap plugin</a> looks cool. Should grab that later.</li>
</ul>
<s>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> So does the <a href="https://www.npmjs.com/package/eleventy-plugin-reading-time" target="_blank">reading time one</a>.</li>
</ul>
</s>
<ul class="task-list">
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Also <a href="https://github.com/jdsteinbach/eleventy-plugin-toc/" target="_blank">this TOC plugin</a> mby?</p>
</li>
<li class="task-list-item">
<p data-wordfix="true"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Use <a href="https://www.11ty.dev/docs/data-deep-merge/" target="_blank">Data Deep Merge</a> in this blog.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Decide if I want to render the CSS fancier than just a base file and do per-template splitting.</p>
</li>
</ul>
<s>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Can I use the template inside of dinky that already exists instead of copy/pasting it?</li>
</ul>
</s>
<s>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Is there a way to have permalinks to posts contain metadata without organizing them into subfolders?</li>
</ul>
</s>
<ul class="task-list">
<li class="task-list-item">
<p data-wordfix="true"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> How do I cachebreak files on the basis of new build events? Datetime? <code>site.github.build_revision</code> is <a href="https://github.com/jekyll/github-metadata/blob/master/docs/site.github.md" target="_blank">how Jekyll accomplishes this</a>, but is there a way to push <a href="https://docs.github.com/en/actions/reference/context-and-expression-syntax-for-github-actions#github-context" target="_blank">that</a> <a href="https://stackoverflow.com/questions/54310050/how-to-version-build-artifacts-using-github-actions" target="_blank">into the build process</a> for Eleventy?</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Make link text look less shitty. It looks like it is a whole, lighter, font.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Code blocks do not have good syntax highlighting. I want good syntax highlighting.</p>
</li>
<li class="task-list-item">
<p data-wordfix="true"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Build a Markdown-it plugin to take my typing shortcuts <code>[prob, b/c, ...?]</code> and expand them on build.</p>
</li>
</ul>
<s>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> See if we can start Markdown's interpretation of H tags to <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/Heading_Elements#multiple_h1" target="_blank">start at 2, since H1</a> is always pulled from the page title metadata. If it isn't easy, I just have to change my pattern of writing in the MD documents.</li>
</ul>
</s>
<ul class="task-list">
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Should I <a href="https://www.madebymike.com.au/writing/11ty-filters-data-shortcodes/" target="_blank">explore some shortcodes</a>?</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Order projects listing by last posted blog in that project</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Limit the output of home page post lists to a specific number of posts</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Show the latest post below the site intro on the homepage.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Tags pages with Pagination</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Posts should be able to support a preview header image that can also be shown on post lists.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Create a Markdown-It plugin that reads the project's repo URL off the folder data file and renders commit messages with <a href="https://stackoverflow.com/questions/15919635/on-github-api-what-is-the-best-way-to-get-the-last-commit-message-associated-w" target="_blank">links to the referenced commit</a>. (Is this even possible?) (Is there a way to do it with eleventy instead?)</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Create Next Day/Previous Day links on each post / Next/Previous post on post templates from projects</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Tags should be in the sidebar of articles and link to tag pages</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Create a skiplink for the todo section (or would this be better served with the ToC plugin?) - Yes it would be!</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Add a Things I Learned section to the project pages that are the things I learned from that specific project.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Add a technical reading log to the homepage</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/:empty" target="_blank">Hide</a> empty sections.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Add byline to post pages</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Have table of contents attach to sidebar bottom on mobile</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Support dark mode</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Social Icons</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> SEO/Social/JSON-LD HEAD data</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Create a per-project <code>/now</code> page.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Create a whole-site aggregated <code>/now</code> page.</p>
</li>
</ul>
<h2 id="day-44" tabindex="-1">Day 44</h2>
<p>My github actions were running on Node 12 apparently and GitHub doesn't support that anymore. Let's update to 16 as required.</p>
<p>I use <code>nvm</code> to manage my local project Node version so:</p>
<p><code>nvm use 16</code></p>
<p>I'm going to want to make sure I can build this locally first so:</p>
<p><code>npm ci</code></p>
<p><code>npm run build</code></p>
<p>Oh, that failed because I tried to use <code>sh</code> for one of my code blocks and that isn't a language supported by Prism. I'll switch that to <code>bash</code> instead and try again.</p>
<p><a target="_blank" href="https://github.com/AramZS/devblog/commit/6f2a8f9b817ca04d15b3b11e7818391e9c32cbb8" class="git-commit-link"><code>git commit -am &quot;Update project to 16&quot;</code></a></p>
<p>That worked!</p>
]]></content:encoded>
	</item>
	
	<item>
		<title>Day 5 - Iterate some dirs cast some hashmaps.</title>
		<link>https://fightwithtools.dev/posts/projects/notebook/day-5-iterate-some-dirs/?source=rss</link>
		<pubDate>Tue, 13 Jun 2023 02:59:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/projects/notebook/day-5-iterate-some-dirs/</guid>
		<description>Let's play with using Rust to process private to public notes.</description>
		<content:encoded><![CDATA[<h2 id="project-scope-and-todos" tabindex="-1">Project Scope and ToDos</h2>
<ol>
<li>Pull public-marked notes from the notebook to the new repo</li>
<li>Create website that treats them like a wiki and links pages together</li>
<li>Support the basic YAML in <a href="https://github.com/AramZS/notebook/blob/main/README.md" target="_blank">https://github.com/AramZS/notebook/blob/main/README.md</a></li>
</ol>
<h2 id="day-5" tabindex="-1">Day 5</h2>
<p>Ok, so I found the path. Now I can try and iterate through the files and folders in that path. First step, is it a folder at all?</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/notebook/day-5-iterate-some-dirs/#code-skip-day-5-iterate-some-dirs-4" id="skip-to-code-skip-day-5-iterate-some-dirs-4" class="skip-link">Skip code block ▼</a></p>
<pre class="language-rust"><code class="language-rust"><span class="token namespace">fs<span class="token punctuation">::</span></span><span class="token function">read_dir</span><span class="token punctuation">(</span>note_path<span class="token punctuation">)</span></code></pre>
<p id="code-skip-day-5-iterate-some-dirs-4">Ok, that should get the dir. But it also consumes the value. I think the best thing to do is <code>.clone</code> the variable so it can be used down the line. Now I need to do error handling and have an <code>else</code>. I can create a dir if none is found and if one isn't, I'll iterate through the files and folders in the path and find one. Then when I walk through that list I can figure out if it is a file or a folder and if it is a file I can process it with a function. I'll need more complex loops as well so I'll pull this into a function all its own later. For now, let's just get it working.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/notebook/day-5-iterate-some-dirs/#code-skip-day-5-iterate-some-dirs-3" id="skip-to-code-skip-day-5-iterate-some-dirs-3" class="skip-link">Skip code block ▼</a></p>
<pre class="language-rust"><code class="language-rust">    <span class="token keyword">if</span> <span class="token namespace">fs<span class="token punctuation">::</span></span><span class="token function">read_dir</span><span class="token punctuation">(</span>note_path<span class="token punctuation">.</span><span class="token function">clone</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">is_err</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />        <span class="token comment">// Create the notes directory if none is found.</span><br />        <span class="token macro property">println!</span><span class="token punctuation">(</span><span class="token string">"No notes directory found. Creating one now."</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />        <span class="token namespace">fs<span class="token punctuation">::</span></span><span class="token function">create_dir</span><span class="token punctuation">(</span>note_path<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">expect</span><span class="token punctuation">(</span><span class="token string">"Failed to create notes directory"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />    <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span><br />        <span class="token comment">// Parse the notes directory into an iterable object that we can walk through and take actions on.</span><br />        <span class="token namespace">fs<span class="token punctuation">::</span></span><span class="token function">read_dir</span><span class="token punctuation">(</span>note_path<span class="token punctuation">)</span><br />            <span class="token punctuation">.</span><span class="token function">and_then</span><span class="token punctuation">(</span><span class="token closure-params"><span class="token closure-punctuation punctuation">|</span>op<span class="token closure-punctuation punctuation">|</span></span> <span class="token punctuation">{</span><br />                <span class="token keyword">for</span> entry <span class="token keyword">in</span> op <span class="token punctuation">{</span><br />                    <span class="token keyword">let</span> entry <span class="token operator">=</span> entry<span class="token operator">?</span><span class="token punctuation">;</span><br />                    <span class="token keyword">let</span> path <span class="token operator">=</span> entry<span class="token punctuation">.</span><span class="token function">path</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />                    <span class="token macro property">println!</span><span class="token punctuation">(</span><span class="token string">"Name: {}"</span><span class="token punctuation">,</span> path<span class="token punctuation">.</span><span class="token function">display</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />                <span class="token punctuation">}</span><br />                <span class="token class-name">Ok</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><br />            <span class="token punctuation">}</span><span class="token punctuation">)</span><br />            <span class="token punctuation">.</span><span class="token function">expect</span><span class="token punctuation">(</span><span class="token string">"Failed to read notes directory"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />    <span class="token punctuation">}</span></code></pre>
<p id="code-skip-day-5-iterate-some-dirs-3">Ok, look at that. I have a list of directories and files! Now I need to detect if it is a dir or file and take the next step. It <a href="https://stackoverflow.com/questions/30309100/how-to-check-if-a-given-path-is-a-file-or-directory" target="_blank">looks like the <code>fs</code> library has a <code>metadata</code> function</a> that I can use to find out! Once I have that path, I can pass it to my function to parse it. I see there are some options for things I can do with that <code>path</code> var. Should I be using <a href="https://doc.rust-lang.org/std/ffi/struct.OsStr.html" target="_blank">OsStr</a>? What's the difference between that and a normal string? Why should I use it? It's pretty unclear.</p>
<p>Wait I just realized that I don't only have a bool value in public. My notes have the public YAML property with a bunch of different properties:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/notebook/day-5-iterate-some-dirs/#code-skip-day-5-iterate-some-dirs-2" id="skip-to-code-skip-day-5-iterate-some-dirs-2" class="skip-link">Skip code block ▼</a></p>
<pre class="language-markdown"><code class="language-markdown">- `public:` This note is intended to be published.<br />	- Notes marked `false` or with no value will never have any part published.<br />	- Notes marked `true` will have their whole body published along with metadata.<br />	- Notes marked `partial-public` will have any `:::{public} content :::` content blocks published and no metadata other than title.<br />	- Notes marked `partial-private` will have all content except for `:::{private} content :::` content blocks published and all metadata.<br />	- Notes marked `true` will also follow the `private` directives.</code></pre>
<p id="code-skip-day-5-iterate-some-dirs-2">Ok, so how do I deal--in a strongly typed system--with the fact that I have a value that can be more than one type? Wait... more than that, what happens where the property isn't there? I need to do a check.</p>
<p>It looks like in Rust the best way to parse an object with a set of defined but not consistent properties is a hashmap. The YAML library I'm using has a function to transform the YAML object into a linked hashmap. I can then use that to check for the property and then check the value of the property.</p>
<p>Huh... it's still not working. I have the LinkedHashMap but <code>contains_key</code> won't just take a string. It looks like I have to transform my key into a yaml-y string from looking at the code.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/notebook/day-5-iterate-some-dirs/#code-skip-day-5-iterate-some-dirs-1" id="skip-to-code-skip-day-5-iterate-some-dirs-1" class="skip-link">Skip code block ▼</a></p>
<pre class="language-rust"><code class="language-rust"><span class="token keyword">let</span> yamlHashmap <span class="token operator">=</span> <span class="token operator">&amp;</span>yamlObj<span class="token punctuation">.</span><span class="token function">as_hash</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">unwrap</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token keyword">let</span> keycheck <span class="token operator">=</span> yamlHashmap<span class="token punctuation">.</span><span class="token function">contains_key</span><span class="token punctuation">(</span><span class="token operator">&amp;</span><span class="token class-name">Yaml</span><span class="token punctuation">::</span><span class="token function">from_str</span><span class="token punctuation">(</span><span class="token string">"public"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p id="code-skip-day-5-iterate-some-dirs-1">Yeah, that works! I can check if the key exists now. And if it does I can start doing stuff with it. But will Rust let me cast it as a bool even when it has a value for the purposes of the first check? Can I do <code>if !keycheck || false == yamlObj[&quot;public&quot;].as_bool().unwrap()</code>?</p>
<p>Ok, I gotta get off the computer so I'll find out next workday!</p>
<p><code>git commit -am &quot;Improving md processer for my notes.&quot;</code></p>
]]></content:encoded>
	</item>
	
	<item>
		<title>Day 4 - Getting folders in here</title>
		<link>https://fightwithtools.dev/posts/projects/notebook/day-4-getting-folders-in-here/?source=rss</link>
		<pubDate>Fri, 26 May 2023 02:59:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/projects/notebook/day-4-getting-folders-in-here/</guid>
		<description>Let's play with using Rust to process private to public notes.</description>
		<content:encoded><![CDATA[<h2 id="project-scope-and-todos" tabindex="-1">Project Scope and ToDos</h2>
<ol>
<li>Pull public-marked notes from the notebook to the new repo</li>
<li>Create website that treats them like a wiki and links pages together</li>
<li>Support the basic YAML in <a href="https://github.com/AramZS/notebook/blob/main/README.md" target="_blank">https://github.com/AramZS/notebook/blob/main/README.md</a></li>
</ol>
<h2 id="day-4" tabindex="-1">Day 4</h2>
<p>I'd like to change <code>option_to_hold_file</code> to an ANY? I'm not sure how best to do that, but let's set up to actually do something that needs that process.</p>
<p>Ok, I'm at the point where I need to start scanning folders. Only one thing... I don't want to leak my folder structure from my system, so I need to store it as an environmental variable. What's the best way to do that? Does Rust have some equivalent of dotenv?</p>
<p>Looks like <a href="https://lib.rs/crates/dotenvy" target="_blank">it does</a>!</p>
<p>Ok, it loads, but I don't see any result. Have I misconfigured it or have I done something wrong?</p>
<p>Looks like the recommended way to run the function is <code>dotenvy::dotenv()?;</code> but that only gives the good result not the error. I can drop that question mark and get a <code>Result</code> object which I can check for an <code>ok</code> or an error.</p>
<p>Cool so now it looks like this:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/notebook/day-4-getting-folders-in-here/#code-skip-day-4-getting-folders-in-here-2" id="skip-to-code-skip-day-4-getting-folders-in-here-2" class="skip-link">Skip code block ▼</a></p>
<pre class="language-rust"><code class="language-rust"><span class="token keyword">let</span> env_result <span class="token operator">=</span> <span class="token namespace">dotenvy<span class="token punctuation">::</span></span><span class="token function">dotenv</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token keyword">if</span> <span class="token punctuation">(</span>env_result<span class="token punctuation">.</span><span class="token function">is_ok</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />	<span class="token macro property">dbg!</span><span class="token punctuation">(</span>env_result<span class="token punctuation">.</span><span class="token function">unwrap</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span><br />	<span class="token macro property">println!</span><span class="token punctuation">(</span><span class="token string">"Env tool failed"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token macro property">dbg!</span><span class="token punctuation">(</span>env_result<span class="token punctuation">.</span><span class="token function">unwrap</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span></code></pre>
<p id="code-skip-day-4-getting-folders-in-here-2">This does the bad thing I want it to do, which is I want it to freak out and stop execution and tell me what the heck the failure is.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/notebook/day-4-getting-folders-in-here/#code-skip-day-4-getting-folders-in-here-1" id="skip-to-code-skip-day-4-getting-folders-in-here-1" class="skip-link">Skip code block ▼</a></p>
<pre class="language-bash"><code class="language-bash">Env tool failed<br />thread <span class="token string">'main'</span> panicked at <span class="token string">'called `Result::unwrap()` on an `Err` value: LineParse("\"../../../Dropbox\\ \\(redacted)/redacted path to notes/Notes\"", 20)'</span>, src/main.rs:19:25<br />note: run with <span class="token variable"><span class="token variable">`</span><span class="token assign-left variable">RUST_BACKTRACE</span><span class="token operator">=</span><span class="token number">1</span><span class="token variable">`</span></span> environment variable to display a backtrace</code></pre>
<p id="code-skip-day-4-getting-folders-in-here-1">Likely not good error handling, but good at doing what I want, which is to give me a useful error.</p>
<p>Ok, so I <em>am</em> calling the function correctly but it doesn't like my string. I pulled that string from the autocomplete for the path by OSX. But perhaps it doesn't need to handle things that way. Ok. let's try some test strings.</p>
<p>Ok, removing the escaping required by OSX terminal does seem to make the string workable for this process. But can it give me a path to query the directory? Let's see!</p>
<p>Fun aside here: Though the rest of the ENV vars come out in alphabetical order when walking the keys, the one this adds gets put at the bottom of the list. Almost thought it didn't work when that happened, glad I checked.</p>
]]></content:encoded>
	</item>
	
	<item>
		<title>Day 3 - Back at it</title>
		<link>https://fightwithtools.dev/posts/projects/notebook/day-3-back-at-it/?source=rss</link>
		<pubDate>Thu, 11 May 2023 02:59:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/projects/notebook/day-3-back-at-it/</guid>
		<description>Let's play with using Rust to process private to public notes.</description>
		<content:encoded><![CDATA[<h2 id="project-scope-and-todos" tabindex="-1">Project Scope and ToDos</h2>
<ol>
<li>Pull public-marked notes from the notebook to the new repo</li>
<li>Create website that treats them like a wiki and links pages together</li>
<li>Support the basic YAML in <a href="https://github.com/AramZS/notebook/blob/main/README.md" target="_blank">https://github.com/AramZS/notebook/blob/main/README.md</a></li>
</ol>
<h2 id="day-3" tabindex="-1">Day 3</h2>
<p>Ok, I think I've got stuff basically working!</p>
<p><code>git commit -am &quot;Adding more conventions.&quot;</code></p>
<p>So I got the object, I can read metadata out of the file. Now I need to do something with that file! Step one, let's copy that file! I may want to edit it at the point of copying it over. I've read the file into a variable, so that should be the first step. Now how to write it?</p>
<p>First I want to check if the YAML public value is true. Hey, is this my first Rust <code>if</code> statement? I think so. Ok, so we cast it as <code>bool</code> and unrap it is what I'm seeing. Let's try that.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/notebook/day-3-back-at-it/#code-skip-day-3-back-at-it-2" id="skip-to-code-skip-day-3-back-at-it-2" class="skip-link">Skip code block ▼</a></p>
<pre class="language-rust"><code class="language-rust">    <span class="token keyword">if</span> yamlObj<span class="token punctuation">[</span><span class="token string">"public"</span><span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">as_bool</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">unwrap</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />        <span class="token macro property">println!</span><span class="token punctuation">(</span><span class="token string">"Public is true"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />    <span class="token punctuation">}</span></code></pre>
<p id="code-skip-day-3-back-at-it-2">Hey, it works! Ok, now I want to write it.</p>
<p>Ok, just like <code>node</code> there's a clearly labeled <code>fs</code> library. Looks like it has a basic <code>write</code> function. Let's give it a try!</p>
<p>I've been passing everything (pretty much) by reference. But I'm actually done with this variable, so good behavior would be to actually clear it out when I'm done with it. So I should pass it not by reference, right? Let's try that. I've used <code>expect</code> in the past to handle errors, but the documentation says it isn't the preferred way to handle it. It looks like <a href="https://doc.rust-lang.org/std/result/" target="_blank">there is chaining to handle errors</a> instead. Hmmm, whatever the syntax is supposed to be here, I'm not getting it right. I'll <a href="https://doc.rust-lang.org/rust-by-example/error/option_unwrap/and_then.html" target="_blank">have</a> <a href="https://web.mit.edu/rust-lang_v1.25/arch/amd64_ubuntu1404/share/doc/rust/html/book/first-edition/error-handling.html" target="_blank">to look</a> <a href="https://dev.to/nathan20/how-to-handle-errors-in-rust-a-comprehensive-guide-1cco" target="_blank">around</a>.</p>
<p>Ok, it might not be the right error handling process for this. It looks like <a href="https://dev.to/nathan20/how-to-handle-errors-in-rust-a-comprehensive-guide-1cco" target="_blank">perhaps</a> I could use a <code>?</code> after to early return an error. But that's not great, I want to do something with the error. So a control structure for that appears to be <a href="https://doc.rust-lang.org/book/ch06-02-match.html" target="_blank">match</a>. It looks like <a href="https://doc.rust-lang.org/book/ch09-02-recoverable-errors-with-result.html" target="_blank">this is the suggested way to handle errors in a recoverable way</a>.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/notebook/day-3-back-at-it/#code-skip-day-3-back-at-it-1" id="skip-to-code-skip-day-3-back-at-it-1" class="skip-link">Skip code block ▼</a></p>
<pre class="language-rust"><code class="language-rust">    <span class="token keyword">if</span> yamlObj<span class="token punctuation">[</span><span class="token string">"public"</span><span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">as_bool</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">unwrap</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />        <span class="token macro property">println!</span><span class="token punctuation">(</span><span class="token string">"Public is true"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />        <span class="token keyword">let</span> write_result <span class="token operator">=</span> <span class="token namespace">fs<span class="token punctuation">::</span></span><span class="token function">write</span><span class="token punctuation">(</span><span class="token string">"../src/notes/README.md"</span><span class="token punctuation">,</span> file_contents<span class="token punctuation">)</span><span class="token punctuation">;</span><br />        <span class="token keyword">let</span> written_file <span class="token operator">=</span> <span class="token keyword">match</span> write_result <span class="token punctuation">{</span><br />            <span class="token class-name">Ok</span><span class="token punctuation">(</span>file<span class="token punctuation">)</span> <span class="token operator">=></span> file<span class="token punctuation">,</span><br />            <span class="token class-name">Err</span><span class="token punctuation">(</span>error<span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token macro property">panic!</span><span class="token punctuation">(</span><span class="token string">"Problem opening the file: {:?}"</span><span class="token punctuation">,</span> error<span class="token punctuation">)</span><span class="token punctuation">,</span><br />        <span class="token punctuation">}</span><span class="token punctuation">;</span><br />    <span class="token punctuation">}</span></code></pre>
<p id="code-skip-day-3-back-at-it-1">Hey, look at that, I wrote a file! It works!</p>
<p><code>git commit -am &quot;Write a file, heck yes&quot;</code></p>
<p>And yeah, if <code>public</code> is <code>false</code> it won't write the file. Good first step!</p>
<p>Ok, what happens if <code>public</code> is not a bool, but is instead one of the directives I'm planning to use? How do I take a value that may or may not be a bool and handle it, optionally turning it into a <code>bool</code> or using it like a <code>bool</code>? I think the right answer is using <code>match</code>?</p>
<p>Maybe not, I think I can use <a href="https://doc.rust-lang.org/std/any/trait.Any.html" target="_blank"><code>Any</code></a> and either <a href="https://doc.rust-lang.org/std/any/trait.Any.html#method.downcast-1" target="_blank"><code>downcast</code></a> it or <a href="https://doc.rust-lang.org/std/boxed/struct.Box.html#method.downcast" target="_blank">handle it in a <code>Box</code></a>.</p>
]]></content:encoded>
	</item>
	
	<item>
		<title>Day 2 - More Futzing</title>
		<link>https://fightwithtools.dev/posts/projects/notebook/day-2-more-futzing/?source=rss</link>
		<pubDate>Wed, 15 Mar 2023 02:59:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/projects/notebook/day-2-more-futzing/</guid>
		<description>Let's play with using Rust to process private to public notes.</description>
		<content:encoded><![CDATA[<h2 id="project-scope-and-todos" tabindex="-1">Project Scope and ToDos</h2>
<ol>
<li>Pull public-marked notes from the notebook to the new repo</li>
<li>Create website that treats them like a wiki and links pages together</li>
<li>Support the basic YAML in <a href="https://github.com/AramZS/notebook/blob/main/README.md" target="_blank">https://github.com/AramZS/notebook/blob/main/README.md</a></li>
</ol>
<h2 id="day-2" tabindex="-1">Day 2</h2>
<p>Ok, let's play around with Rust some more and see what we can figure out while futzing around blind. We have to figure out how to handle this object.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/notebook/day-2-more-futzing/#code-skip-day-2-more-futzing-1" id="skip-to-code-skip-day-2-more-futzing-1" class="skip-link">Skip code block ▼</a></p>
<pre class="language-bash"><code class="language-bash"><span class="token punctuation">[</span>src/main.rs:91<span class="token punctuation">]</span> yaml_test_result <span class="token operator">=</span> Ok<span class="token punctuation">(</span><br />    Some<span class="token punctuation">(</span><br />        Hash<span class="token punctuation">(</span><br />            <span class="token punctuation">{</span><br />                String<span class="token punctuation">(</span><br />                    <span class="token string">"aliases"</span>,<br />                <span class="token punctuation">)</span>: Array<span class="token punctuation">(</span><br />                    <span class="token punctuation">[</span><br />                        String<span class="token punctuation">(</span><br />                            <span class="token string">"Note Publisher"</span>,<br />                        <span class="token punctuation">)</span>,<br />                        String<span class="token punctuation">(</span><br />                            <span class="token string">"NotePub"</span>,<br />                        <span class="token punctuation">)</span>,<br />                        String<span class="token punctuation">(</span><br />                            <span class="token string">"NotePublisher"</span>,<br />                        <span class="token punctuation">)</span>,<br />                        String<span class="token punctuation">(</span><br />                            <span class="token string">"Notebook"</span>,<br />                        <span class="token punctuation">)</span>,<br />                    <span class="token punctuation">]</span>,<br />                <span class="token punctuation">)</span>,<br />                String<span class="token punctuation">(</span><br />                    <span class="token string">"public"</span>,<br />                <span class="token punctuation">)</span>: Boolean<span class="token punctuation">(</span><br />                    true,<br />                <span class="token punctuation">)</span>,<br />            <span class="token punctuation">}</span>,<br />        <span class="token punctuation">)</span>,<br />    <span class="token punctuation">)</span>,<br /><span class="token punctuation">)</span></code></pre>
<p id="code-skip-day-2-more-futzing-1"><code>Ok</code> is a way to handle error checking. <a href="https://doc.rust-lang.org/std/result/" target="_blank">Useful info on how to deal with it here</a>. It looks like I want to check it, then <code>unwrap()</code> it. Ok. I also have to remove the first <code>dbg!</code> because it takes ownership of the <code>yaml_test_result</code> object.</p>
<p>Next, what to do with <code>Some</code>? It appears to be a way to return a legitimate response from a function when it could also potentially respond with a null value, since <a href="https://stackoverflow.com/questions/24771655/what-are-some-and-none" target="_blank">there isn't another way to hold that according to stack overflow</a>. Rust has some useful tools for processing <code>Some</code> it seems!</p>
<blockquote>
<p>Ending the expression with ? will result in the Some’s unwrapped value, unless the result is None, in which case None is returned early from the enclosing function.</p>
</blockquote>
<p data-wordfix="true">Hmmmm. That's not quite right. It looks like we probably need to further unwrap it? Perhaps with <code>unwrap_or_else</code>? Hmmmm, not sure how to use that. I could just <code>unwrap</code> again and deal with the Hash, but that probably isn't good handling.</p>
<p><code>git commit -am &quot;Continuing to figure out rust&quot;</code></p>
]]></content:encoded>
	</item>
	
	<item>
		<title>Day 1 - We try new things.</title>
		<link>https://fightwithtools.dev/posts/projects/notebook/day-1-try-new-things/?source=rss</link>
		<pubDate>Fri, 10 Mar 2023 02:59:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/projects/notebook/day-1-try-new-things/</guid>
		<description>Let's play with using Rust to process private to public notes.</description>
		<content:encoded><![CDATA[<h2 id="project-scope-and-todos" tabindex="-1">Project Scope and ToDos</h2>
<ol>
<li>Pull public-marked notes from the notebook to the new repo</li>
<li>Create website that treats them like a wiki and links pages together</li>
<li>Support the basic YAML in <a href="https://github.com/AramZS/notebook/blob/main/README.md" target="_blank">https://github.com/AramZS/notebook/blob/main/README.md</a></li>
</ol>
<h2 id="day-1" tabindex="-1">Day 1</h2>
<p>I have a private Notes file, but I want to start making some of those files public so other people can use the notes files that might be helpful. I also want to connect with folks involved in the <a href="https://www.fellowshipofthelink.org/" target="_blank">Fellowship of the Link</a> project who are putting together similar notes and personal knowledge management sites.</p>
<p>I also want to move forward with learning new things! So let's start with something cool - Rust. Everyone is doing stuff with Rust lately. I want to pick it up. Ok. So <a href="https://www.rust-lang.org/learn/get-started" target="_blank">we start at the beginning</a>.</p>
<p>Let's go with the basics!</p>
<p><code>curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh</code></p>
<p><code>1</code> to do a basic install.</p>
<p>I want to add it to <code>zsh</code>, which is my CLI tool of choice.</p>
<p>I can add it to my <code>export PATH=</code> setup. Just slip <code>$HOME/.cargo/env</code> in there.</p>
<p>Ok. <code>cargo new notebox</code>. Set it up.</p>
<p>It isn't running however.</p>
<p><code>xcrun: error: invalid active developer path (/Library/Developer/CommandLineTools), missing xcrun at: /Library/Developer/CommandLineTools/usr/bin/xcrun</code></p>
<p><a href="https://developer.apple.com/forums/thread/711512" target="_blank">Looks like I may need to update xcode</a>.</p>
<p>Ok that works.</p>
<p>Next: we'll need to <a href="https://blog.logrocket.com/how-to-read-files-rust/" target="_blank">read some files</a> and parse some Markdown!</p>
<p>Let's <a href="https://lib.rs/search?q=commonmark" target="_blank">look</a> at <a href="https://crates.io/keywords/markdown" target="_blank">some options</a></p>
<p>I think, for the sake of trying stuff out here, we'll try <a href="https://lib.rs/crates/pulldown-cmark" target="_blank"><code>pulldown-cmark</code></a> and <a href="https://github.com/kivikakk/comrak" target="_blank"><code>comrak</code></a>.</p>
<p>For <code>pulldown-cmark</code> we'll try one of their <a href="https://github.com/raphlinus/pulldown-cmark/blob/master/examples/string-to-string.rs" target="_blank">examples</a>.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/notebook/day-1-try-new-things/#code-skip-day-1-try-new-things-6" id="skip-to-code-skip-day-1-try-new-things-6" class="skip-link">Skip code block ▼</a></p>
<pre class="language-rust"><code class="language-rust"><span class="token keyword">use</span> <span class="token namespace">pulldown_cmark<span class="token punctuation">::</span></span><span class="token punctuation">{</span>html<span class="token punctuation">,</span> <span class="token class-name">Options</span><span class="token punctuation">,</span> <span class="token class-name">Parser</span><span class="token punctuation">}</span><span class="token punctuation">;</span><br /><br /><span class="token keyword">fn</span> <span class="token function-definition function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />    <span class="token keyword">let</span> markdown_input<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token keyword">str</span> <span class="token operator">=</span> <span class="token string">"Hello world, this is a ~~complicated~~ *very simple* example."</span><span class="token punctuation">;</span><br />    <span class="token macro property">println!</span><span class="token punctuation">(</span><span class="token string">"Parsing the following markdown string:\n{}"</span><span class="token punctuation">,</span> markdown_input<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br />    <span class="token comment">// Set up options and parser. Strikethroughs are not part of the CommonMark standard</span><br />    <span class="token comment">// and we therefore must enable it explicitly.</span><br />    <span class="token keyword">let</span> <span class="token keyword">mut</span> options <span class="token operator">=</span> <span class="token class-name">Options</span><span class="token punctuation">::</span><span class="token function">empty</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />    options<span class="token punctuation">.</span><span class="token function">insert</span><span class="token punctuation">(</span><span class="token class-name">Options</span><span class="token punctuation">::</span><span class="token constant">ENABLE_STRIKETHROUGH</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />    <span class="token keyword">let</span> parser <span class="token operator">=</span> <span class="token class-name">Parser</span><span class="token punctuation">::</span><span class="token function">new_ext</span><span class="token punctuation">(</span>markdown_input<span class="token punctuation">,</span> options<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br />    <span class="token comment">// Write to String buffer.</span><br />    <span class="token keyword">let</span> <span class="token keyword">mut</span> html_output<span class="token punctuation">:</span> <span class="token class-name">String</span> <span class="token operator">=</span> <span class="token class-name">String</span><span class="token punctuation">::</span><span class="token function">with_capacity</span><span class="token punctuation">(</span>markdown_input<span class="token punctuation">.</span><span class="token function">len</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">*</span> <span class="token number">3</span> <span class="token operator">/</span> <span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />    <span class="token namespace">html<span class="token punctuation">::</span></span><span class="token function">push_html</span><span class="token punctuation">(</span><span class="token operator">&amp;</span><span class="token keyword">mut</span> html_output<span class="token punctuation">,</span> parser<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br />    <span class="token comment">// Check that the output is what we expected.</span><br />    <span class="token keyword">let</span> expected_html<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token keyword">str</span> <span class="token operator">=</span><br />        <span class="token string">"&lt;p>Hello world, this is a &lt;del>complicated&lt;/del> &lt;em>very simple&lt;/em> example.&lt;/p>\n"</span><span class="token punctuation">;</span><br />    <span class="token macro property">assert_eq!</span><span class="token punctuation">(</span>expected_html<span class="token punctuation">,</span> <span class="token operator">&amp;</span>html_output<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br />    <span class="token comment">// Write result to stdout.</span><br />    <span class="token macro property">println!</span><span class="token punctuation">(</span><span class="token string">"\nHTML output:\n{}"</span><span class="token punctuation">,</span> <span class="token operator">&amp;</span>html_output<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span></code></pre>
<p id="code-skip-day-1-try-new-things-6">Ok, that worked! A good sign. Let's pull the document file we want out of the file and into the string. We'll start with the README.</p>
<p>What can I learn from reading the code while I do this?</p>
<p>Well, it looks like one can do Rust typed. <code>: &amp;str</code> at the end of the var decleration seems to indicate an expected type. It <a href="https://doc.rust-lang.org/std/primitive.str.html" target="_blank">isn't a normal string</a>, not like what I get out of the <code>fs::read_to_string</code> function though. I can expect a <a href="https://doc.rust-lang.org/std/string/struct.String.html" target="_blank"><code>String</code></a> out of the <code>fs</code> function it seems.</p>
<p>However, the Markdown parser expects the simpler type of string. I'll need to transform it. Looks like there's an easy way to handle this issue listed in the docs:</p>
<blockquote>
<p><code>String</code> implements <code>Deref&lt;Target = str&gt;</code>, and so inherits all of <code>str</code>’s methods. In addition, this means that you can pass a String to a function which takes a &amp;str by using an ampersand (&amp;)</p>
</blockquote>
<p>Ok! This works:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/notebook/day-1-try-new-things/#code-skip-day-1-try-new-things-5" id="skip-to-code-skip-day-1-try-new-things-5" class="skip-link">Skip code block ▼</a></p>
<pre class="language-rust"><code class="language-rust"><span class="token keyword">use</span> <span class="token namespace">pulldown_cmark<span class="token punctuation">::</span></span><span class="token punctuation">{</span>html<span class="token punctuation">,</span> <span class="token class-name">Options</span><span class="token punctuation">,</span> <span class="token class-name">Parser</span><span class="token punctuation">}</span><span class="token punctuation">;</span><br /><span class="token keyword">use</span> <span class="token namespace">std<span class="token punctuation">::</span></span>fs<span class="token punctuation">;</span><br /><br /><span class="token keyword">fn</span> <span class="token function-definition function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />	<span class="token keyword">let</span> file_contents<span class="token punctuation">:</span> <span class="token class-name">String</span> <span class="token operator">=</span> <span class="token namespace">fs<span class="token punctuation">::</span></span><span class="token function">read_to_string</span><span class="token punctuation">(</span><span class="token string">"../README.md"</span><span class="token punctuation">)</span><br />        <span class="token punctuation">.</span><span class="token function">expect</span><span class="token punctuation">(</span><span class="token string">"LogRocket: Should have been able to read the file"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />    <span class="token keyword">let</span> markdown_input<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token keyword">str</span> <span class="token operator">=</span> <span class="token operator">&amp;</span>file_contents<span class="token punctuation">;</span><br />    <span class="token macro property">println!</span><span class="token punctuation">(</span><span class="token string">"Parsing the following markdown string:\n{}"</span><span class="token punctuation">,</span> markdown_input<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br />    <span class="token comment">// Set up options and parser. Strikethroughs are not part of the CommonMark standard</span><br />    <span class="token comment">// and we therefore must enable it explicitly.</span><br />    <span class="token keyword">let</span> <span class="token keyword">mut</span> options <span class="token operator">=</span> <span class="token class-name">Options</span><span class="token punctuation">::</span><span class="token function">empty</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />    options<span class="token punctuation">.</span><span class="token function">insert</span><span class="token punctuation">(</span><span class="token class-name">Options</span><span class="token punctuation">::</span><span class="token constant">ENABLE_STRIKETHROUGH</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />    <span class="token keyword">let</span> parser <span class="token operator">=</span> <span class="token class-name">Parser</span><span class="token punctuation">::</span><span class="token function">new_ext</span><span class="token punctuation">(</span>markdown_input<span class="token punctuation">,</span> options<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br />    <span class="token comment">// Write to String buffer.</span><br />    <span class="token keyword">let</span> <span class="token keyword">mut</span> html_output<span class="token punctuation">:</span> <span class="token class-name">String</span> <span class="token operator">=</span> <span class="token class-name">String</span><span class="token punctuation">::</span><span class="token function">with_capacity</span><span class="token punctuation">(</span>markdown_input<span class="token punctuation">.</span><span class="token function">len</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">*</span> <span class="token number">3</span> <span class="token operator">/</span> <span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />    <span class="token namespace">html<span class="token punctuation">::</span></span><span class="token function">push_html</span><span class="token punctuation">(</span><span class="token operator">&amp;</span><span class="token keyword">mut</span> html_output<span class="token punctuation">,</span> parser<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br />    <span class="token comment">// Check that the output is what we expected.</span><br />    <span class="token comment">// let expected_html: &amp;str =</span><br />    <span class="token comment">//     "&lt;p>Hello world, this is a &lt;del>complicated&lt;/del> &lt;em>very simple&lt;/em> example.&lt;/p>\n";</span><br />    <span class="token comment">// assert_eq!(expected_html, &amp;html_output);</span><br /><br />    <span class="token comment">// Write result to stdout.</span><br />    <span class="token macro property">println!</span><span class="token punctuation">(</span><span class="token string">"\nHTML output:\n{}"</span><span class="token punctuation">,</span> <span class="token operator">&amp;</span>html_output<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span></code></pre>
<p id="code-skip-day-1-try-new-things-5">But it doesn't parse out the YAML headmatter which isn't great!</p>
<p>Between <code>pulldown_cmark</code> being old and not seeming to be interested in supporting <code>YAML</code> and the fact that there doesn't appear to be a big community interested in resolving that problem I'm not particularly inclined to resolve this issue.</p>
<p>Let's try the next tool.</p>
<p>Looking at the ways it can be rendered now. Interesting. I hadn't realized it but <code>println!</code> takes a string and has a way to deliver an argument into the string at the position of <code>{}</code>;</p>
<p>Ok, this works:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/notebook/day-1-try-new-things/#code-skip-day-1-try-new-things-4" id="skip-to-code-skip-day-1-try-new-things-4" class="skip-link">Skip code block ▼</a></p>
<pre class="language-rust"><code class="language-rust"><span class="token keyword">extern</span> <span class="token keyword">crate</span> <span class="token module-declaration namespace">comrak</span><span class="token punctuation">;</span><br /><span class="token keyword">use</span> <span class="token namespace">comrak<span class="token punctuation">::</span></span><span class="token punctuation">{</span>markdown_to_html<span class="token punctuation">,</span> parse_document<span class="token punctuation">,</span> format_html<span class="token punctuation">,</span> <span class="token class-name">Arena</span><span class="token punctuation">,</span> <span class="token class-name">ComrakOptions</span><span class="token punctuation">}</span><span class="token punctuation">;</span><br /><span class="token keyword">use</span> <span class="token namespace">comrak<span class="token punctuation">::</span>nodes<span class="token punctuation">::</span></span><span class="token punctuation">{</span><span class="token class-name">AstNode</span><span class="token punctuation">,</span> <span class="token class-name">NodeValue</span><span class="token punctuation">}</span><span class="token punctuation">;</span><br /><span class="token keyword">use</span> <span class="token namespace">std<span class="token punctuation">::</span></span>fs<span class="token punctuation">;</span><br /><br /><span class="token keyword">fn</span> <span class="token function-definition function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />	<span class="token keyword">let</span> file_contents<span class="token punctuation">:</span> <span class="token class-name">String</span> <span class="token operator">=</span> <span class="token namespace">fs<span class="token punctuation">::</span></span><span class="token function">read_to_string</span><span class="token punctuation">(</span><span class="token string">"../README.md"</span><span class="token punctuation">)</span><br />        <span class="token punctuation">.</span><span class="token function">expect</span><span class="token punctuation">(</span><span class="token string">"LogRocket: Should have been able to read the file"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />    <span class="token keyword">let</span> markdown_input<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token keyword">str</span> <span class="token operator">=</span> <span class="token operator">&amp;</span>file_contents<span class="token punctuation">;</span><br />    <span class="token comment">// println!("Parsing the following markdown string:\n{}", markdown_input);</span><br /><br />	<span class="token comment">// The returned nodes are created in the supplied Arena, and are bound by its lifetime.</span><br />	<span class="token keyword">let</span> arena <span class="token operator">=</span> <span class="token class-name">Arena</span><span class="token punctuation">::</span><span class="token function">new</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br />	<span class="token keyword">let</span> root <span class="token operator">=</span> <span class="token function">parse_document</span><span class="token punctuation">(</span><br />		<span class="token operator">&amp;</span>arena<span class="token punctuation">,</span><br />		<span class="token string">"This is my input.\n\n1. Also my input.\n2. Certainly my input.\n"</span><span class="token punctuation">,</span><br />		<span class="token operator">&amp;</span><span class="token class-name">ComrakOptions</span><span class="token punctuation">::</span><span class="token function">default</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br />	<span class="token keyword">fn</span> <span class="token function-definition function">iter_nodes</span><span class="token operator">&lt;</span><span class="token lifetime-annotation symbol">'a</span><span class="token punctuation">,</span> <span class="token class-name">F</span><span class="token operator">></span><span class="token punctuation">(</span>node<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token lifetime-annotation symbol">'a</span> <span class="token class-name">AstNode</span><span class="token operator">&lt;</span><span class="token lifetime-annotation symbol">'a</span><span class="token operator">></span><span class="token punctuation">,</span> f<span class="token punctuation">:</span> <span class="token operator">&amp;</span><span class="token class-name">F</span><span class="token punctuation">)</span><br />		<span class="token keyword">where</span> <span class="token class-name">F</span> <span class="token punctuation">:</span> <span class="token class-name">Fn</span><span class="token punctuation">(</span><span class="token operator">&amp;</span><span class="token lifetime-annotation symbol">'a</span> <span class="token class-name">AstNode</span><span class="token operator">&lt;</span><span class="token lifetime-annotation symbol">'a</span><span class="token operator">></span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />		<span class="token function">f</span><span class="token punctuation">(</span>node<span class="token punctuation">)</span><span class="token punctuation">;</span><br />		<span class="token keyword">for</span> c <span class="token keyword">in</span> node<span class="token punctuation">.</span><span class="token function">children</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />			<span class="token function">iter_nodes</span><span class="token punctuation">(</span>c<span class="token punctuation">,</span> f<span class="token punctuation">)</span><span class="token punctuation">;</span><br />		<span class="token punctuation">}</span><br />	<span class="token punctuation">}</span><br /><br />	<span class="token function">iter_nodes</span><span class="token punctuation">(</span>root<span class="token punctuation">,</span> <span class="token operator">&amp;</span><span class="token closure-params"><span class="token closure-punctuation punctuation">|</span>node<span class="token closure-punctuation punctuation">|</span></span> <span class="token punctuation">{</span><br />		<span class="token keyword">match</span> <span class="token operator">&amp;</span><span class="token keyword">mut</span> node<span class="token punctuation">.</span>data<span class="token punctuation">.</span><span class="token function">borrow_mut</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span>value <span class="token punctuation">{</span><br />			<span class="token operator">&amp;</span><span class="token keyword">mut</span> <span class="token class-name">NodeValue</span><span class="token punctuation">::</span><span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token keyword">ref</span> <span class="token keyword">mut</span> text<span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />				<span class="token keyword">let</span> orig <span class="token operator">=</span> <span class="token namespace">std<span class="token punctuation">::</span>mem<span class="token punctuation">::</span></span><span class="token function">replace</span><span class="token punctuation">(</span>text<span class="token punctuation">,</span> <span class="token macro property">vec!</span><span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />				<span class="token operator">*</span>text <span class="token operator">=</span> <span class="token class-name">String</span><span class="token punctuation">::</span><span class="token function">from_utf8</span><span class="token punctuation">(</span>orig<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">unwrap</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span><span class="token string">"my"</span><span class="token punctuation">,</span> <span class="token string">"your"</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">as_bytes</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">to_vec</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />			<span class="token punctuation">}</span><br />			_ <span class="token operator">=></span> <span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br />		<span class="token punctuation">}</span><br />	<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br />	<span class="token keyword">let</span> <span class="token keyword">mut</span> html <span class="token operator">=</span> <span class="token macro property">vec!</span><span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span><br />	<span class="token function">format_html</span><span class="token punctuation">(</span>root<span class="token punctuation">,</span> <span class="token operator">&amp;</span><span class="token class-name">ComrakOptions</span><span class="token punctuation">::</span><span class="token function">default</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token operator">&amp;</span><span class="token keyword">mut</span> html<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">unwrap</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br />	<span class="token keyword">let</span> result <span class="token operator">=</span> <span class="token class-name">String</span><span class="token punctuation">::</span><span class="token function">from_utf8</span><span class="token punctuation">(</span>html<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">unwrap</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br />	<span class="token macro property">assert_eq!</span><span class="token punctuation">(</span><br />		result<span class="token punctuation">,</span><br />		<span class="token string">"&lt;p>This is your input.&lt;/p>\n\<br />		 &lt;ol>\n\<br />		 &lt;li>Also your input.&lt;/li>\n\<br />		 &lt;li>Certainly your input.&lt;/li>\n\<br />		 &lt;/ol>\n"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br />	<span class="token keyword">let</span> basic_result <span class="token operator">=</span> <span class="token function">markdown_to_html</span><span class="token punctuation">(</span><span class="token string">"Hello, **世界**!"</span><span class="token punctuation">,</span> <span class="token operator">&amp;</span><span class="token class-name">ComrakOptions</span><span class="token punctuation">::</span><span class="token function">default</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token macro property">assert_eq!</span><span class="token punctuation">(</span>basic_result<span class="token punctuation">,</span><br />		 <span class="token string">"&lt;p>Hello, &lt;strong>世界&lt;/strong>!&lt;/p>\n"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br />	<span class="token macro property">println!</span><span class="token punctuation">(</span><span class="token string">"\nHTML output:\n"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token macro property">println!</span><span class="token punctuation">(</span><span class="token string">"{}"</span><span class="token punctuation">,</span> result<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br />	<span class="token macro property">println!</span><span class="token punctuation">(</span><span class="token string">"\nBasic HTML output:\n{}"</span><span class="token punctuation">,</span> basic_result<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span></code></pre>
<p id="code-skip-day-1-try-new-things-4">Both ways allow you to render HTML. It looks good! Now let's take a look at the YAML parsing processs.</p>
<p>Hmmmm, I tried adding:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/notebook/day-1-try-new-things/#code-skip-day-1-try-new-things-3" id="skip-to-code-skip-day-1-try-new-things-3" class="skip-link">Skip code block ▼</a></p>
<pre class="language-rust"><code class="language-rust">	<span class="token keyword">let</span> file_result <span class="token operator">=</span> <span class="token function">markdown_to_html</span><span class="token punctuation">(</span>markdown_input<span class="token punctuation">,</span> <span class="token operator">&amp;</span><span class="token class-name">ComrakOptions</span><span class="token punctuation">::</span><span class="token function">default</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token macro property">println!</span><span class="token punctuation">(</span><span class="token string">"\nFile HTML output:\n{}"</span><span class="token punctuation">,</span> file_result<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p id="code-skip-day-1-try-new-things-3">But the output seems to just include the YAML frontmatter as HTML. Not at all what I had hoped. Ok is there a way to handle this using the Comrak package? Yeah! <a href="https://whoisryosuke.com/blog/2022/create-a-markdown-editor-using-rust-and-react/" target="_blank">It looks like I wasn't the only one looking at doing this</a>!</p>
<p>Ok, looking through how this works and realizing this changes in place.</p>
<p>I think I can zero out all the text and just output the FrontMatter in theory <a href="https://lib.rs/crates/yaml-rust" target="_blank">to process</a>. I suppose I could just pull it out. <a href="https://github.com/azdle/rust-frontmatter/blob/master/src/lib.rs" target="_blank">It looks like someone else has tried that</a>.</p>
<p>The problem is that I want to replace in-place the various blocks. The way this seems to be done in Rust is with <code>std::mem::replace(blocks, vec![]);</code>. But when the block does not have a <code>vec</code> type but instead a more complex type it will refuse to run the program. Perhaps I can just pull it out outside the function?</p>
<p>No, that doesn't work.</p>
<p>I want to try to figure this out using the tool at hand. I think it would be interesting. How can I best zero out those blocks? Could I use <code>std::mem::forget</code>?</p>
<p>Doesn't seem to work.</p>
<p>Oh look though I can do <code>*text = vec![];</code> to eliminate the Text nodes. I'm guessing it reassigns it back to the node effectively?</p>
<p>It looks like I <em>could</em> replace it with a default using <code>Default::default()</code> or <code>std::mem::take</code>, but there's no way to do so right now because the crate doesn't define a default state. Interesting!</p>
<p>Ok, well, this is almost enough for now. Let's try that frontmatter package: <code>cargo add frontmatter</code>.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/notebook/day-1-try-new-things/#code-skip-day-1-try-new-things-2" id="skip-to-code-skip-day-1-try-new-things-2" class="skip-link">Skip code block ▼</a></p>
<pre class="language-rust"><code class="language-rust">    <span class="token keyword">let</span> yaml_test_result <span class="token operator">=</span> <span class="token namespace">frontmatter<span class="token punctuation">::</span></span><span class="token function">parse</span><span class="token punctuation">(</span>markdown_input<span class="token punctuation">)</span><span class="token punctuation">;</span><br />    <span class="token macro property">dbg!</span><span class="token punctuation">(</span>yaml_test_result<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p id="code-skip-day-1-try-new-things-2">Looks like it works? I don't know the <code>dbg</code> output what is shown when I do <code>cargo run</code> in the CLI well enough to fully understand what is happening here.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/notebook/day-1-try-new-things/#code-skip-day-1-try-new-things-1" id="skip-to-code-skip-day-1-try-new-things-1" class="skip-link">Skip code block ▼</a></p>
<pre class="language-bash"><code class="language-bash"><span class="token punctuation">[</span>src/main.rs:91<span class="token punctuation">]</span> yaml_test_result <span class="token operator">=</span> Ok<span class="token punctuation">(</span><br />    Some<span class="token punctuation">(</span><br />        Hash<span class="token punctuation">(</span><br />            <span class="token punctuation">{</span><br />                String<span class="token punctuation">(</span><br />                    <span class="token string">"aliases"</span>,<br />                <span class="token punctuation">)</span>: Array<span class="token punctuation">(</span><br />                    <span class="token punctuation">[</span><br />                        String<span class="token punctuation">(</span><br />                            <span class="token string">"Note Publisher"</span>,<br />                        <span class="token punctuation">)</span>,<br />                        String<span class="token punctuation">(</span><br />                            <span class="token string">"NotePub"</span>,<br />                        <span class="token punctuation">)</span>,<br />                        String<span class="token punctuation">(</span><br />                            <span class="token string">"NotePublisher"</span>,<br />                        <span class="token punctuation">)</span>,<br />                        String<span class="token punctuation">(</span><br />                            <span class="token string">"Notebook"</span>,<br />                        <span class="token punctuation">)</span>,<br />                    <span class="token punctuation">]</span>,<br />                <span class="token punctuation">)</span>,<br />                String<span class="token punctuation">(</span><br />                    <span class="token string">"public"</span>,<br />                <span class="token punctuation">)</span>: Boolean<span class="token punctuation">(</span><br />                    true,<br />                <span class="token punctuation">)</span>,<br />            <span class="token punctuation">}</span>,<br />        <span class="token punctuation">)</span>,<br />    <span class="token punctuation">)</span>,<br /><span class="token punctuation">)</span></code></pre>
<p id="code-skip-day-1-try-new-things-1">Ok, well, I found out a whole bunch of random interesting stuff about Rust, so mission accomplished in that sense! We'll get back to processing this later.</p>
<p><code>git commit -am &quot;Wild and potentially useless experementation&quot;</code></p>
]]></content:encoded>
	</item>
	
	<item>
		<title>Context Center Timelines - Day 21 - Slug Fixes.</title>
		<link>https://fightwithtools.dev/posts/projects/context-timelines/day-21-slug-fixes/?source=rss</link>
		<pubDate>Tue, 21 Feb 2023 02:59:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/projects/context-timelines/day-21-slug-fixes/</guid>
		<description>One slug to rule them, one url path to bind them, one permalink to find them all and in the darkness bind them.</description>
		<content:encoded><![CDATA[<h2 id="project-scope-and-todos" tabindex="-1">Project Scope and ToDos</h2>
<ol>
<li>Create timeline pages where one can see the whole timeline of a particular event</li>
<li>Give timeline items type or category icons so that you can easily scan what is happening.</li>
<li>Allow the user to enter the timeline at any individually sharable link of an event and seamlessly scroll up and down</li>
</ol>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Deliver timelines as a plugin that can be extended by other Eleventy users</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Auto-create social-media-ready screenshots of a timeline item</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Integrate with Contexter to have context-full link cards in the timeline</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Leverage the Live Blog format of Schema dot org</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Allow each entry to be its own Markdown file</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Handle SASS instead of CSS</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Fast Scroller by Month and Year</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Add timelines and individual timeline items to the sitemap</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Generate images more efficiently.</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Support a counter that can increment depending on where you are on the timeline.</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Generate QR codes / Stickers for each timeline</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> /raw/md returns a raw version of a topic (in markdown)</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> /raw/md includes a YAML header with relevant information</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> /raw/json returns a JSON version of a topic</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> /feed/ returns a latest links feed of a topic</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> RSS feed of links</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> RSS feed of new links per topic / timeline</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Support a header image.</li>
</ul>
<h2 id="day-21" tabindex="-1">Day 21</h2>
<p>Ok, so it looks like it is just the skiplink slug that is inconsistent with the rest of the site. But just in case, I'm going to do my own slug function and run all the timeline stuff through that. I can separate it out into a file and import it everywhere I need it and as a template filter.</p>
<p><code>git commit -am &quot;Fixing to a consistent slugging process&quot;</code></p>
]]></content:encoded>
	</item>
	
	<item>
		<title>Context Center Timelines - Day 20 - Liveblog Schema Metadata and SEO and Image fixes.</title>
		<link>https://fightwithtools.dev/posts/projects/context-timelines/day-20-liveblog-metadata-and-fixes/?source=rss</link>
		<pubDate>Tue, 21 Feb 2023 02:59:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/projects/context-timelines/day-20-liveblog-metadata-and-fixes/</guid>
		<description>Meta for metadata.</description>
		<content:encoded><![CDATA[<h2 id="project-scope-and-todos" tabindex="-1">Project Scope and ToDos</h2>
<ol>
<li>Create timeline pages where one can see the whole timeline of a particular event</li>
<li>Give timeline items type or category icons so that you can easily scan what is happening.</li>
<li>Allow the user to enter the timeline at any individually sharable link of an event and seamlessly scroll up and down</li>
</ol>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Deliver timelines as a plugin that can be extended by other Eleventy users</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Auto-create social-media-ready screenshots of a timeline item</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Integrate with Contexter to have context-full link cards in the timeline</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Leverage the Live Blog format of Schema dot org</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Allow each entry to be its own Markdown file</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Handle SASS instead of CSS</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Fast Scroller by Month and Year</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Add timelines and individual timeline items to the sitemap</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Generate images more efficiently.</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Support a counter that can increment depending on where you are on the timeline.</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Generate QR codes / Stickers for each timeline</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> /raw/md returns a raw version of a topic (in markdown)</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> /raw/md includes a YAML header with relevant information</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> /raw/json returns a JSON version of a topic</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> /feed/ returns a latest links feed of a topic</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> RSS feed of links</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> RSS feed of new links per topic / timeline</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Support a header image.</li>
</ul>
<h2 id="day-20" tabindex="-1">Day 20</h2>
<p>Ok, I need to pull the raw version (markdown) of the post text in for the JSON-LD. I think I've got it working with <code>timelineItem.template.frontMatter.content</code>.</p>
<p><code>git commit -am &quot;Timeline JSON LD working for overall timelines.&quot;</code></p>
<p>Now that the basics are there, let's take a larger more detailed block and we can put the new details into it via Nunjucks <code>extends</code> method.</p>
<p>Before I test this out I'll switch my methodology around images, only create them now where they don't already exist.</p>
<p>Oops, I need to resolve something when the image to-create queue is zeroed out or the build won't resolve. I can't leave the promise un-resolved.</p>
<p><code>git commit -am &quot;Fix timeline and timeline image generation&quot;</code></p>
<p>I need to have an object for single pages now.</p>
<p>I gotta say, as usual, Nunjucks isn't doing great with formatting. I should likely figure out a switch over to using JS to generate my templates instead of Nunjucks, at least for JSON-LD where these are JSON objects anyway.</p>
<p>This is pretty straightforward, except for the <code>isPartOf</code> block which needs to refer back to the timeline, not the site. I'll need to pass the <code>url</code> from the timeline obj into the template.</p>
<p>It works! I think I'm good on metadata for now!</p>
<p>Huh, wait, I am seeing an issue.</p>
<p>Why doesn't my <code>page.url</code> match with the URL I can access it on? There's two URLs for this?</p>
<p><code>new-omicron-variant-ba2121-has-taken-over-massachusetts-here-s-what-you-need-know</code></p>
<p>and</p>
<p><code>http://localhost/timeline/covid/new-omicron-variant-ba2121-has-taken-over-massachusetts-heres-what-you-need-know/</code></p>
<p>Something is wonky here. Ok, let's save place before digging into it.</p>
<p><code>git commit -am &quot;Setting up standalone item meta&quot;</code></p>
]]></content:encoded>
	</item>
	
	<item>
		<title>Context Center Timelines - Day 19 - Setting up data for JSON LD.</title>
		<link>https://fightwithtools.dev/posts/projects/context-timelines/day-19-liveblog-metadata-from-timelines/?source=rss</link>
		<pubDate>Thu, 02 Feb 2023 02:59:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/projects/context-timelines/day-19-liveblog-metadata-from-timelines/</guid>
		<description>Meta for metadata.</description>
		<content:encoded><![CDATA[<h2 id="project-scope-and-todos" tabindex="-1">Project Scope and ToDos</h2>
<ol>
<li>Create timeline pages where one can see the whole timeline of a particular event</li>
<li>Give timeline items type or category icons so that you can easily scan what is happening.</li>
<li>Allow the user to enter the timeline at any individually sharable link of an event and seamlessly scroll up and down</li>
</ol>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Deliver timelines as a plugin that can be extended by other Eleventy users</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Auto-create social-media-ready screenshots of a timeline item</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Integrate with Contexter to have context-full link cards in the timeline</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Leverage the Live Blog format of Schema dot org</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Allow each entry to be its own Markdown file</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Handle SASS instead of CSS</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Fast Scroller by Month and Year</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Add timelines and individual timeline items to the sitemap</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Generate images more efficiently.</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Generate QR codes / Stickers for each timeline</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> /raw/md returns a raw version of a topic (in markdown)</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> /raw/md includes a YAML header with relevant information</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> /raw/json returns a JSON version of a topic</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> /feed/ returns a latest links feed of a topic</li>
</ul>
<h2 id="day-19" tabindex="-1">Day 19</h2>
<p>Ok, lets start figuring out what the metadata structure is that is needed for the timeline schema.</p>
<p>I have a bunch of these values set already, though they may not be passed through to the template.</p>
<p>But I might not have all of them.</p>
<p>I'll start with <code>timelineObj</code> as my new template layout uses that object pretty effectively, even if I'll have to enhance it. But it looks like it doesn't have all the data I need.</p>
<p>I'll need to calculate a value for <code>coverageStartTime</code>. That should be easy enough, I can just reverse the calculation for <code>lastUpdatedPost</code> and make sure it doesn't fall back to zero.</p>
<p>There are some places where I might want to have fields in the future but keep fallbacks to standard values. For those I'll use the Nunjucks construction of <code>{{ X or Y }}</code> which will hopefully work without issue.</p>
<p>Then comes the hard part, I need to play out the timeline entries into the <code>liveBlogUpdate</code> array.</p>
<p>Some of this is pretty straightforward, but I am going to have some trailing commas that are not how they are supposed to be. Is that going to be a problem? Probably! I can use the same <code>last</code> technique I used when generating the JSON of timelines earlier.</p>
<p>But wait... I don't think I can compare complex objects like this?</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/context-timelines/day-19-liveblog-metadata-from-timelines/#code-skip-day-19-liveblog-metadata-from-timelines-1" id="skip-to-code-skip-day-19-liveblog-metadata-from-timelines-1" class="skip-link">Skip code block ▼</a></p>
<pre class="language-liquid"><code class="language-liquid">{%<span class="token templateTag"> <span class="token keyword">if</span> entry <span class="token operator">!==</span> collections<span class="token punctuation">[</span>timelineSlug<span class="token punctuation">]</span> <span class="token operator">|</span> sort <span class="token operator">|</span> last </span>%},{%<span class="token templateTag"> endif </span>%}</code></pre>
<p id="code-skip-day-19-liveblog-metadata-from-timelines-1">Welllllll, let's try next time.</p>
<p><code>git commit -am &quot;Setting up timeline metadata&quot;</code></p>
]]></content:encoded>
	</item>
	
	<item>
		<title>Context Center Timelines - Day 18 - Setting up JSON LD.</title>
		<link>https://fightwithtools.dev/posts/projects/context-timelines/day-18-liveblog-format-for-timelines/?source=rss</link>
		<pubDate>Sat, 14 Jan 2023 02:59:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/projects/context-timelines/day-18-liveblog-format-for-timelines/</guid>
		<description>Getting structured data some structure.</description>
		<content:encoded><![CDATA[<h2 id="project-scope-and-todos" tabindex="-1">Project Scope and ToDos</h2>
<ol>
<li>Create timeline pages where one can see the whole timeline of a particular event</li>
<li>Give timeline items type or category icons so that you can easily scan what is happening.</li>
<li>Allow the user to enter the timeline at any individually sharable link of an event and seamlessly scroll up and down</li>
</ol>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Deliver timelines as a plugin that can be extended by other Eleventy users</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Auto-create social-media-ready screenshots of a timeline item</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Integrate with Contexter to have context-full link cards in the timeline</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Leverage the Live Blog format of Schema dot org</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Allow each entry to be its own Markdown file</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Handle SASS instead of CSS</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Fast Scroller by Month and Year</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Add timelines and individual timeline items to the sitemap</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Generate images more efficiently.</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Generate QR codes / Stickers for each timeline</li>
</ul>
<h2 id="day-18" tabindex="-1">Day 18</h2>
<p>What I'd like to do is implement the correct SEO tags. I've now put in the Social Media Optimization tags.</p>
<p><code>git commit -am &quot;Add socials and fix links. Still don't have the keyvalues working for individual timeline items&quot;</code></p>
<p>But it has been very annoying to have the images build constantly during watch. I bet I can fix that.</p>
<p>Let's try setting a breaker to stop the <code>.after</code> from running after the first time.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/context-timelines/day-18-liveblog-format-for-timelines/#code-skip-day-18-liveblog-format-for-timelines-1" id="skip-to-code-skip-day-18-liveblog-format-for-timelines-1" class="skip-link">Skip code block ▼</a></p>
<pre class="language-js"><code class="language-js">	<span class="token keyword">let</span> ranOnce <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">;</span><br />	eleventyConfig<span class="token punctuation">.</span><span class="token function">on</span><span class="token punctuation">(</span><span class="token string">"eleventy.after"</span><span class="token punctuation">,</span> <span class="token keyword">async</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />		<span class="token keyword">if</span> <span class="token punctuation">(</span>ranOnce<span class="token punctuation">)</span> <span class="token punctuation">{</span><br />			<span class="token keyword">return</span><span class="token punctuation">;</span><br />		<span class="token punctuation">}</span><br />		console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">Image array of </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>timelineImages<span class="token punctuation">.</span>length<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> ready to process</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />		<span class="token keyword">let</span> processFinished <span class="token operator">=</span> imageTool<span class="token punctuation">.</span><span class="token function">queueImagesProcess</span><span class="token punctuation">(</span>timelineImages<span class="token punctuation">)</span><span class="token punctuation">;</span><br />		ranOnce <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">;</span><br />		<span class="token keyword">return</span> processFinished<span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span><br />			console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">"Image generation process complete"</span><span class="token punctuation">)</span><br />		<span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p id="code-skip-day-18-liveblog-format-for-timelines-1">This means establishing an a structured data article schema using JSON-LD.</p>
<p>We want news articles <a href="https://support.google.com/webmasters/thread/95258798/for-liveblogposting-markup-it-need-be-together-with-newsarticle-or-can-be-alone?hl=en" target="_blank">I think</a>? Or <a href="https://schema.org/Article" target="_blank">articles</a> as a format.</p>
<p><a href="https://developers.google.com/search/docs/appearance/structured-data/article" target="_blank">https://developers.google.com/search/docs/appearance/structured-data/article</a></p>
<p>I think it makes sense to render <a href="https://schema.org/LiveBlogPosting" target="_blank">these timelines as <code>LiveBlogPostings</code></a>? It isn't traditionally the case for longer term content, however, we should give it a try. We can always make it optional later, perhaps only some timelines get <a href="https://moz.com/blog/live-blog-posting-schema" target="_blank">the Liveblog treatment</a>. These are composed of <a href="https://schema.org/liveBlogUpdate" target="_blank">liveBlogUpdates</a>. We can see <a href="https://validator.schema.org/#url=https%3A%2F%2Fwww.washingtonpost.com%2Fnation%2F2022%2F01%2F07%2Fcovid-omicron-variant-live-updates%2F" target="_blank">an example of how this works with one of the articles that the Moz blog linked</a>.</p>
<p>Ok, I fixed the image generation process so it won't constantly re-run in watch mode. I think this is a good start, but maybe I shouldn't even build the images if they are already built.</p>
<p>I'll set up the framework of the JSON-LD block I have in the main blog and then work from there now that I've unblocked myself on this issue.</p>
<p><code>git commit -am &quot;Set up JSON LD block for further development&quot;</code></p>
]]></content:encoded>
	</item>
	
	<item>
		<title>Context Center Timelines - Day 17 - Image Generation Backoff.</title>
		<link>https://fightwithtools.dev/posts/projects/context-timelines/day-17-image-generation-timing-management/?source=rss</link>
		<pubDate>Mon, 09 Jan 2023 02:59:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/projects/context-timelines/day-17-image-generation-timing-management/</guid>
		<description>Getting a preview image auto-generated.</description>
		<content:encoded><![CDATA[<h2 id="project-scope-and-todos" tabindex="-1">Project Scope and ToDos</h2>
<ol>
<li>Create timeline pages where one can see the whole timeline of a particular event</li>
<li>Give timeline items type or category icons so that you can easily scan what is happening.</li>
<li>Allow the user to enter the timeline at any individually sharable link of an event and seamlessly scroll up and down</li>
</ol>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Deliver timelines as a plugin that can be extended by other Eleventy users</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Auto-create social-media-ready screenshots of a timeline item</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Integrate with Contexter to have context-full link cards in the timeline</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Leverage the Live Blog format of Schema dot org</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Allow each entry to be its own Markdown file</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Handle SASS instead of CSS</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Fast Scroller by Month and Year</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Add timelines and individual timeline items to the sitemap</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Generate images more efficiently.</li>
</ul>
<h2 id="day-17" tabindex="-1">Day 17</h2>
<p>After the experimentation with the other error, I don't think it is causing the failure I'm seeing. It seems like even with an array of images it may be crashing anyway. I want to try this out in isolation.</p>
<p>By going into the log function in my version of Eleventy in the node_modules folder (<code>node_modules/@11ty/elevent/src/EleventyErrorHandler.js</code>) I added more general logging to see the issue better:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/context-timelines/day-17-image-generation-timing-management/#code-skip-day-17-image-generation-timing-management-3" id="skip-to-code-skip-day-17-image-generation-timing-management-3" class="skip-link">Skip code block ▼</a></p>
<pre class="language-js"><code class="language-js"><span class="token function">log</span><span class="token punctuation">(</span>e<span class="token punctuation">,</span> type <span class="token operator">=</span> <span class="token string">"log"</span><span class="token punctuation">,</span> prefix <span class="token operator">=</span> <span class="token string">">"</span><span class="token punctuation">,</span> chalkColor <span class="token operator">=</span> <span class="token string">""</span><span class="token punctuation">,</span> forceToConsole <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />  <span class="token keyword">let</span> ref <span class="token operator">=</span> e<span class="token punctuation">;</span><br />	console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Error Thrown'</span><span class="token punctuation">,</span> e<span class="token punctuation">)</span><br />  <span class="token keyword">while</span> <span class="token punctuation">(</span>ref<span class="token punctuation">)</span> <span class="token punctuation">{</span><br />    <span class="token keyword">let</span> nextRef <span class="token operator">=</span> ref<span class="token punctuation">.</span>originalError<span class="token punctuation">;</span><br />    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>nextRef <span class="token operator">&amp;&amp;</span> EleventyErrorUtil<span class="token punctuation">.</span><span class="token function">hasEmbeddedError</span><span class="token punctuation">(</span>ref<span class="token punctuation">.</span>message<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />      nextRef <span class="token operator">=</span> EleventyErrorUtil<span class="token punctuation">.</span><span class="token function">deconvertErrorToObject</span><span class="token punctuation">(</span>ref<span class="token punctuation">)</span><span class="token punctuation">;</span><br />    <span class="token punctuation">}</span></code></pre>
<p id="code-skip-day-17-image-generation-timing-management-3">Let's get the actual image objects I want to use and write them locally.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/context-timelines/day-17-image-generation-timing-management/#code-skip-day-17-image-generation-timing-management-2" id="skip-to-code-skip-day-17-image-generation-timing-management-2" class="skip-link">Skip code block ▼</a></p>
<pre class="language-js"><code class="language-js">	eleventyConfig<span class="token punctuation">.</span><span class="token function">on</span><span class="token punctuation">(</span><span class="token string">"eleventy.after"</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />		console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">Image array of </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>timelineImages<span class="token punctuation">.</span>length<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> ready to process</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />		<span class="token keyword">const</span> fs <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">"fs"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />		fs<span class="token punctuation">.</span><span class="token function">writeFileSync</span><span class="token punctuation">(</span><br />			<span class="token string">"images.json"</span><span class="token punctuation">,</span><br />			<span class="token constant">JSON</span><span class="token punctuation">.</span><span class="token function">stringify</span><span class="token punctuation">(</span>timelineImages<span class="token punctuation">,</span> <span class="token keyword">null</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">)</span><br />		<span class="token punctuation">)</span><span class="token punctuation">;</span><br />		console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>timelineImages<span class="token punctuation">)</span><span class="token punctuation">;</span><br />		<span class="token keyword">return</span> <span class="token boolean">true</span><span class="token punctuation">;</span><br />		<span class="token function">htmlToImage</span><span class="token punctuation">(</span><span class="token punctuation">{</span><br />			<span class="token literal-property property">html</span><span class="token operator">:</span> imageTool<span class="token punctuation">.</span><span class="token function">handlebarsTemplate</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br />			<span class="token literal-property property">content</span><span class="token operator">:</span> timelineImages<span class="token punctuation">,</span><br />			<span class="token literal-property property">puppeteerArgs</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">timeout</span><span class="token operator">:</span> <span class="token number">0</span> <span class="token punctuation">}</span><span class="token punctuation">,</span><br />		<span class="token punctuation">}</span><span class="token punctuation">)</span><br />			<span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">"The images were created successfully!"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><br />			<span class="token punctuation">.</span><span class="token function">catch</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">error</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />				console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">"The images were not created successfully!"</span><span class="token punctuation">,</span> error<span class="token punctuation">)</span><span class="token punctuation">;</span><br />			<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p id="code-skip-day-17-image-generation-timing-management-2">Once I've got this file, I can go ahead, take it, and move it into a standalone project. I can use Glitch to experiment with this.</p>
<p>Ok, looks like I can't use Puppeteer on Glitch for some reason. I'll do this locally. Glitch provides Git urls, so I can just download it right from that site using Git. <a href="https://glitch.com/edit/#!/better-recondite-umbrella" target="_blank">Here's the Glitch project</a> and I can just run the local file without the server: <code>node -e 'require(&quot;./image-generator.js&quot;)()'</code>.</p>
<p>Hmmm, well, in isolation it seems to freeze at around 129 items and then stop there. I should likely back off, or perhaps split up the array of images and handle them, maybe 50 at a time.</p>
<p>Let's <a href="https://stackoverflow.com/questions/8495687/split-array-into-chunks" target="_blank">pull together some code to chunk up the array</a>.</p>
<p>Once it is chunked up, I wonder if I can get it to run in parallel? Or should I get it to run in sequence. Let's try parallel first.</p>
<p>Huh. It says it completed, but no go, only 129 of over 400 items it is supposed to generate.</p>
<p>I can try using <code>await</code> in the forEach loop? No, that is still causing a timeout. What if I try decreasing the size of the sub arrays. Nope, that didn't work.</p>
<p>Let's instead try chaining the array more directly into a Promise sequence.</p>
<p>Wait... there are only 62 posts and I'm duplicating, so there should be 124 images. That's weird... why did it act like were over 400 elements?</p>
<p>Huh, it looks like there was a problem with the image output names not being properly escaped via slugify. Let's make sure the fix for that is in place.</p>
<p>Hmm ok, I also need to remove quotes and some other symbols. Ok, better file names now. This seems like it is working, but I'm not seeing every single file created. Let me check to see if somehow I'm overwriting a file that already exists.</p>
<p>Ah, I need to <code>shift</code> the first element off the front of the array.</p>
<p>Oh and I need to return the Promise so it can be handled. Ok, this is working in the standalone project now. Let's bring it back over.</p>
<p><code>git commit -am &quot;Get image generation more sequenced, less in parallel. And it is working&quot;</code></p>
<p>My working dynamically generated Promise chain looks like this:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/context-timelines/day-17-image-generation-timing-management/#code-skip-day-17-image-generation-timing-management-1" id="skip-to-code-skip-day-17-image-generation-timing-management-1" class="skip-link">Skip code block ▼</a></p>
<pre class="language-js"><code class="language-js"><span class="token keyword">function</span> <span class="token function">generateSomeImages</span><span class="token punctuation">(</span><span class="token parameter">imageSet</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />	<span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">Promise</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">resolve<span class="token punctuation">,</span> reject</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />		console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">Image sub array of </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>imageSet<span class="token punctuation">.</span>length<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> ready to process</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />		imageSet<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">imgObject</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />			<span class="token keyword">if</span> <span class="token punctuation">(</span>fs<span class="token punctuation">.</span><span class="token function">existsSync</span><span class="token punctuation">(</span>imgObject<span class="token punctuation">.</span>output<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />				<span class="token comment">//console.log("File already exists", imgObject.output);</span><br />			<span class="token punctuation">}</span><br />		<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />		<span class="token function">htmlToImage</span><span class="token punctuation">(</span><span class="token punctuation">{</span><br />			<span class="token literal-property property">html</span><span class="token operator">:</span> <span class="token function">handlebarsTemplate</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br />			<span class="token literal-property property">content</span><span class="token operator">:</span> imageSet<span class="token punctuation">,</span><br />			<span class="token literal-property property">puppeteerArgs</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">timeout</span><span class="token operator">:</span> <span class="token number">0</span> <span class="token punctuation">}</span><span class="token punctuation">,</span><br />		<span class="token punctuation">}</span><span class="token punctuation">)</span><br />			<span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />				console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">"The images were created successfully!"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />				<span class="token function">resolve</span><span class="token punctuation">(</span><span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />			<span class="token punctuation">}</span><span class="token punctuation">)</span><br />			<span class="token punctuation">.</span><span class="token function">catch</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">error</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />				console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">"The images were not created successfully!"</span><span class="token punctuation">,</span> error<span class="token punctuation">)</span><span class="token punctuation">;</span><br />				<span class="token function">reject</span><span class="token punctuation">(</span>error<span class="token punctuation">)</span><span class="token punctuation">;</span><br />			<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span><br /><br /><br /><span class="token keyword">const</span> <span class="token function-variable function">queueImagesProcess</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">timelineImages</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />	console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">Image array of </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>timelineImages<span class="token punctuation">.</span>length<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> ready to process</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token comment">//console.log(timelineImages);</span><br />	<span class="token keyword">let</span> chunks <span class="token operator">=</span> <span class="token function">chunkUpArray</span><span class="token punctuation">(</span>timelineImages<span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token keyword">let</span> firstChunk <span class="token operator">=</span> chunks<span class="token punctuation">.</span><span class="token function">shift</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token keyword">try</span> <span class="token punctuation">{</span><br />		<span class="token keyword">let</span> finalPromise <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Promise</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">resolve<span class="token punctuation">,</span> reject</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />			<span class="token keyword">let</span> finalStep <span class="token operator">=</span> Promise<span class="token punctuation">.</span><span class="token function">resolve</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />			<span class="token keyword">let</span> promiseChain <span class="token operator">=</span> chunks<span class="token punctuation">.</span><span class="token function">reduce</span><span class="token punctuation">(</span><br />				<span class="token punctuation">(</span><span class="token parameter">prev<span class="token punctuation">,</span> cur</span><span class="token punctuation">)</span> <span class="token operator">=></span><br />					prev<span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />						<span class="token keyword">return</span> <span class="token function">generateSomeImages</span><span class="token punctuation">(</span>cur<span class="token punctuation">)</span><span class="token punctuation">;</span><br />					<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br />				<span class="token function">generateSomeImages</span><span class="token punctuation">(</span>firstChunk<span class="token punctuation">)</span><br />			<span class="token punctuation">)</span><span class="token punctuation">;</span><br />			<span class="token keyword">return</span> promiseChain<br />				<span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />					console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">"Chain complete"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />					<span class="token function">resolve</span><span class="token punctuation">(</span><span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />				<span class="token punctuation">}</span><span class="token punctuation">)</span><br />				<span class="token punctuation">.</span><span class="token function">catch</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />					console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">"Promise catch error in-chain "</span><span class="token punctuation">,</span> e<span class="token punctuation">)</span><span class="token punctuation">;</span><br />					<span class="token function">reject</span><span class="token punctuation">(</span><span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />				<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />		<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />		<span class="token keyword">return</span> finalPromise<span class="token punctuation">;</span><br />	<span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span>e<span class="token punctuation">)</span> <span class="token punctuation">{</span><br />		console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">"Promise resolution failed"</span><span class="token punctuation">,</span> e<span class="token punctuation">)</span><span class="token punctuation">;</span><br />		<span class="token keyword">return</span> <span class="token boolean">false</span><span class="token punctuation">;</span><br />	<span class="token punctuation">}</span><br /><span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
<p id="code-skip-day-17-image-generation-timing-management-1">I found this after I found my solution, which itself <a href="https://stackoverflow.com/questions/21372320/how-to-chain-execution-of-array-of-functions-when-every-function-returns-deferre" target="_blank">was adapted</a>, but <a href="https://decembersoft.com/posts/promises-in-serial-with-array-reduce/" target="_blank">this appears to be a pretty decent walk-through of the thinking behind using <code>reduce</code> to accomplish this</a>.</p>
<p>And the last step is to set it up in the HEAD tag of the template!</p>
<p><code>git commit -am &quot;Add social image to timeline page headers&quot;</code></p>
]]></content:encoded>
	</item>
	
	<item>
		<title>Context Center Timelines - Day 16 - Attempting to change the build time for images.</title>
		<link>https://fightwithtools.dev/posts/projects/context-timelines/day-16-attempting-to-change-the-image-build-time/?source=rss</link>
		<pubDate>Tue, 03 Jan 2023 02:59:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/projects/context-timelines/day-16-attempting-to-change-the-image-build-time/</guid>
		<description>Getting a preview image auto-generated.</description>
		<content:encoded><![CDATA[<h2 id="project-scope-and-todos" tabindex="-1">Project Scope and ToDos</h2>
<ol>
<li>Create timeline pages where one can see the whole timeline of a particular event</li>
<li>Give timeline items type or category icons so that you can easily scan what is happening.</li>
<li>Allow the user to enter the timeline at any individually sharable link of an event and seamlessly scroll up and down</li>
</ol>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Deliver timelines as a plugin that can be extended by other Eleventy users</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Auto-create social-media-ready screenshots of a timeline item</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Integrate with Contexter to have context-full link cards in the timeline</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Leverage the Live Blog format of Schema dot org</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Allow each entry to be its own Markdown file</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Handle SASS instead of CSS</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Fast Scroller by Month and Year</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Add timelines and individual timeline items to the sitemap</li>
</ul>
<h2 id="day-16" tabindex="-1">Day 16</h2>
<p>The image build is just too heavy to do as is, even if it works.</p>
<p>It looks like I can pass an array into the library and build all the images at once? This might solve my problem with too many puppeteer instances launching (looks like <a href="https://github.com/frinyvonnick/node-html-to-image/issues/80" target="_blank">I'm not the only one to have this issue</a>). But it looks like it expects me to pass in a <code>content</code> property and use a Handlebars template. Well, that's good, I already have a Handlebars template I can pull in.</p>
<p>I just need to pass in the object for <code>content</code>.</p>
<p>I'll do another test function to handle this.</p>
<p>Hmmm, there are a few things that need to be cleaned up let's see.</p>
<p>Ok, I've resolved most of the errors, but I'm still getting one.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/context-timelines/day-16-attempting-to-change-the-image-build-time/#code-skip-day-16-attempting-to-change-the-image-build-time-4" id="skip-to-code-skip-day-16-attempting-to-change-the-image-build-time-4" class="skip-link">Skip code block ▼</a></p>
<pre class="language-bash"><code class="language-bash"> ✘  ~/Dev/context-center   timeline ●  <span class="token function">node</span> <span class="token parameter variable">-e</span> <span class="token string">'require("./_custom-plugins/timelinety/src/build-tools/timeline-social-image.js").testHandlebarImg()'</span><br />Create Template Social Image Enters<br />TypeError: <span class="token punctuation">(</span>lookupProperty<span class="token punctuation">(</span><span class="token punctuation">..</span>.<span class="token punctuation">)</span> <span class="token operator">||</span> <span class="token punctuation">(</span>depth0 <span class="token operator">&amp;&amp;</span> lookupProperty<span class="token punctuation">(</span><span class="token punctuation">..</span>.<span class="token punctuation">))</span> <span class="token operator">||</span> alias4<span class="token punctuation">)</span>.call is not a <span class="token keyword">function</span><br />    at Object.eval <span class="token punctuation">[</span>as main<span class="token punctuation">]</span> <span class="token punctuation">(</span>eval at createFunctionContext <span class="token punctuation">(</span>/Users/zuckerscharffa/Dev/context-center/node_modules/handlebars/dist/cjs/handlebars/compiler/javascript-compiler.js:262:23<span class="token punctuation">)</span>, <span class="token operator">&lt;</span>anonymous<span class="token operator">></span>:35:128<span class="token punctuation">)</span><br />    at main <span class="token punctuation">(</span>/Users/zuckerscharffa/Dev/context-center/node_modules/handlebars/dist/cjs/handlebars/runtime.js:208:32<span class="token punctuation">)</span><br />    at ret <span class="token punctuation">(</span>/Users/zuckerscharffa/Dev/context-center/node_modules/handlebars/dist/cjs/handlebars/runtime.js:212:12<span class="token punctuation">)</span><br />    at ret <span class="token punctuation">(</span>/Users/zuckerscharffa/Dev/context-center/node_modules/handlebars/dist/cjs/handlebars/compiler/compiler.js:519:21<span class="token punctuation">)</span><br />    at /Users/zuckerscharffa/Dev/context-center/node_modules/node-html-to-image/dist/screenshot.js:50:44<br />    at step <span class="token punctuation">(</span>/Users/zuckerscharffa/Dev/context-center/node_modules/node-html-to-image/dist/screenshot.js:33:23<span class="token punctuation">)</span><br />    at Object.next <span class="token punctuation">(</span>/Users/zuckerscharffa/Dev/context-center/node_modules/node-html-to-image/dist/screenshot.js:14:53<span class="token punctuation">)</span><br />    at /Users/zuckerscharffa/Dev/context-center/node_modules/node-html-to-image/dist/screenshot.js:8:71<br />    at new Promise <span class="token punctuation">(</span><span class="token operator">&lt;</span>anonymous<span class="token operator">></span><span class="token punctuation">)</span><br />    at __awaiter <span class="token punctuation">(</span>/Users/zuckerscharffa/Dev/context-center/node_modules/node-html-to-image/dist/screenshot.js:4:12<span class="token punctuation">)</span></code></pre>
<p id="code-skip-day-16-attempting-to-change-the-image-build-time-4">Ok, let's start slowly adding chunks of Handlebar code to see what triggers the error.</p>
<p>Ok, it looks like the core problem is <code>or</code> use in my template? Is there a different version of Handlebars at use in the <code>node-html-to-image</code> process?</p>
<p>What happens if we change the <code>or</code>s to instead be <code>if</code>s.</p>
<p>Ok, that seems to have fixed the issue, though it is still showing some rendering errors. I am not sure why Handlebars is working differently here. The Handlebars version <a href="https://github.com/frinyvonnick/node-html-to-image/blob/master/package.json#L11" target="_blank">we're seeing in the node library is 4.5.3</a> and <a href="https://github.com/11ty/eleventy/blob/v1.x/package.json#L110" target="_blank">in Eleventy we're using 4.7.7</a>.</p>
<p>Hmm, it looks like the techniques I used for Nunjucks doesn't translate to Handlebars. I'll have to swap it over to Handlebars techniques instead. Annoying. Ugh, I've been doing Nunjucks for so long I've forgotten my Handlebars.</p>
<p>Ok, I've gotten a corrected template working now, but it isn't quite the same, I'll have to fix the style since I don't have custom HTML components anymore.</p>
<p>I'll need to set up Handlebars to generate a test rendered page, even with the fixes it still isn't working like I'd hoped.</p>
<p>Ok, a few differences in the layout are there that I'll need to adjust for, but shouldn't be too bad.</p>
<p>Ok, got it working again!</p>
<p><img src="https://fightwithtools.dev/img/test-img-gen-5.png" alt="A working version of the timeline image" /></p>
<p><code>git commit -am &quot;Set up a handlebars template for social image generation&quot;</code></p>
<p>Ok, it looks like by putting an Array variable outside of the filter function, using it inside the filter function, and then using the Eleventy <code>after</code> event I can have it run against all the images at once:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/context-timelines/day-16-attempting-to-change-the-image-build-time/#code-skip-day-16-attempting-to-change-the-image-build-time-3" id="skip-to-code-skip-day-16-attempting-to-change-the-image-build-time-3" class="skip-link">Skip code block ▼</a></p>
<pre class="language-js"><code class="language-js">eleventyConfig<span class="token punctuation">.</span><span class="token function">on</span><span class="token punctuation">(</span><span class="token string">"eleventy.after"</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />	console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">"Image object ready to process"</span><span class="token punctuation">,</span> timelineImages<span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token function">htmlToImage</span><span class="token punctuation">(</span><span class="token punctuation">{</span><br />		<span class="token literal-property property">html</span><span class="token operator">:</span> imageTool<span class="token punctuation">.</span><span class="token function">handlebarsTemplate</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br />		<span class="token literal-property property">content</span><span class="token operator">:</span> timelineImages<span class="token punctuation">,</span><br />	<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">"The images were created successfully!"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p id="code-skip-day-16-attempting-to-change-the-image-build-time-3">This does seem to work, but I'm still getting an error:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/context-timelines/day-16-attempting-to-change-the-image-build-time/#code-skip-day-16-attempting-to-change-the-image-build-time-2" id="skip-to-code-skip-day-16-attempting-to-change-the-image-build-time-2" class="skip-link">Skip code block ▼</a></p>
<pre class="language-bash"><code class="language-bash">Error: Timeout hit: <span class="token number">30000</span><br />    at /Users/zuckerscharffa/Dev/context-center/node_modules/puppeteer-cluster/dist/util.js:69:23<br />    at Generator.next <span class="token punctuation">(</span><span class="token operator">&lt;</span>anonymous<span class="token operator">></span><span class="token punctuation">)</span><br />    at fulfilled <span class="token punctuation">(</span>/Users/zuckerscharffa/Dev/context-center/node_modules/puppeteer-cluster/dist/util.js:5:58<span class="token punctuation">)</span><br />    at runNextTicks <span class="token punctuation">(</span>internal/process/task_queues.js:60:5<span class="token punctuation">)</span><br />    at processTimers <span class="token punctuation">(</span>internal/timers.js:497:9<span class="token punctuation">)</span><br />  Eleventy:TemplatePassthrough Copying individual</code></pre>
<p id="code-skip-day-16-attempting-to-change-the-image-build-time-2">This appears to be Puppeteer timing out when I build the images? Let's <a href="https://pptr.dev/api/puppeteer.launchoptions.timeout/" target="_blank">see if I can pass it the args</a> in order to avoid that timeout.</p>
<p>I'm getting an unrelated error from JSDOM... I guess I don't really need that anymore though? Let's remove it. Wow that will be a lot of work that it turned out I didn't need to do. Yeah, that works!</p>
<p>Ok, I've got less errors now, but it is still crashing. The images seem to be building out, but it crashes out and I think it is still the timeout?</p>
<p><code>git commit -m &quot;Adding fixes for the template generation of the preview image&quot;</code></p>
<p>Ok, I don't seem to be getting the same error. Perhaps this is a error about a particular post? I don't know, but the timeout error does seem to be gone.</p>
<p>I'm trying to eliminate other errors, and it does look as if Eleventy is tripping over my error in the markdown-contexter around processing after <code>pContext</code> there.</p>
<p>It appears that the timeout error is at</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/context-timelines/day-16-attempting-to-change-the-image-build-time/#code-skip-day-16-attempting-to-change-the-image-build-time-1" id="skip-to-code-skip-day-16-attempting-to-change-the-image-build-time-1" class="skip-link">Skip code block ▼</a></p>
<pre class="language-js"><code class="language-js"><span class="token function">setTimeout</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />	console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><br />		<span class="token string">"Request timed out for "</span><span class="token punctuation">,</span><br />		cacheFile<br />	<span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token function">reject</span><span class="token punctuation">(</span><span class="token string">"Timeout error"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token number">6000</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p id="code-skip-day-16-attempting-to-change-the-image-build-time-1">So it looks like a try/catch around my array of promises with <code>Promise.all</code> resolution doesn't seem to be working.</p>
<p>Ok, replacing <code>reject(&quot;Timeout error&quot;)</code> with <code>reject(new Error(&quot;Archiving request timeout error&quot;));</code> at least tells me what the error is. But it is saying it is unhandled, and I'm not sure why that is the case. It should be handled. Maybe I just remove the reject?</p>
<p><code>git commit -am &quot;Adding better logging for markdown contexter&quot;</code></p>
]]></content:encoded>
	</item>
	
	<item>
		<title>Context Center Timelines - Day 15 - Get CSS for Image Generation Working</title>
		<link>https://fightwithtools.dev/posts/projects/context-timelines/day-15-get-css-for-image-generation-working/?source=rss</link>
		<pubDate>Mon, 02 Jan 2023 02:59:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/projects/context-timelines/day-15-get-css-for-image-generation-working/</guid>
		<description>Getting a preview image auto-generated.</description>
		<content:encoded><![CDATA[<h2 id="project-scope-and-todos" tabindex="-1">Project Scope and ToDos</h2>
<ol>
<li>Create timeline pages where one can see the whole timeline of a particular event</li>
<li>Give timeline items type or category icons so that you can easily scan what is happening.</li>
<li>Allow the user to enter the timeline at any individually sharable link of an event and seamlessly scroll up and down</li>
</ol>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Deliver timelines as a plugin that can be extended by other Eleventy users</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Auto-create social-media-ready screenshots of a timeline item</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Integrate with Contexter to have context-full link cards in the timeline</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Leverage the Live Blog format of Schema dot org</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Allow each entry to be its own Markdown file</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Handle SASS instead of CSS</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Fast Scroller by Month and Year</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Add timelines and individual timeline items to the sitemap</li>
</ul>
<h2 id="day-15" tabindex="-1">Day 15</h2>
<p>Looks like there are quite a few options for getting CSS minified in the way I'm thinking, but when filtering for recently updated, not with a lot of issues, commonly used, and with a clear intent to be used inside standard Node work, not some larger system, I've narrowed it down to one candidate - <a href="https://www.npmjs.com/package/csso" target="_blank">csso</a>.</p>
<p>Let's install and try that.</p>
<p>Wait though... what happens when an eleventy plugin has a dependency? I should be fine once it is packaged up and I install it with an actual install command, right? Ok, lets put that to one side.</p>
<p>Ok, now we're getting somewhere!</p>
<p>I need to import the user stylesheet as well and the layout isn't fully working, but it is definitely a <em>lot</em> closer.</p>
<p><img src="https://fightwithtools.dev/img/test-img-gen-4.png" alt="A broken version of the timeline item that doesn't quite work but is getting there - it has style applied now!" />.</p>
<p>To get it all the way there I'll need an image specific stylesheet to pull in. I've done it so it is always <code>odd</code> in terms of its placement configuration so I don't have to worry about two different styles.</p>
<p>I will need to make two images it looks like, <a href="https://developers.facebook.com/docs/sharing/webmasters/images/" target="_blank">one for Facebook</a> at <code>1200 x 630</code> and one with a 2:1 aspect ratio (so lets do <code>1200 x 600</code>) <a href="https://developer.twitter.com/en/docs/twitter-for-websites/cards/overview/summary-card-with-large-image" target="_blank">for Twitter</a>.</p>
<p><a href="https://github.com/11ty/eleventy/pull/2633" target="_blank">Now that I know that there is a queued writing system</a> in Eleventy using <code>graceful-fs</code>, I'll use that instead of standard <code>fs</code> here.</p>
<p>I know that if the link is there by itself, it'll have a particular pattern I can check the <code>content</code> property for with a ReExp check:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/context-timelines/day-15-get-css-for-image-generation-working/#code-skip-day-15-get-css-for-image-generation-working-1" id="skip-to-code-skip-day-15-get-css-for-image-generation-working-1" class="skip-link">Skip code block ▼</a></p>
<pre class="language-js"><code class="language-js"><span class="token keyword">let</span> rexExpCheck <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">RegExp</span><span class="token punctuation">(</span><br />  <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">&lt;p>&lt;a href="</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>dataObj<span class="token punctuation">.</span>isBasedOn<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">" target="_blank"></span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>dataObj<span class="token punctuation">.</span>isBasedOn<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">&lt;/a>&lt;/p>\n</span><span class="token template-punctuation string">`</span></span><br /><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p id="code-skip-day-15-get-css-for-image-generation-working-1">Wait actually, I think it might build the share card beforehand? Let's try.</p>
<p>I also should try to vertically center the box during image generation.</p>
<p>Ok, yeah, it does! Nice!</p>
<p><code>git commit -am &quot;Set up image build function&quot;</code></p>
<p>Hmmm, it looks like the image builder backs up and crashes.</p>
<p>I can also see that there is a problem with some of the timegate URLs that are based on URLs. Looks like I'm getting some filepaths like <code>timegate/https://activitystrea.ms//index.html</code>.</p>
<p>And we'll fix the positioning in the CSS.</p>
<p><code>git commit -am &quot;Get image positioning right.&quot; </code></p>
<p>Ok, now to figure out how to generate these images during build.</p>
]]></content:encoded>
	</item>
	
	<item>
		<title>Context Center Timelines - Day 14 - Generate Timeline Item Image</title>
		<link>https://fightwithtools.dev/posts/projects/context-timelines/day-14-continuing-to-generate-image/?source=rss</link>
		<pubDate>Sat, 31 Dec 2022 02:59:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/projects/context-timelines/day-14-continuing-to-generate-image/</guid>
		<description>Getting a preview image auto-generated.</description>
		<content:encoded><![CDATA[<h2 id="project-scope-and-todos" tabindex="-1">Project Scope and ToDos</h2>
<ol>
<li>Create timeline pages where one can see the whole timeline of a particular event</li>
<li>Give timeline items type or category icons so that you can easily scan what is happening.</li>
<li>Allow the user to enter the timeline at any individually sharable link of an event and seamlessly scroll up and down</li>
</ol>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Deliver timelines as a plugin that can be extended by other Eleventy users</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Auto-create social-media-ready screenshots of a timeline item</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Integrate with Contexter to have context-full link cards in the timeline</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Leverage the Live Blog format of Schema dot org</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Allow each entry to be its own Markdown file</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Handle SASS instead of CSS</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Fast Scroller by Month and Year</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Add timelines and individual timeline items to the sitemap</li>
</ul>
<h2 id="day-14" tabindex="-1">Day 14</h2>
<p>Ok, not sure what is going wrong with the image generation, but clearly something is wonky. I'm going to <a href="https://stackoverflow.com/questions/30782693/run-function-in-script-from-command-line-node-js" target="_blank">try running a test function on the command line</a> and see what happens.</p>
<p><code>node -e 'require(&quot;./_custom-plugins/timelinety/src/build-tools/timeline-social-image.js&quot;).testImg()'</code></p>
<p>Ok, this has worked.</p>
<p><img src="https://fightwithtools.dev/img/test-img-gen-1.png" alt="A basic hello world" /></p>
<p>Let us try to add some elements here and see if it continues to work.</p>
<p>Sizing is a little weird, but looking good!</p>
<p><img src="https://fightwithtools.dev/img/test-img-gen-2.png" alt="A basic hello world but now with color text and background" /></p>
<p>Ok, this is looking promising!</p>
<p>To size the final image I need to set body styles when I create JSDOM as an object, like so:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/context-timelines/day-14-continuing-to-generate-image/#code-skip-day-14-continuing-to-generate-image-4" id="skip-to-code-skip-day-14-continuing-to-generate-image-4" class="skip-link">Skip code block ▼</a></p>
<pre class="language-js"><code class="language-js"><span class="token keyword">const</span> dom <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">JSDOM</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">&lt;!DOCTYPE html>&lt;head><br />&lt;link href="https://fonts.googleapis.com/css?family=Roboto+Slab|Hind+Vadodara:400,600" rel="stylesheet" type="text/css"><br />&lt;style><br />body {<br /> width: 600px;<br /> height: 500px;<br />}<br />&lt;/style><br />&lt;/head>&lt;body>&lt;/body></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p id="code-skip-day-14-continuing-to-generate-image-4">I'll try adding the style in next. Hmm. Oh, I forgot that the style element needs <code>innerHTML</code>. Hmmm, no that doesn't do it. Perhaps I need to <a href="https://stackoverflow.com/questions/524696/how-to-create-a-style-tag-with-javascript" target="_blank">give it a type</a>.</p>
<p>Looks like that worked. Hmm.</p>
<p>Ok, lets see if I can abstract the custom HTML element class to its own file.</p>
<p>I'll just have to pass the class the document and HTMLElement objects into the stand-alone file like so:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/context-timelines/day-14-continuing-to-generate-image/#code-skip-day-14-continuing-to-generate-image-3" id="skip-to-code-skip-day-14-continuing-to-generate-image-3" class="skip-link">Skip code block ▼</a></p>
<pre class="language-js"><code class="language-js">module<span class="token punctuation">.</span><span class="token function-variable function">exports</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">document<span class="token punctuation">,</span> HTMLElement</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />	<span class="token keyword">class</span> <span class="token class-name">TimelineItem</span> <span class="token keyword">extends</span> <span class="token class-name">HTMLElement</span> <span class="token punctuation">{</span><br />		<span class="token operator">...</span><br />	<span class="token punctuation">}</span><br />	<span class="token keyword">return</span> TimelineItem<span class="token punctuation">;</span><br /><span class="token punctuation">}</span></code></pre>
<p id="code-skip-day-14-continuing-to-generate-image-3">Ok, now lets try running a test with an actual timeline object:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/context-timelines/day-14-continuing-to-generate-image/#code-skip-day-14-continuing-to-generate-image-2" id="skip-to-code-skip-day-14-continuing-to-generate-image-2" class="skip-link">Skip code block ▼</a></p>
<pre class="language-js"><code class="language-js"><span class="token punctuation">{</span><br />  <span class="token literal-property property">timeline</span><span class="token operator">:</span> <span class="token string">'monkeypox'</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">title</span><span class="token operator">:</span> <span class="token string">'A looming deadline for tens of millions of Americans'</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">description</span><span class="token operator">:</span> <span class="token string">'The GOP battles over a trillion-dollar stimulus deal. Ahead of the November election, President Trump guts a landmark environmental law. And, how to avoid a devastating potential kink in the vaccine supply chain.'</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">tags</span><span class="token operator">:</span> <span class="token punctuation">[</span><br />    <span class="token string">'timeline'</span><span class="token punctuation">,</span><br />    <span class="token string">'Monkeypox'</span><span class="token punctuation">,</span><br />    <span class="token string">'Health'</span><span class="token punctuation">,</span><br />    <span class="token string">'Medicine'</span><span class="token punctuation">,</span><br />    <span class="token string">'Stimulus'</span><span class="token punctuation">,</span><br />    <span class="token string">'Markets'</span><br />  <span class="token punctuation">]</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">date</span><span class="token operator">:</span> <span class="token string">'2020-06-22T16:00:00.100Z'</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">categories</span><span class="token operator">:</span> <span class="token punctuation">[</span> <span class="token string">'News'</span> <span class="token punctuation">]</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">filters</span><span class="token operator">:</span> <span class="token punctuation">[</span> <span class="token string">'USA'</span> <span class="token punctuation">]</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">dateAdded</span><span class="token operator">:</span> <span class="token string">'2022-08-09T02:59:43.100Z'</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">isBasedOn</span><span class="token operator">:</span> <span class="token string">'https://www.washingtonpost.com/podcasts/post-reports/a-looming-deadline-for-tens-of-millions-americans/'</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">shortdate</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">color</span><span class="token operator">:</span> <span class="token string">'grey'</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">content</span><span class="token operator">:</span> <span class="token string">'&lt;p>&lt;a href="https://www.washingtonpost.com/podcasts/post-reports/a-looming-deadline-for-tens-of-millions-americans/" target="_blank">https://www.washingtonpost.com/podcasts/post-reports/a-looming-deadline-for-tens-of-millions-americans/&lt;/a>&lt;/p>\n'</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">slug</span><span class="token operator">:</span> <span class="token string">'a-looming-deadline-for-tens-of-millions-of-americans'</span><br /><span class="token punctuation">}</span></code></pre>
<p id="code-skip-day-14-continuing-to-generate-image-2">Now we're starting to get somewhere!</p>
<p><img src="https://fightwithtools.dev/img/test-img-gen-3.png" alt="A broken version of the timeline item that doesn't quite work but is getting there" /></p>
<p><code>git commit -m &quot;Basic working timeline image even if it looks terrible&quot;</code></p>
<p>Ok, I need to write the HTML to a document to debug it.</p>
<p>Oh huh, I guess I need to add metadata with the Contexter plugin settings, since I'm going to need it to add information to the images as well. Ok, shouldn't be too hard, for that plugin I can add global data.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/context-timelines/day-14-continuing-to-generate-image/#code-skip-day-14-continuing-to-generate-image-1" id="skip-to-code-skip-day-14-continuing-to-generate-image-1" class="skip-link">Skip code block ▼</a></p>
<pre class="language-js"><code class="language-js"><span class="token keyword">let</span> options <span class="token operator">=</span> <span class="token punctuation">{</span><br />	<span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">"markdown-contexter"</span><span class="token punctuation">,</span><br />	<span class="token literal-property property">extension</span><span class="token operator">:</span> <span class="token string">"md"</span><span class="token punctuation">,</span><br />	<span class="token literal-property property">cachePath</span><span class="token operator">:</span> <span class="token string">"_contexterCache"</span><span class="token punctuation">,</span><br />	<span class="token literal-property property">publicImagePath</span><span class="token operator">:</span> <span class="token string">"assets/images/contexter"</span><span class="token punctuation">,</span><br />	<span class="token literal-property property">publicPath</span><span class="token operator">:</span> <span class="token string">"timegate"</span><span class="token punctuation">,</span><br />	<span class="token literal-property property">domain</span><span class="token operator">:</span> <span class="token string">"http://localhost:8080"</span><span class="token punctuation">,</span><br />	<span class="token literal-property property">buildArchive</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span><br />	<span class="token function-variable function">existingRenderer</span><span class="token operator">:</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span><br />	<span class="token operator">...</span>userOptions<span class="token punctuation">,</span><br /><span class="token punctuation">}</span><span class="token punctuation">;</span><br /><br /><span class="token keyword">const</span> cacheFolder <span class="token operator">=</span> path<span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span><br />	__dirname<span class="token punctuation">,</span><br />	<span class="token string">"../../"</span><span class="token punctuation">,</span><br />	<span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">/</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>options<span class="token punctuation">.</span>cachePath<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">/</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span><br />	pageFilePath<br /><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br />options<span class="token punctuation">.</span>cacheFolder <span class="token operator">=</span> cacheFolder<span class="token punctuation">;</span><br />eleventyConfig<span class="token punctuation">.</span><span class="token function">addPassthroughCopy</span><span class="token punctuation">(</span><span class="token punctuation">{</span><br />	<span class="token punctuation">[</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>options<span class="token punctuation">.</span>cachePath<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">/images</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">]</span><span class="token operator">:</span> options<span class="token punctuation">.</span>publicImagePath<span class="token punctuation">,</span><br /><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />eleventyConfig<span class="token punctuation">.</span><span class="token function">addGlobalData</span><span class="token punctuation">(</span><span class="token string">"contexterSettings"</span><span class="token punctuation">,</span> options<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p id="code-skip-day-14-continuing-to-generate-image-1">Hmm and instead of copy pasting the CSS, why don't I use <code>fs.readSync</code> to import it?</p>
<p>Hmmm, this seems to theoretically work, but I'm getting a huge cluster of CSS that isn't working because all the linebreaks are gone. I suppose I could minify it, but that seems silly, why can't I get a readFile output to maintain it's format?</p>
<p>I gotta remember to put my <code>\n</code>s in doublequotes too.</p>
<p>Hmmm, is the problem is <code>createTextNode</code>? Or is it just not possible to get all the linebreaks in there properly with how JS inserts text inside of elements? I guess I have to minify the CSS after all.</p>
]]></content:encoded>
	</item>
	
	<item>
		<title>Mucking with Node libraries - Day 4</title>
		<link>https://fightwithtools.dev/posts/projects/raspberrypi/day-4-mucking-with-node-libraries/?source=rss</link>
		<pubDate>Tue, 27 Dec 2022 02:59:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/projects/raspberrypi/day-4-mucking-with-node-libraries/</guid>
		<description>Let's get a node project up and running</description>
		<content:encoded><![CDATA[<h2 id="project-scope-and-todos" tabindex="-1">Project Scope and ToDos</h2>
<ol>
<li>Be able to host a server</li>
<li>Be able to build node projects</li>
<li>Be able to handle larger projects</li>
</ol>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Be able to run continually</li>
</ul>
<h2 id="day-3" tabindex="-1">Day 3</h2>
<p>Problem still not resolved. I'm starting to think maybe a hack is needed to Eleventy to make it work. Let's fiddle!</p>
<p>I'm trying my own changes with <code>graceful-fs</code> but I want to <a href="https://github.com/11ty/eleventy/pull/2633" target="_blank">try the fix that is currently in a PR</a>. To do that I'll <a href="https://stackoverflow.com/questions/8088795/installing-a-local-module-using-npm" target="_blank">need</a> <a href="https://stackoverflow.com/questions/19094630/how-do-i-uninstall-a-package-installed-using-npm-link" target="_blank">to</a> <a href="https://dev.to/erinbush/npm-linking-and-unlinking-2h1g" target="_blank">use</a> <a href="https://docs.npmjs.com/cli/v9/commands/npm-link" target="_blank"><code>npm link</code></a>.</p>
<p>Hmm, I've got some good logging changes I did with <code>nano</code> on my Raspberry Pi. Let's get <a href="https://github.com/cli/cli/blob/trunk/docs/install_linux.md" target="_blank">setup with GitHub to commit some changes</a> and <a href="https://docs.github.com/en/authentication/managing-commit-signature-verification/telling-git-about-your-signing-key" target="_blank">set</a> <a href="https://docs.github.com/en/authentication/managing-commit-signature-verification/telling-git-about-your-signing-key" target="_blank">up</a> <a href="https://homepages.inf.ed.ac.uk/da/id/gpg-howto.shtml" target="_blank">GPG</a>.</p>
<p>Noting that the command I needed to key my key ID for use here is <code>gpg --list-keys --with-colons --with-fingerprint</code> with the ID being the first long sequence on the <code>pub</code> line. (I can copy one over with <code>scp</code> although I ended up just genning a new one for that machine.)</p>
<p>Also need to setup and add an <a href="https://docs.github.com/en/authentication/connecting-to-github-with-ssh/adding-a-new-ssh-key-to-your-github-account" target="_blank">SSH Key</a>.</p>
]]></content:encoded>
	</item>
	
	<item>
		<title>Doing dangerous things with Raspberry Pi memory settings - Day 3</title>
		<link>https://fightwithtools.dev/posts/projects/raspberrypi/day-3-doing-dangerous-things-with-raspberrypi-memory/?source=rss</link>
		<pubDate>Mon, 26 Dec 2022 02:59:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/projects/raspberrypi/day-3-doing-dangerous-things-with-raspberrypi-memory/</guid>
		<description>Let's get a node project up and running</description>
		<content:encoded><![CDATA[<h2 id="project-scope-and-todos" tabindex="-1">Project Scope and ToDos</h2>
<ol>
<li>Be able to host a server</li>
<li>Be able to build node projects</li>
<li>Be able to handle larger projects</li>
</ol>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Be able to run continually</li>
</ul>
<h2 id="day-3" tabindex="-1">Day 3</h2>
<p>Ok, it does seem to be that I'm still running out of memory. This is why I wanted to move over to the Raspberry Pi Linux setup. I can start doing things I wouldn't feel comfortable doing with a work machine, like setting up a ludicrous amount of swap memory.</p>
<p><a href="https://manpages.ubuntu.com/manpages/trusty/man8/dphys-swapfile.8.html" target="_blank">Looks like this is a swapfile setting</a> I can edit that sets the default max from 2gigs to something higher. Let's try 32 and see if I blow up my machine or my USB stick.</p>
<p>I was able to do a dry run on my Macbook and it worked, but when I try to write the files it all goes to shit.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/raspberrypi/day-3-doing-dangerous-things-with-raspberrypi-memory/#code-skip-day-3-doing-dangerous-things-with-raspberrypi-memory-2" id="skip-to-code-skip-day-3-doing-dangerous-things-with-raspberrypi-memory-2" class="skip-link">Skip code block ▼</a></p>
<pre class="language-bash"><code class="language-bash">npx @11ty/eleventy <span class="token parameter variable">--quiet</span> <span class="token parameter variable">--incremental</span><br />Image request error Bad response <span class="token keyword">for</span> https://pbs.twimg.com/media/Coe4W7eUEAMxRd2.jpg <span class="token punctuation">(</span><span class="token number">404</span><span class="token punctuation">)</span>: Not Found<br />Image request error Bad response <span class="token keyword">for</span> https://pbs.twimg.com/media/B3-EfHwCIAAMDKN.jpg <span class="token punctuation">(</span><span class="token number">404</span><span class="token punctuation">)</span>: Not Found<br />Image request error Bad response <span class="token keyword">for</span> https://pbs.twimg.com/media/B3VERMVCMAAdf1U.jpg <span class="token punctuation">(</span><span class="token number">404</span><span class="token punctuation">)</span>: Not Found<br /><br /><span class="token operator">&lt;</span>--- Last few GCs ---<span class="token operator">></span><br /><br /><span class="token punctuation">[</span><span class="token number">3594</span>:0x7fd580008000<span class="token punctuation">]</span>   <span class="token number">536892</span> ms: Scavenge <span class="token punctuation">(</span>reduce<span class="token punctuation">)</span> <span class="token number">3826.7</span> <span class="token punctuation">(</span><span class="token number">3948.8</span><span class="token punctuation">)</span> -<span class="token operator">></span> <span class="token number">3826.6</span> <span class="token punctuation">(</span><span class="token number">3949.0</span><span class="token punctuation">)</span> MB, <span class="token number">3.9</span> / <span class="token number">0.0</span> ms  <span class="token punctuation">(</span>average mu <span class="token operator">=</span> <span class="token number">0.277</span>, current mu <span class="token operator">=</span> <span class="token number">0.256</span><span class="token punctuation">)</span> allocation failure<br /><span class="token punctuation">[</span><span class="token number">3594</span>:0x7fd580008000<span class="token punctuation">]</span>   <span class="token number">536923</span> ms: Scavenge <span class="token punctuation">(</span>reduce<span class="token punctuation">)</span> <span class="token number">3833.2</span> <span class="token punctuation">(</span><span class="token number">3954.5</span><span class="token punctuation">)</span> -<span class="token operator">></span> <span class="token number">3833.1</span> <span class="token punctuation">(</span><span class="token number">3954.5</span><span class="token punctuation">)</span> MB, <span class="token number">4.6</span> / <span class="token number">0.0</span> ms  <span class="token punctuation">(</span>average mu <span class="token operator">=</span> <span class="token number">0.277</span>, current mu <span class="token operator">=</span> <span class="token number">0.256</span><span class="token punctuation">)</span> allocation failure<br /><span class="token punctuation">[</span><span class="token number">3594</span>:0x7fd580008000<span class="token punctuation">]</span>   <span class="token number">536947</span> ms: Scavenge <span class="token punctuation">(</span>reduce<span class="token punctuation">)</span> <span class="token number">3838.1</span> <span class="token punctuation">(</span><span class="token number">3958.8</span><span class="token punctuation">)</span> -<span class="token operator">></span> <span class="token number">3838.0</span> <span class="token punctuation">(</span><span class="token number">3958.5</span><span class="token punctuation">)</span> MB, <span class="token number">4.0</span> / <span class="token number">0.0</span> ms  <span class="token punctuation">(</span>average mu <span class="token operator">=</span> <span class="token number">0.277</span>, current mu <span class="token operator">=</span> <span class="token number">0.256</span><span class="token punctuation">)</span> allocation failure<br /><br /><br /><span class="token operator">&lt;</span>--- JS stacktrace ---<span class="token operator">></span><br /><br />FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memory<br /> <span class="token number">1</span>: 0x108e19815 node::Abort<span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">(</span>.cold.1<span class="token punctuation">)</span> <span class="token punctuation">[</span>/Users/zuckerscharffa/.nvm/versions/node/v16.13.1/bin/node<span class="token punctuation">]</span><br /> <span class="token number">2</span>: 0x107b18aa9 node::Abort<span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">[</span>/Users/zuckerscharffa/.nvm/versions/node/v16.13.1/bin/node<span class="token punctuation">]</span><br /> <span class="token number">3</span>: 0x107b18c1f node::OnFatalError<span class="token punctuation">(</span>char const*, char const*<span class="token punctuation">)</span> <span class="token punctuation">[</span>/Users/zuckerscharffa/.nvm/versions/node/v16.13.1/bin/node<span class="token punctuation">]</span><br /> <span class="token number">4</span>: 0x107c99877 v8::Utils::ReportOOMFailure<span class="token punctuation">(</span>v8::internal::Isolate*, char const*, bool<span class="token punctuation">)</span> <span class="token punctuation">[</span>/Users/zuckerscharffa/.nvm/versions/node/v16.13.1/bin/node<span class="token punctuation">]</span><br /> <span class="token number">5</span>: 0x107c99813 v8::internal::V8::FatalProcessOutOfMemory<span class="token punctuation">(</span>v8::internal::Isolate*, char const*, bool<span class="token punctuation">)</span> <span class="token punctuation">[</span>/Users/zuckerscharffa/.nvm/versions/node/v16.13.1/bin/node<span class="token punctuation">]</span><br /> <span class="token number">6</span>: 0x107e3ac65 v8::internal::Heap::FatalProcessOutOfMemory<span class="token punctuation">(</span>char const*<span class="token punctuation">)</span> <span class="token punctuation">[</span>/Users/zuckerscharffa/.nvm/versions/node/v16.13.1/bin/node<span class="token punctuation">]</span><br /> <span class="token number">7</span>: 0x107e3ecad v8::internal::Heap::RecomputeLimits<span class="token punctuation">(</span>v8::internal::GarbageCollector<span class="token punctuation">)</span> <span class="token punctuation">[</span>/Users/zuckerscharffa/.nvm/versions/node/v16.13.1/bin/node<span class="token punctuation">]</span><br /> <span class="token number">8</span>: 0x107e3b58d v8::internal::Heap::PerformGarbageCollection<span class="token punctuation">(</span>v8::internal::GarbageCollector, v8::GCCallbackFlags<span class="token punctuation">)</span> <span class="token punctuation">[</span>/Users/zuckerscharffa/.nvm/versions/node/v16.13.1/bin/node<span class="token punctuation">]</span><br /> <span class="token number">9</span>: 0x107e38aad v8::internal::Heap::CollectGarbage<span class="token punctuation">(</span>v8::internal::AllocationSpace, v8::internal::GarbageCollectionReason, v8::GCCallbackFlags<span class="token punctuation">)</span> <span class="token punctuation">[</span>/Users/zuckerscharffa/.nvm/versions/node/v16.13.1/bin/node<span class="token punctuation">]</span><br /><span class="token number">10</span>: 0x107e45de0 v8::internal::Heap::AllocateRawWithLightRetrySlowPath<span class="token punctuation">(</span>int, v8::internal::AllocationType, v8::internal::AllocationOrigin, v8::internal::AllocationAlignment<span class="token punctuation">)</span> <span class="token punctuation">[</span>/Users/zuckerscharffa/.nvm/versions/node/v16.13.1/bin/node<span class="token punctuation">]</span><br /><span class="token number">11</span>: 0x107e45e61 v8::internal::Heap::AllocateRawWithRetryOrFailSlowPath<span class="token punctuation">(</span>int, v8::internal::AllocationType, v8::internal::AllocationOrigin, v8::internal::AllocationAlignment<span class="token punctuation">)</span> <span class="token punctuation">[</span>/Users/zuckerscharffa/.nvm/versions/node/v16.13.1/bin/node<span class="token punctuation">]</span><br /><span class="token number">12</span>: 0x107e0cfce v8::internal::FactoryBase<span class="token operator">&lt;</span>v8::internal::Factory<span class="token operator">></span>::NewRawTwoByteString<span class="token punctuation">(</span>int, v8::internal::AllocationType<span class="token punctuation">)</span> <span class="token punctuation">[</span>/Users/zuckerscharffa/.nvm/versions/node/v16.13.1/bin/node<span class="token punctuation">]</span><br /><span class="token number">13</span>: 0x1080e7c88 v8::internal::String::SlowFlatten<span class="token punctuation">(</span>v8::internal::Isolate*, v8::internal::Handle<span class="token operator">&lt;</span>v8::internal::ConsString<span class="token operator">></span>, v8::internal::AllocationType<span class="token punctuation">)</span> <span class="token punctuation">[</span>/Users/zuckerscharffa/.nvm/versions/node/v16.13.1/bin/node<span class="token punctuation">]</span><br /><span class="token number">14</span>: 0x107cb65ad v8::String::Utf8Length<span class="token punctuation">(</span>v8::Isolate*<span class="token punctuation">)</span> const <span class="token punctuation">[</span>/Users/zuckerscharffa/.nvm/versions/node/v16.13.1/bin/node<span class="token punctuation">]</span><br /><span class="token number">15</span>: 0x107af3e0b node::Buffer::<span class="token punctuation">(</span>anonymous namespace<span class="token punctuation">)</span>::ByteLengthUtf8<span class="token punctuation">(</span>v8::FunctionCallbackInfo<span class="token operator">&lt;</span>v8::Value<span class="token operator">></span> const<span class="token operator">&amp;</span><span class="token punctuation">)</span> <span class="token punctuation">[</span>/Users/zuckerscharffa/.nvm/versions/node/v16.13.1/bin/node<span class="token punctuation">]</span><br /><span class="token number">16</span>: 0x108506e8c Builtins_CallApiCallback <span class="token punctuation">[</span>/Users/zuckerscharffa/.nvm/versions/node/v16.13.1/bin/node<span class="token punctuation">]</span><br /><span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span>    <span class="token number">3503</span> abort      npx @11ty/eleventy <span class="token parameter variable">--quiet</span> <span class="token parameter variable">--incremental</span></code></pre>
<p id="code-skip-day-3-doing-dangerous-things-with-raspberrypi-memory-2">Meanwhile on the Raspberry Pi I was able to get it closer to running it seems, but even a dry-run hits the RAM max. Very strange because <code>htop</code> doesn't seem to show it ever hitting max. Is it not able to access the swap space?</p>
<p>The failures here seem to be the important ones?</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/raspberrypi/day-3-doing-dangerous-things-with-raspberrypi-memory/#code-skip-day-3-doing-dangerous-things-with-raspberrypi-memory-1" id="skip-to-code-skip-day-3-doing-dangerous-things-with-raspberrypi-memory-1" class="skip-link">Skip code block ▼</a></p>
<pre class="language-bash"><code class="language-bash"> <span class="token number">6</span>: 0x10cc46c65 v8::internal::Heap::FatalProcessOutOfMemory<span class="token punctuation">(</span>char const*<span class="token punctuation">)</span> <span class="token punctuation">[</span>/Users/zuckerscharffa/.nvm/versions/node/v16.13.1/bin/node<span class="token punctuation">]</span><br /> <span class="token number">7</span>: 0x10cc4acad v8::internal::Heap::RecomputeLimits<span class="token punctuation">(</span>v8::internal::GarbageCollector<span class="token punctuation">)</span> <span class="token punctuation">[</span>/Users/zuckerscharffa/.nvm/versions/node/v16.13.1/bin/node<span class="token punctuation">]</span><br /> <span class="token number">8</span>: 0x10cc4758d v8::internal::Heap::PerformGarbageCollection<span class="token punctuation">(</span>v8::internal::GarbageCollector, v8::GCCallbackFlags<span class="token punctuation">)</span> <span class="token punctuation">[</span>/Users/zuckerscharffa/.nvm/versions/node/v16.13.1/bin/node<span class="token punctuation">]</span><br /> <span class="token number">9</span>: 0x10cc44aad v8::internal::Heap::CollectGarbage<span class="token punctuation">(</span>v8::internal::AllocationSpace, v8::internal::GarbageCollectionReason, v8::GCCallbackFlags<span class="token punctuation">)</span> <span class="token punctuation">[</span>/Users/zuckerscharffa/.nvm/versions/node/v16.13.1/bin/node<span class="token punctuation">]</span><br /><span class="token number">10</span>: 0x10cc51de0 v8::internal::Heap::AllocateRawWithLightRetrySlowPath<span class="token punctuation">(</span>int, v8::internal::AllocationType, v8::internal::AllocationOrigin, v8::internal::AllocationAlignment<span class="token punctuation">)</span> <span class="token punctuation">[</span>/Users/zuckerscharffa/.nvm/versions/node/v16.13.1/bin/node<span class="token punctuation">]</span></code></pre>
]]></content:encoded>
	</item>
	
	<item>
		<title>Getting NPM install running on Raspberry Pi - Day 2</title>
		<link>https://fightwithtools.dev/posts/projects/raspberrypi/day-2-raspberrypi-npm-install/?source=rss</link>
		<pubDate>Sun, 25 Dec 2022 02:59:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/projects/raspberrypi/day-2-raspberrypi-npm-install/</guid>
		<description>Let's get a node project up and running</description>
		<content:encoded><![CDATA[<h2 id="project-scope-and-todos" tabindex="-1">Project Scope and ToDos</h2>
<ol>
<li>Be able to host a server</li>
<li>Be able to build node projects</li>
<li>Be able to handle larger projects</li>
</ol>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Be able to run continually</li>
</ul>
<h2 id="day-2" tabindex="-1">Day 2</h2>
<p>Ok, I've got a complicated project here to run <code>npm install</code> on. Let's see if it works.</p>
<p>Ok, so I've got my big project on the Raspberry Pi and NPM install seems to have worked despite throwing a bunch of errors. But now I've got</p>
<p><code>FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memory</code></p>
<p>There is <a href="https://stackoverflow.com/questions/54137165/fatal-error-ineffective-mark-compacts-near-heap-limit-allocation-failed-javas" target="_blank">a suggested way forward</a>, let's try it.</p>
<p>I'm going to add this as a command to my <code>package.json</code>.</p>
<p><code>&quot;start:heavy&quot;: &quot;NODE_OPTIONS=--max-old-space-size=16384 npm run start&quot;,</code></p>
<p>Ok, let's give that a try.</p>
<p>Nope, still maxing out. In fact, now it does so immediately. Oh, I see. <a href="https://stackoverflow.com/questions/53230823/fatal-error-ineffective-mark-compacts-near-heap-limit-allocation-failed-javas" target="_blank">I've made the allowed use of RAM more than the 8gigs in my Raspberry Pi 4</a>.</p>
<p>Hmmm, still getting <code>FATAL ERROR: Committing semi space failed. Allocation failed - JavaScript heap out of memory</code>.</p>
<p>This seems to be a memory issue. I think I can increase the memory fast by using a USB key as swap space? Let's try that.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/raspberrypi/day-2-raspberrypi-npm-install/#code-skip-day-2-raspberrypi-npm-install-3" id="skip-to-code-skip-day-2-raspberrypi-npm-install-3" class="skip-link">Skip code block ▼</a></p>
<pre class="language-bash"><code class="language-bash">NAME        MAJ:MIN RM   SIZE RO TYPE MOUNTPOINT<br />sda           <span class="token number">8</span>:0    <span class="token number">1</span> <span class="token number">119</span>.2G  <span class="token number">0</span> disk<br />├─sda1        <span class="token number">8</span>:1    <span class="token number">1</span>   200M  <span class="token number">0</span> part<br />└─sda2        <span class="token number">8</span>:2    <span class="token number">1</span>   119G  <span class="token number">0</span> part /media/zs/BigStick<br />mmcblk0     <span class="token number">179</span>:0    <span class="token number">0</span>  <span class="token number">29</span>.7G  <span class="token number">0</span> disk<br />├─mmcblk0p1 <span class="token number">179</span>:1    <span class="token number">0</span>   <span class="token number">2</span>.4G  <span class="token number">0</span> part<br />├─mmcblk0p2 <span class="token number">179</span>:2    <span class="token number">0</span>     1K  <span class="token number">0</span> part<br />├─mmcblk0p5 <span class="token number">179</span>:5    <span class="token number">0</span>    32M  <span class="token number">0</span> part<br />├─mmcblk0p6 <span class="token number">179</span>:6    <span class="token number">0</span>   256M  <span class="token number">0</span> part /boot<br />└─mmcblk0p7 <span class="token number">179</span>:7    <span class="token number">0</span>  <span class="token number">27</span>.1G  <span class="token number">0</span> part /</code></pre>
<p id="code-skip-day-2-raspberrypi-npm-install-3">Ok, I've reformatted my BigStick <a href="https://www.addictivetips.com/ubuntu-linux-tips/use-swap-space-on-usb-drive-in-rasbian-linux/" target="_blank">using the instructions at addictive tips</a>. It worked pretty well so far, but I did have to <a href="https://www.computernetworkingnotes.com/linux-tutorials/how-to-create-swap-partition-in-linux.html" target="_blank">change the type to Linux Swap which is noted as 82 instead of 83 here</a>.</p>
<p>I rebooted and it looks like, by using <code>free -m</code> I can see I've added about 2 gigs of swap, not the whole stick. Why is that the case?</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/raspberrypi/day-2-raspberrypi-npm-install/#code-skip-day-2-raspberrypi-npm-install-2" id="skip-to-code-skip-day-2-raspberrypi-npm-install-2" class="skip-link">Skip code block ▼</a></p>
<pre class="language-bash"><code class="language-bash">               total        used        <span class="token function">free</span>      shared  buff/cache   available<br />Mem:            <span class="token number">7898</span>         <span class="token number">244</span>        <span class="token number">7160</span>          <span class="token number">35</span>         <span class="token number">493</span>        <span class="token number">7393</span><br />Swap:           <span class="token number">2047</span>           <span class="token number">0</span>        <span class="token number">2047</span></code></pre>
<p id="code-skip-day-2-raspberrypi-npm-install-2">It <a href="https://forums.raspberrypi.com/viewtopic.php?t=150141" target="_blank">looks like that's the max using the tools I used</a>. But lets try leaving it here and rerunning my commands.</p>
<p>Well, it definitely used the swap space and I don't think I ever saw it run out of Memory, but it still failed. New error this time though! Let's reproduce here in full:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/raspberrypi/day-2-raspberrypi-npm-install/#code-skip-day-2-raspberrypi-npm-install-1" id="skip-to-code-skip-day-2-raspberrypi-npm-install-1" class="skip-link">Skip code block ▼</a></p>
<pre class="language-bash"><code class="language-bash"><br /><span class="token operator">&lt;</span>--- Last few GCs ---<span class="token operator">></span><br /><br /><span class="token punctuation">[</span><span class="token number">3171</span>:0x40cd090<span class="token punctuation">]</span>  <span class="token number">1578766</span> ms: Scavenge <span class="token number">2040.1</span> <span class="token punctuation">(</span><span class="token number">2088.9</span><span class="token punctuation">)</span> -<span class="token operator">></span> <span class="token number">2039.9</span> <span class="token punctuation">(</span><span class="token number">2088.9</span><span class="token punctuation">)</span> MB, <span class="token number">26.5</span> / <span class="token number">0.1</span> ms  <span class="token punctuation">(</span>average mu <span class="token operator">=</span> <span class="token number">0.874</span>, current mu <span class="token operator">=</span> <span class="token number">0.340</span><span class="token punctuation">)</span> external memory pressure<br /><span class="token punctuation">[</span><span class="token number">3171</span>:0x40cd090<span class="token punctuation">]</span>  <span class="token number">1578831</span> ms: Scavenge <span class="token number">2039.9</span> <span class="token punctuation">(</span><span class="token number">2088.9</span><span class="token punctuation">)</span> -<span class="token operator">></span> <span class="token number">2039.7</span> <span class="token punctuation">(</span><span class="token number">2088.9</span><span class="token punctuation">)</span> MB, <span class="token number">63.4</span> / <span class="token number">0.1</span> ms  <span class="token punctuation">(</span>average mu <span class="token operator">=</span> <span class="token number">0.874</span>, current mu <span class="token operator">=</span> <span class="token number">0.340</span><span class="token punctuation">)</span> external memory pressure<br /><span class="token punctuation">[</span><span class="token number">3171</span>:0x40cd090<span class="token punctuation">]</span>  <span class="token number">1582402</span> ms: Mark-sweep <span class="token number">2041.7</span> <span class="token punctuation">(</span><span class="token number">2090.6</span><span class="token punctuation">)</span> -<span class="token operator">></span> <span class="token number">2026.5</span> <span class="token punctuation">(</span><span class="token number">2085.1</span><span class="token punctuation">)</span> MB, <span class="token number">3102.0</span> / <span class="token number">2.0</span> ms  <span class="token punctuation">(</span>average mu <span class="token operator">=</span> <span class="token number">0.783</span>, current mu <span class="token operator">=</span> <span class="token number">0.292</span><span class="token punctuation">)</span> allocation failure GC <span class="token keyword">in</span> old space requested<br /><br /><br /><span class="token operator">&lt;</span>--- JS stacktrace ---<span class="token operator">></span><br /><br />FATAL ERROR: NewSpace::Rebalance Allocation failed - JavaScript heap out of memory<br />Aborted</code></pre>
<p id="code-skip-day-2-raspberrypi-npm-install-1">New error is good!</p>
]]></content:encoded>
	</item>
	
	<item>
		<title>Setting up a Raspberry Pi for Development - Day 1</title>
		<link>https://fightwithtools.dev/posts/projects/raspberrypi/day-1-setup/?source=rss</link>
		<pubDate>Sat, 24 Dec 2022 02:59:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/projects/raspberrypi/day-1-setup/</guid>
		<description>Getting together everything I need for a remote development environment.</description>
		<content:encoded><![CDATA[<h2 id="project-scope-and-todos" tabindex="-1">Project Scope and ToDos</h2>
<ol>
<li>Be able to host a server</li>
<li>Be able to build node projects</li>
<li>Be able to handle larger projects</li>
</ol>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Be able to run continually</li>
</ul>
<h2 id="day-1" tabindex="-1">Day 1</h2>
<p>I've had a Canakit Raspberry Pi 4 sitting around for a while and while trying to set up a site to host an archive of my Tweets <a href="https://github.com/tweetback/tweetback/issues/10" target="_blank">I've maxed out some some things on my MacBook</a>. This isn't great, but there seem to be solutions. However, those solutions require mucking about with some pretty core system settings that maybe I don't want to mess with on my main machine.</p>
<p>So, it makes sense to set this machine up to handle these projects. That means getting a dev environment running with Node capabilities. The package I got ships with <a href="https://www.raspberrypi.com/news/introducing-noobs/" target="_blank">NOOBS</a> a tool for setting it up with <a href="https://www.raspbian.org/" target="_blank">Raspbian</a> a Linux variant specialized for Pis. I slid that in, connected it to the internet via ethernet, and then let it do the install. First step was easy.</p>
<p>Next step is allowing me to control it remotely. I have a tiny keyboard and tiny monitor that helps me with my Pi setup, but it isn't really great to work on, so let's do some alternatives right?</p>
<p>I can go into the first menu and go to Raspberry Pi Configuration under preferences. From there I can turn on SSH and VNC connections. That's a good start!</p>
<p>Now that I've turned this on I can SSH in. But I'll need to know my local IP.</p>
<p><code>hostname -I</code></p>
<p>That gives me my the IP. Useful! I also want it to have a real hostname so I can more easily see it on the network.</p>
<p><code>sudo hostnamectl set-hostname newhostname</code><br />
<code>sudo vi /etc/hosts</code></p>
<p>Then I can replace the value that follows <code>127.0.1.1</code> (usually <code>raspberrypi</code>) with my new hostname <code>newhostname</code>.</p>
<p>Now from my normal machine I can SSH in.</p>
<p><code>ssh username@192.168.1.xx</code></p>
<p>I then accept the new key and enter my password and I'm in. I can see my new hostname.</p>
<p>Ok, I have a bluetooth dongle I might want to use later, so I'll make sure I've got that all configured.</p>
<p>With <code>lsusb</code> I can see all the USB items that are attached to the device.</p>
<p>I'll first update my packages.</p>
<p><code>sudo apt-get update</code></p>
<p>Then I'll make sure all the bluetooth tools are ready to go.</p>
<p><code>sudo apt install bluetooth pi-bluetooth bluez blueman</code></p>
<p>I'll make sure the default configuration is in place.</p>
<p><code>sudo update-rc.d bluetooth defaults</code></p>
<p>I'll double check and can see that the <code>git</code> command is working. So we've got that.</p>
<p>Next, from my home directory, I'll make a folder to put my projects into:</p>
<p><code>mkdir Projects</code></p>
<p>I want to pull my first big project in from my main machine. I could pull it on to a USB stick and copy it back and forth, but there is a faster option.</p>
<p>In a new console window, I'll set up that connection and use <code>-az</code> in order to make the copying of the files as efficient as possible.</p>
<p><code>rsync -az ~/ProjectsFolder/tweetback username@192.168.1.xxx:~/ProjectsFolder/twitterwork/</code></p>
<p>This will copy the folder on my local machine <code>tweetback</code> as a folder into <code>~/ProjectsFolder/twitterwork/</code> giving me my project at <code>~/ProjectsFolder/twitterwork/tweetback</code>. Ok, now to let it move over 5+ gigs. All done in around 20 minutes!</p>
<p>I might want to do some actual folder sharing later, so for that <code>sudo apt install samba -y</code></p>
<p>I want to set up to use Node now. Easy way to do that? Let's use <code>nvm</code> which we can set up to manage our node versions for use in various projects:</p>
<p><code>curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.37.2/install.sh | bash</code></p>
<p>Now I can install node versions with <code>nvm</code> like <code>nvm install 14</code></p>
<p>Now, let's make this a slightly better dev environment. We're going to install ZSH.</p>
<p><code>sudo apt-get install zsh -y</code></p>
<p>and now Oh My ZSH.</p>
<p><code>sh -c &quot;$(curl -fsSL https://raw.github.com/robbyrussell/oh-my-zsh/master/tools/install.sh)&quot;</code></p>
<p>Now let's install Powerline fonts.</p>
<p><code>git clone https://github.com/powerline/fonts</code><br />
<code>cd fonts</code><br />
<code>./install.sh</code></p>
<p>Now we can try out using the <code>agnoster</code> theme for ZSH, which is my fav.</p>
<p>Here's the bash configuration for NVM:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/raspberrypi/day-1-setup/#code-skip-day-1-setup-1" id="skip-to-code-skip-day-1-setup-1" class="skip-link">Skip code block ▼</a></p>
<pre class="language-bash"><code class="language-bash"><span class="token builtin class-name">export</span> <span class="token assign-left variable">NVM_DIR</span><span class="token operator">=</span><span class="token string">"<span class="token environment constant">$HOME</span>/.nvm"</span><br /><span class="token punctuation">[</span> <span class="token parameter variable">-s</span> <span class="token string">"<span class="token variable">$NVM_DIR</span>/nvm.sh"</span> <span class="token punctuation">]</span> <span class="token operator">&amp;&amp;</span> <span class="token punctuation">\</span>. <span class="token string">"<span class="token variable">$NVM_DIR</span>/nvm.sh"</span>  <span class="token comment"># This loads nvm</span><br /><span class="token punctuation">[</span> <span class="token parameter variable">-s</span> <span class="token string">"<span class="token variable">$NVM_DIR</span>/bash_completion"</span> <span class="token punctuation">]</span> <span class="token operator">&amp;&amp;</span> <span class="token punctuation">\</span>. <span class="token string">"<span class="token variable">$NVM_DIR</span>/bash_completion"</span>  <span class="token comment"># This loads nvm bash_completion</span></code></pre>
<p id="code-skip-day-1-setup-1">Hmm, adopting my version of NVM as a manager isn't quite working. It looks like there are some tools for managing ZSH plugins. Let's take a look.</p>
<p>Let's try <a href="https://github.com/zplug/zplug" target="_blank">Zplug</a>?</p>
<p>Having <a href="https://github.com/zplug/zplug/issues/535" target="_blank">this issue</a>. Hmmm.</p>
<p>First I had to <code>chmod 775 /home/zs/.zplug</code></p>
<p>Then I had to do <code>zplug 'tj/n', as:command, use:'bin/n'</code> from <a href="https://github.com/zplug/zplug/issues/204#issuecomment-225431044" target="_blank">here</a>.</p>
<p>Then <a href="https://github.com/lukechilds/zsh-nvm" target="_blank">I set up <code>zsh-nvm</code></a> using zplug - <code>https://github.com/lukechilds/zsh-nvm</code>.</p>
<p>Next I need to remove node_modules. I'll need to rebuild everything on the new Linux environment.</p>
<p>Ok, that's it for today, I'll take care of that tomorrow.</p>
]]></content:encoded>
	</item>
	
	<item>
		<title>Context Center Timelines - Day 13 - Generate Timeline Item Image</title>
		<link>https://fightwithtools.dev/posts/projects/context-timelines/day-13-more-html-to-image-generation/?source=rss</link>
		<pubDate>Mon, 14 Nov 2022 02:59:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/projects/context-timelines/day-13-more-html-to-image-generation/</guid>
		<description>Getting a preview image auto-generated.</description>
		<content:encoded><![CDATA[<h2 id="project-scope-and-todos" tabindex="-1">Project Scope and ToDos</h2>
<ol>
<li>Create timeline pages where one can see the whole timeline of a particular event</li>
<li>Give timeline items type or category icons so that you can easily scan what is happening.</li>
<li>Allow the user to enter the timeline at any individually sharable link of an event and seamlessly scroll up and down</li>
</ol>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Deliver timelines as a plugin that can be extended by other Eleventy users</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Auto-create social-media-ready screenshots of a timeline item</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Integrate with Contexter to have context-full link cards in the timeline</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Leverage the Live Blog format of Schema dot org</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Allow each entry to be its own Markdown file</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Handle SASS instead of CSS</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Fast Scroller by Month and Year</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Add timelines and individual timeline items to the sitemap</li>
</ul>
<h2 id="day-13" tabindex="-1">Day 13</h2>
<p>It looks like there is no straightforward way to handle the Canvas element with JSDOM without a <em>lot</em> of hacking. When people out there are writing about trying to do this purely through Node, it appears the only real choice is using <a href="https://github.com/puppeteer" target="_blank">puppeteer</a>.</p>
<p>Ok. Looks like there is a package for doing it this way. <a href="https://www.npmjs.com/package/node-html-to-image" target="_blank">Let's try <code>node-html-to-image</code> instead</a>. Ugh. I'm going to basically have to redo my template if I want to do this right. But... for now I might just dump it out of JSDOM now to see if it works.</p>
<p>I did a little test and it looks like it works!</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/context-timelines/day-13-more-html-to-image-generation/#code-skip-day-13-more-html-to-image-generation-1" id="skip-to-code-skip-day-13-more-html-to-image-generation-1" class="skip-link">Skip code block ▼</a></p>
<pre class="language-js"><code class="language-js">console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">"Create Template Social Image Enters"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token keyword">const</span> dom <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">JSDOM</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">&lt;!DOCTYPE html>&lt;head><br />&lt;link href="https://fonts.googleapis.com/css?family=Roboto+Slab|Hind+Vadodara:400,600" rel="stylesheet" type="text/css"><br />&lt;/head>&lt;body>&lt;/body></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token keyword">const</span> window <span class="token operator">=</span> dom<span class="token punctuation">.</span>window<span class="token punctuation">;</span><br /><span class="token keyword">const</span> document <span class="token operator">=</span> window<span class="token punctuation">.</span>document<span class="token punctuation">;</span><br /><span class="token keyword">const</span> customElements <span class="token operator">=</span> window<span class="token punctuation">.</span>customElements<span class="token punctuation">;</span><br /><span class="token keyword">const</span> HTMLElement <span class="token operator">=</span> window<span class="token punctuation">.</span>HTMLElement<span class="token punctuation">;</span><br /><span class="token keyword">function</span> <span class="token function">h</span><span class="token punctuation">(</span><span class="token parameter">tag<span class="token punctuation">,</span> attrs<span class="token punctuation">,</span> <span class="token operator">...</span>children</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /><span class="token keyword">var</span> el <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">createElement</span><span class="token punctuation">(</span>tag<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">isPlainObject</span><span class="token punctuation">(</span>attrs<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />	<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">let</span> k <span class="token keyword">in</span> attrs<span class="token punctuation">)</span> <span class="token punctuation">{</span><br />		<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">typeof</span> attrs<span class="token punctuation">[</span>k<span class="token punctuation">]</span> <span class="token operator">===</span> <span class="token string">"function"</span><span class="token punctuation">)</span><br />			el<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span>k<span class="token punctuation">,</span> attrs<span class="token punctuation">[</span>k<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />		<span class="token keyword">else</span> el<span class="token punctuation">.</span><span class="token function">setAttribute</span><span class="token punctuation">(</span>k<span class="token punctuation">,</span> attrs<span class="token punctuation">[</span>k<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token punctuation">}</span><br /><span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>attrs<span class="token punctuation">)</span> <span class="token punctuation">{</span><br />	children <span class="token operator">=</span> <span class="token punctuation">[</span>attrs<span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">concat</span><span class="token punctuation">(</span>children<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span><br />children <span class="token operator">=</span> children<span class="token punctuation">.</span><span class="token function">filter</span><span class="token punctuation">(</span>Boolean<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">let</span> child <span class="token keyword">of</span> children<span class="token punctuation">)</span> el<span class="token punctuation">.</span><span class="token function">append</span><span class="token punctuation">(</span>child<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token keyword">return</span> el<span class="token punctuation">;</span><br /><span class="token punctuation">}</span><br /><br /><span class="token keyword">function</span> <span class="token function">isPlainObject</span><span class="token punctuation">(</span><span class="token parameter">v</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /><span class="token keyword">return</span> v <span class="token operator">&amp;&amp;</span> <span class="token keyword">typeof</span> v <span class="token operator">===</span> <span class="token string">"object"</span> <span class="token operator">&amp;&amp;</span> <span class="token class-name">Object</span><span class="token punctuation">.</span>prototype <span class="token operator">===</span> v<span class="token punctuation">.</span>__proto__<span class="token punctuation">;</span><br /><span class="token punctuation">}</span><br />document<span class="token punctuation">.</span>body<span class="token punctuation">.</span><span class="token function">append</span><span class="token punctuation">(</span><span class="token function">h</span><span class="token punctuation">(</span><span class="token string">"div"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token function">h</span><span class="token punctuation">(</span><span class="token string">"p"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token string">"Hello world"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token function">htmlToImage</span><span class="token punctuation">(</span><span class="token punctuation">{</span><br /><span class="token literal-property property">output</span><span class="token operator">:</span> <span class="token string">"./image.png"</span><span class="token punctuation">,</span><br /><span class="token literal-property property">html</span><span class="token operator">:</span> dom<span class="token punctuation">.</span><span class="token function">serialize</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br /><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">"The image was created successfully!"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p id="code-skip-day-13-more-html-to-image-generation-1">Ok, let's see if we can use this with the timeline code. Wow... doing every image at once is <em>a lot</em>. The system is freaking out, so that's not good. Also it re-triggers the build task, which... I dunno if I want that?</p>
<p>Ugh, that didn't work.</p>
<p><img src="https://fightwithtools.dev/img/node-html-img-test-one.png" alt="A whole mess of HTML not properly rendering" /></p>
<p><code>git commit -m &quot;Another test of the image generation&quot;</code></p>
]]></content:encoded>
	</item>
	
	<item>
		<title>Why you should find the Mastodon instance that works for you</title>
		<link>https://fightwithtools.dev/posts/writing/why-you-should-find-a-mastodon-instance/?source=rss</link>
		<pubDate>Sun, 06 Nov 2022 21:30:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/writing/why-you-should-find-a-mastodon-instance/</guid>
		<description>You can start with one of the main popular instances of Mastodon but, if you want to make it fun, you need to find an instance that matches your interests.</description>
		<content:encoded><![CDATA[<h2 id="some-help-for-having-fun-on-mastodon" tabindex="-1">Some help for having fun on Mastodon</h2>
<p>Self-hosting Mastodon as a personal instance is a neat trick I see some of you are doing, but it is just as bad for your experience as joining one of the super popular main instances. It just isn't really how you're going to get the most out of the tool. Let me explain.</p>
<p>Mastodon is decentralized in a general sense, but more importantly the service is federated, which means it's capable of being meaningfully decentralized... but still having centers of activity. The point isn't decentralization, it's to find a center you want to live in.</p>
<p><img src="https://fightwithtools.dev/img/network-models.jpg" alt="From left to right: Centralized, Federated, Distributed" /><br />
<em>From left to right: Centralized, Federated, Distributed, <a href="https://docs.joinmastodon.org/" target="_blank">from the Mastodon Website</a>.</em></p>
<p>To get the most out of it, you have to find an instance you like, with rules you like, people you like, and—most importantly—people interested in the same stuff and content you want to talk about. Because the secret power of Mastodon is...</p>
<p><strong>your instance's Local.</strong></p>
<h2 id="why-do-you-need-to-care-about-your-local-timeline" tabindex="-1">Why do you need to care about your Local Timeline?</h2>
<p>See Mastodon has no algorithm or suggested friends on purpose because what it has instead is federated instances &amp; their Locals. Your Local, if you've got a good one, will replace all those recommendation tools. By the way, this is why the main instance sucks, its Local is nonsense. You use it to find a better one.</p>
<p>Twitter doesn't map on to Mastodon evenly, but it is easier to understand if you think of an instance like a Twitter list, or your Notified feed. Most people who use Twitter well either: live in lists, have a small Follow count, or rely on the algorithm (which emulates the other 2).</p>
<p>You don't actually discover people or stuff on Twitter, other people discover it and discover each other and boost other accounts or sites; then you see those boosts. It's not magical, Twitter just makes the retweet text small so you don't notice and think there's 'magic'.</p>
<p>Like all algorithmic magic it's just people. For Mastodon you join the main instance, you see a person talking about stuff you like to talk about and you check out their instance. If that instance is mostly talking about the type of stuff you like to talk about in the way you like to talk about it, you join! Mastodon makes it very easy for you to port your account over from one instance to another. Your follows, settings, etc..., all that gets moved over easily with your account, making it much easier to switch out algorithmic discovery with Local Timeline discovery.</p>
<h2 id="more-than-one-interest" tabindex="-1">More than one interest?</h2>
<p>Chances are, you're interested in more than one thing! That's cool, set up more accounts! Lurk on servers. I lurk on an art instance and a politics instance and check in on their Locals semi regularly. I basically use these lurker accounts the same way I use Twitter lists, but with less duplication. Those accounts are also little feeder fish, sometimes they'll spot something or someone I really like and I'll follow or boost on my main account. One day, if I decide I'm more interested in drawing than in building indie websites, I can move my main account again!</p>
<p>When things go viral on Mastodon it's usually stuff you saw on your Local. By boosting it people who follow you see it, but also people who don't know you but like the same stuff you do on your instance will see it on their Local and wow you've got new friends now.</p>
<p>When you follow someone from a new instance, they bring cool stuff with them, so you can search their instance, see your favorite tags on more instances relevant to you and have an easier time finding new and interesting stuff. That's why I follow interesting instances' admins along with whoever brought me there. Boosting and following also creates a higher likelihood other people in your instance will find new users and interesting instances! A bonus for everyone! That's what I mean when I say the Local is the key: that's your Discovery, Virality, and Suggested Friends, all at once.</p>
<h2 id="still-want-to-do-it-yourself" tabindex="-1">Still want to do it yourself?</h2>
<p>So, if you have a group of people with similar interests, by all means start up a server and get them all together on your own instance. Or, as you use a more general instance, gather a group of users and split off. But... a personal instance just for yourself? You're giving yourself extra work to miss out on the fun.</p>
<p>If you just want to broadcast, you can <a href="https://indieweb.org/WordPress_ActivityPub_plugin" target="_blank">rig your WordPress blog up to ActivityPub</a>. But if you want to participate: join a few instances, find one you like, and make it home. Solo instances, like big undifferentiated instances, are missing the point of the whole system.</p>
<p>This is, I think, the most confusing part about Mastodon. Sorry, it definitely isn't perfect. To be clear, it isn't just Twitter with a different skin! If that sounds interesting then you'll have to invest some time in figuring it out. We had to with Twitter too!</p>
<p>Oh and uh, <a href="https://indieweb.social/@Chronotope" target="_blank">follow me on Mastodon</a>!</p>
<hr />
<p><em>Adapted from <a href="https://twitter.com/Chronotope/status/1588145803796807682" target="_blank">my original Twitter thread</a></em></p>
]]></content:encoded>
	</item>
	
	<item>
		<title>Context Center Timelines - Day 12 - Generate Timeline Item Image</title>
		<link>https://fightwithtools.dev/posts/projects/context-timelines/day-12-generate-timeline-item-image/?source=rss</link>
		<pubDate>Wed, 02 Nov 2022 02:59:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/projects/context-timelines/day-12-generate-timeline-item-image/</guid>
		<description>Getting a preview image auto-generated.</description>
		<content:encoded><![CDATA[<h2 id="project-scope-and-todos" tabindex="-1">Project Scope and ToDos</h2>
<ol>
<li>Create timeline pages where one can see the whole timeline of a particular event</li>
<li>Give timeline items type or category icons so that you can easily scan what is happening.</li>
<li>Allow the user to enter the timeline at any individually sharable link of an event and seamlessly scroll up and down</li>
</ol>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Deliver timelines as a plugin that can be extended by other Eleventy users</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Auto-create social-media-ready screenshots of a timeline item</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Integrate with Contexter to have context-full link cards in the timeline</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Leverage the Live Blog format of Schema dot org</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Allow each entry to be its own Markdown file</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Handle SASS instead of CSS</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Fast Scroller by Month and Year</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Add timelines and individual timeline items to the sitemap</li>
</ul>
<h2 id="day-12" tabindex="-1">Day 12</h2>
<p>Ok, so I want to create social-media-ready screenshots of timeline items. This feels like something I can do with some preexisting library pretty quickly and leverage the Javascript I wrote in my last session to build the DOM element. Today I feel like I want to just complete a task.</p>
<p>So, let's search around and see what we can pull.</p>
<p>So it looks like the two main libraries that people reference are the older but less recently updated library <a href="https://github.com/tsayen/dom-to-image" target="_blank">dom-to-image</a> and the more recently updated <a href="https://github.com/bubkoo/html-to-image" target="_blank">html-to-image</a>. They both seem pretty similar. dom-to-image is more widely used even if it isn't more recently updated. I feel bad using a library that is ripping off another one... if it is? Ah, I see they do give credit to the original. The original author no longer seems to be active on GitHub at all. Ok, I'm going to go with the newer one.</p>
<p>I'm going to duplicate my old code from my previous session for now. I want to keep it dry, but that'll mean setting up a JS build task, and that's for later, assuming I get this to work.</p>
<p>To move towards that, I think I'll want to use <a href="https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_shadow_DOM" target="_blank">Shadow DOM</a> with my custom element.</p>
<p>Now I need to apply the CSS from the stylesheet that isn't included in the element using that.</p>
<p>To create this at the build step, I'll need a virtual DOM I think? Let's pull down <a href="https://github.com/jsdom/jsdom" target="_blank">JSDOM</a>. It looks that <a href="https://dev.to/ficusjs/unit-testing-web-components-with-ava-and-jsdom-2ofp" target="_blank">JSDOM does indeed have customElements to use</a>.</p>
<p>Ok, set that up, set my style element up. How do I attach a Shadow DOM from outside the element?</p>
<p>It looks like as long as I define the Shadow DOM as open with <code>this.attachShadow({ mode: &quot;open&quot; });</code> in my custom element setup, I can attach to it like <code>itemDOMObj.shadowRoot.appendChild(styleElement())</code>;</p>
<p>Ok, I think I have the right custom element, and I can use the library to create the right dataUrl. Then, I think, I can use <code>fs</code> to write that as an image file for my site.</p>
<p>Ok, now how do I create the file during my build step?</p>
<p>The problem is that a bunch of my data is built on to the object at the point the template is made. Can I pull my function into there? Perhaps I can pass it in as a filter? But the object is not ready really there either. And I can't use the <code>set</code> keyword to set deep object properties.</p>
<p>Looks like Nunjucks folks have <a href="https://github.com/mozilla/nunjucks/issues/313" target="_blank">developed a technique for this</a>. I'll use that.</p>
<p>Ok, looks like that is sending the right object and it is getting set up into the right DOM element. Only... it's not writing a file.</p>
<p>Found the error!</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/context-timelines/day-12-generate-timeline-item-image/#code-skip-day-12-generate-timeline-item-image-1" id="skip-to-code-skip-day-12-generate-timeline-item-image-1" class="skip-link">Skip code block ▼</a></p>
<pre><code>Test Social image build failed for reason:  ReferenceError: HTMLCanvasElement is not defined
    at /Users/zuckerscharffa/Dev/context-center/node_modules/html-to-image/lib/clone-node.js:75:33
    at step (/Users/zuckerscharffa/Dev/context-center/node_modules/html-to-image/lib/clone-node.js:33:23)
    at Object.next (/Users/zuckerscharffa/Dev/context-center/node_modules/html-to-image/lib/clone-node.js:14:53)
    at /Users/zuckerscharffa/Dev/context-center/node_modules/html-to-image/lib/clone-node.js:8:71
    at new Promise (&lt;anonymous&gt;)
    at __awaiter (/Users/zuckerscharffa/Dev/context-center/node_modules/html-to-image/lib/clone-node.js:4:12)
    at cloneSingleNode (/Users/zuckerscharffa/Dev/context-center/node_modules/html-to-image/lib/clone-node.js:73:12)
    at /Users/zuckerscharffa/Dev/context-center/node_modules/html-to-image/lib/clone-node.js:171:58
</code></pre>
<p id="code-skip-day-12-generate-timeline-item-image-1">So it <a href="https://github.com/plotly/plotly.js/issues/3239" target="_blank">looks</a> <a href="https://stackoverflow.com/questions/71719298/node-js-application-leveraging-jsdom-and-node-canvas-trying-to-drawimage-from" target="_blank">like</a> <code>HTMLCanvasElement</code> <a href="https://stackoverflow.com/questions/71884870/react-testing-library-cant-acquire-context-from-the-given-item" target="_blank">isn't</a> in JSDOM? Uh oh. <a href="https://www.npmjs.com/package/canvas" target="_blank">I might be able to use this</a>?</p>
<p>Hmmm. Guess this is not so simple. I'll save the rest for another day.</p>
<p><code>git commit -am &quot;Step one of setting up automatic image generation&quot;</code></p>
]]></content:encoded>
	</item>
	
	<item>
		<title>Context Center Timelines - Day 11 - Build on Single Items</title>
		<link>https://fightwithtools.dev/posts/projects/context-timelines/day-11-building-on-individual-items/?source=rss</link>
		<pubDate>Wed, 02 Nov 2022 02:59:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/projects/context-timelines/day-11-building-on-individual-items/</guid>
		<description>Stretching the limits of Nunjucks by using it to create valid JSON.</description>
		<content:encoded><![CDATA[<h2 id="project-scope-and-todos" tabindex="-1">Project Scope and ToDos</h2>
<ol>
<li>Create timeline pages where one can see the whole timeline of a particular event</li>
<li>Give timeline items type or category icons so that you can easily scan what is happening.</li>
<li>Allow the user to enter the timeline at any individually sharable link of an event and seamlessly scroll up and down</li>
</ol>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Deliver timelines as a plugin that can be extended by other Eleventy users</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Auto-create social-media-ready screenshots of a timeline item</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Integrate with Contexter to have context-full link cards in the timeline</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Leverage the Live Blog format of Schema dot org</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Allow each entry to be its own Markdown file</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Handle SASS instead of CSS</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Fast Scroller by Month and Year</li>
</ul>
<h2 id="day-11" tabindex="-1">Day 11</h2>
<p>Ok, so we have single item pages, they are individually linkable, and we have the JSON file we need that has all the data to fill in the timeline.</p>
<p>So, let's set up the page to request the API and use it.</p>
<p>I will set up a single JS file that only loads on this template to handle this process. And to speed up that connection, I'll use the <code>preload</code> link hint to set up the requests.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/context-timelines/day-11-building-on-individual-items/#code-skip-day-11-building-on-individual-items-9" id="skip-to-code-skip-day-11-building-on-individual-items-9" class="skip-link">Skip code block ▼</a></p>
<pre class="language-liquid"><code class="language-liquid"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>link</span> <span class="token attr-name">rel</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>preload<span class="token punctuation">"</span></span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>{{timelinesConfig.jsPath}}/single-item.js<span class="token punctuation">"</span></span> <span class="token attr-name">as</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>script<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span><br /><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>link</span> <span class="token attr-name">rel</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>preload<span class="token punctuation">"</span></span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>{{timelinesConfig.domainName}}/{{timelinesConfig.timelineOutFolder}}/{{timelineEntryItem.data.timeline}}/index.json<span class="token punctuation">"</span></span> <span class="token attr-name">as</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>fetch<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span></code></pre>
<p id="code-skip-day-11-building-on-individual-items-9">I also will want some of the basic data set up to use in my scripts.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/context-timelines/day-11-building-on-individual-items/#code-skip-day-11-building-on-individual-items-8" id="skip-to-code-skip-day-11-building-on-individual-items-8" class="skip-link">Skip code block ▼</a></p>
<pre class="language-liquid"><code class="language-liquid"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>script</span><span class="token punctuation">></span></span><span class="token script"><span class="token language-javascript"><br />    window<span class="token punctuation">.</span>baseItem <span class="token operator">=</span> <span class="token string">"{{- timelineEntryItem.data.title | slugify -}}"</span><span class="token punctuation">;</span><br />    window<span class="token punctuation">.</span>timelineAPI <span class="token operator">=</span> <span class="token string">"{{timelinesConfig.domainName}}/{{timelinesConfig.timelineOutFolder}}/{{timelineEntryItem.data.timeline}}/index.json"</span><span class="token punctuation">;</span><br /></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>script</span><span class="token punctuation">></span></span></code></pre>
<p id="code-skip-day-11-building-on-individual-items-8">Now we can <code>fetch</code> the data for use.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/context-timelines/day-11-building-on-individual-items/#code-skip-day-11-building-on-individual-items-7" id="skip-to-code-skip-day-11-building-on-individual-items-7" class="skip-link">Skip code block ▼</a></p>
<pre class="language-js"><code class="language-js"><span class="token function">fetch</span><span class="token punctuation">(</span>window<span class="token punctuation">.</span>timelineAPI<span class="token punctuation">)</span><br /><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">response</span><span class="token punctuation">)</span> <span class="token operator">=></span> response<span class="token punctuation">.</span><span class="token function">json</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><br /><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">data</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />	console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>data<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p id="code-skip-day-11-building-on-individual-items-7">The objects I need reside on <code>data.items</code>. The object properties are:</p>
<ul>
<li><code>content</code></li>
<li><code>date</code></li>
<li><code>faicon</code></li>
<li><code>humanReadableDate</code></li>
<li><code>image</code>
<ul>
<li>Can contain an <code>Object</code> with the properties of:
<ul>
<li><code>src</code></li>
<li><code>link</code></li>
<li><code>caption</code></li>
</ul>
</li>
</ul>
</li>
<li><code>isBasedOn</code></li>
<li><code>links</code>
<ul>
<li>Can contain an <code>Array</code> of <code>Object</code>s with the properties
<ul>
<li><code>href</code></li>
<li><code>linkText</code></li>
<li><code>extraText</code></li>
</ul>
</li>
</ul>
</li>
<li><code>slug</code></li>
<li><code>tags</code>
<ul>
<li>This contains an <code>Array</code> of strings.</li>
</ul>
</li>
<li><code>title</code></li>
</ul>
<p>Now I have to use JS to translate it to content on the page.</p>
<p>I could prerender some of this stuff, but, as I may have written before, I'm being very intentional here. The goal is a solo page that represents a solo item and so can be SEOed as such, including building and sending the metaphorical link juice to the good publication.</p>
<p>I'm going to <a href="https://github.com/AramZS/HyperRead/blob/master/index.js" target="_blank">steal a function from an old project</a>, which I actually stole from <a href="https://paulfrazee.medium.com/" target="_blank">Paul Frazee</a> a while ago.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/context-timelines/day-11-building-on-individual-items/#code-skip-day-11-building-on-individual-items-6" id="skip-to-code-skip-day-11-building-on-individual-items-6" class="skip-link">Skip code block ▼</a></p>
<pre class="language-js"><code class="language-js"><span class="token keyword">function</span> <span class="token function">h</span><span class="token punctuation">(</span><span class="token parameter">tag<span class="token punctuation">,</span> attrs<span class="token punctuation">,</span> <span class="token operator">...</span>children</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />	<span class="token keyword">var</span> el <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">createElement</span><span class="token punctuation">(</span>tag<span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">isPlainObject</span><span class="token punctuation">(</span>attrs<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />		<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">let</span> k <span class="token keyword">in</span> attrs<span class="token punctuation">)</span> <span class="token punctuation">{</span><br />			<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">typeof</span> attrs<span class="token punctuation">[</span>k<span class="token punctuation">]</span> <span class="token operator">===</span> <span class="token string">"function"</span><span class="token punctuation">)</span><br />				el<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span>k<span class="token punctuation">,</span> attrs<span class="token punctuation">[</span>k<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />			<span class="token keyword">else</span> el<span class="token punctuation">.</span><span class="token function">setAttribute</span><span class="token punctuation">(</span>k<span class="token punctuation">,</span> attrs<span class="token punctuation">[</span>k<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />		<span class="token punctuation">}</span><br />	<span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>attrs<span class="token punctuation">)</span> <span class="token punctuation">{</span><br />		children <span class="token operator">=</span> <span class="token punctuation">[</span>attrs<span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">concat</span><span class="token punctuation">(</span>children<span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token punctuation">}</span><br />	<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">let</span> child <span class="token keyword">of</span> children<span class="token punctuation">)</span> el<span class="token punctuation">.</span><span class="token function">append</span><span class="token punctuation">(</span>child<span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token keyword">return</span> el<span class="token punctuation">;</span><br /><span class="token punctuation">}</span><br /><br /><span class="token keyword">function</span> <span class="token function">isPlainObject</span><span class="token punctuation">(</span><span class="token parameter">v</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />	<span class="token keyword">return</span> v <span class="token operator">&amp;&amp;</span> <span class="token keyword">typeof</span> v <span class="token operator">===</span> <span class="token string">"object"</span> <span class="token operator">&amp;&amp;</span> <span class="token class-name">Object</span><span class="token punctuation">.</span>prototype <span class="token operator">===</span> v<span class="token punctuation">.</span>__proto__<span class="token punctuation">;</span><br /><span class="token punctuation">}</span></code></pre>
<p id="code-skip-day-11-building-on-individual-items-6">There are a lot of complicated JS to HTML functions out there. I don't need any of them. This isn't updating live, I don't care about state management. Simple basic stuff here. This works, it lets me set up nice HTML with attributes and nested elements. Exactly what I need to make this easy.</p>
<p>I think, even though this is pretty basic, it is going to be easier to manage with a custom HTML element. I haven't done this on the main page, though maybe I should, but with setting it up for building with JS, this just seems easier.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/context-timelines/day-11-building-on-individual-items/#code-skip-day-11-building-on-individual-items-5" id="skip-to-code-skip-day-11-building-on-individual-items-5" class="skip-link">Skip code block ▼</a></p>
<pre class="language-js"><code class="language-js"><br /><span class="token keyword">class</span> <span class="token class-name">TimelineItem</span> <span class="token keyword">extends</span> <span class="token class-name">HTMLElement</span> <span class="token punctuation">{</span><br />	<span class="token keyword">static</span> <span class="token keyword">get</span> <span class="token function">observedAttributes</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />		<span class="token keyword">return</span> <span class="token punctuation">[</span><span class="token string">"data-buildobj"</span><span class="token punctuation">]</span><span class="token punctuation">;</span><br />	<span class="token punctuation">}</span><br />	<span class="token function">elBuilder</span><span class="token punctuation">(</span><span class="token parameter">data</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />		console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">"Set data "</span><span class="token punctuation">,</span> data<span class="token punctuation">)</span><span class="token punctuation">;</span><br />		<span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">setAttribute</span><span class="token punctuation">(</span><span class="token string">"data-tags"</span><span class="token punctuation">,</span> data<span class="token punctuation">.</span>tags<span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span><span class="token string">","</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />		<span class="token keyword">let</span> timelineIcon <span class="token operator">=</span> <span class="token function">h</span><span class="token punctuation">(</span><br />			<span class="token string">"div"</span><span class="token punctuation">,</span><br />			<span class="token punctuation">{</span><br />				<span class="token keyword">class</span><span class="token operator">:</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">timeline-icon </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>data<span class="token punctuation">.</span>color<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span><br />			<span class="token punctuation">}</span><span class="token punctuation">,</span><br />			data<span class="token operator">?.</span>faicon<br />				<span class="token operator">?</span> <span class="token function">h</span><span class="token punctuation">(</span><span class="token string">"i"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span><br />						<span class="token keyword">class</span><span class="token operator">:</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">fas fa-</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>data<span class="token punctuation">.</span>faicon<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span><br />						<span class="token string-property property">"aria-hidden"</span><span class="token operator">:</span> <span class="token string">"true"</span><span class="token punctuation">,</span><br />				  <span class="token punctuation">}</span><span class="token punctuation">)</span><br />				<span class="token operator">:</span> <span class="token keyword">null</span><br />		<span class="token punctuation">)</span><span class="token punctuation">;</span><br />		<span class="token keyword">if</span> <span class="token punctuation">(</span>data<span class="token punctuation">.</span>color<span class="token punctuation">)</span> timelineIcon<span class="token punctuation">.</span>classList<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span>data<span class="token punctuation">.</span>color<span class="token punctuation">)</span><span class="token punctuation">;</span><br />		<span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">appendChild</span><span class="token punctuation">(</span>timelineIcon<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br />		<span class="token keyword">let</span> timelineDescription <span class="token operator">=</span> <span class="token function">h</span><span class="token punctuation">(</span><br />			<span class="token string">"div"</span><span class="token punctuation">,</span><br />			<span class="token punctuation">{</span><br />				<span class="token keyword">class</span><span class="token operator">:</span> <span class="token string">"timeline-description"</span><span class="token punctuation">,</span><br />			<span class="token punctuation">}</span><span class="token punctuation">,</span><br />			<span class="token function">h</span><span class="token punctuation">(</span><br />				<span class="token string">"span"</span><span class="token punctuation">,</span><br />				<span class="token punctuation">{</span> <span class="token keyword">class</span><span class="token operator">:</span> <span class="token string">"timestamp"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span><br />				<span class="token function">h</span><span class="token punctuation">(</span><span class="token string">"time"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">datetime</span><span class="token operator">:</span> data<span class="token punctuation">.</span>date <span class="token punctuation">}</span><span class="token punctuation">,</span> data<span class="token punctuation">.</span>humanReadableDate<span class="token punctuation">)</span><br />			<span class="token punctuation">)</span><span class="token punctuation">,</span><br />			<span class="token function">h</span><span class="token punctuation">(</span><br />				<span class="token string">"h2"</span><span class="token punctuation">,</span><br />				<span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span><br />				<span class="token function">h</span><span class="token punctuation">(</span><br />					<span class="token string">"a"</span><span class="token punctuation">,</span><br />					<span class="token punctuation">{</span> <span class="token literal-property property">id</span><span class="token operator">:</span> data<span class="token punctuation">.</span>slug<span class="token punctuation">,</span> <span class="token literal-property property">href</span><span class="token operator">:</span> data<span class="token punctuation">.</span>slug <span class="token punctuation">}</span><span class="token punctuation">,</span><br />					<span class="token function">h</span><span class="token punctuation">(</span><span class="token string">"i"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token keyword">class</span><span class="token operator">:</span> <span class="token string">"fas fa-link"</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><br />				<span class="token punctuation">)</span><span class="token punctuation">,</span><br />				data<span class="token punctuation">.</span>title<br />			<span class="token punctuation">)</span><span class="token punctuation">,</span><br />			data<span class="token punctuation">.</span>image<br />				<span class="token operator">?</span> <span class="token function">h</span><span class="token punctuation">(</span><br />						<span class="token string">"div"</span><span class="token punctuation">,</span><br />						<span class="token punctuation">{</span> <span class="token keyword">class</span><span class="token operator">:</span> <span class="token string">"captioned-image image-right"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span><br />						<span class="token function">h</span><span class="token punctuation">(</span><br />							data<span class="token punctuation">.</span>image<span class="token punctuation">.</span>link <span class="token operator">?</span> <span class="token string">"a"</span> <span class="token operator">:</span> <span class="token string">"span"</span><span class="token punctuation">,</span><br />							<span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span><br />							<span class="token function">h</span><span class="token punctuation">(</span><span class="token string">"img"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span><br />								<span class="token literal-property property">src</span><span class="token operator">:</span> data<span class="token punctuation">.</span>image<span class="token punctuation">.</span>src<span class="token punctuation">,</span><br />								<span class="token literal-property property">alt</span><span class="token operator">:</span> data<span class="token punctuation">.</span>image<span class="token punctuation">.</span>alt<span class="token punctuation">,</span><br />							<span class="token punctuation">}</span><span class="token punctuation">)</span><br />						<span class="token punctuation">)</span><span class="token punctuation">,</span><br />						<span class="token function">h</span><span class="token punctuation">(</span><span class="token string">"span"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token keyword">class</span><span class="token operator">:</span> <span class="token string">"caption"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> data<span class="token punctuation">.</span>image<span class="token punctuation">.</span>caption<span class="token punctuation">)</span><br />				  <span class="token punctuation">)</span><br />				<span class="token operator">:</span> <span class="token keyword">null</span><span class="token punctuation">,</span><br />			data<span class="token punctuation">.</span>isBasedOn <span class="token operator">&amp;&amp;</span> data<span class="token punctuation">.</span>customLink<br />				<span class="token operator">?</span> <span class="token function">h</span><span class="token punctuation">(</span><br />						<span class="token string">"a"</span><span class="token punctuation">,</span><br />						<span class="token punctuation">{</span> <span class="token literal-property property">target</span><span class="token operator">:</span> <span class="token string">"_blank"</span><span class="token punctuation">,</span> <span class="token literal-property property">href</span><span class="token operator">:</span> <span class="token string">"data.customLink"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span><br />						<span class="token string">"Read the article"</span><br />				  <span class="token punctuation">)</span><br />				<span class="token operator">:</span> <span class="token keyword">null</span><span class="token punctuation">,</span><br />			<span class="token function">h</span><span class="token punctuation">(</span><span class="token string">"span"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token keyword">class</span><span class="token operator">:</span> <span class="token string">"inner-description"</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br />			data<span class="token operator">?.</span>links<span class="token punctuation">.</span>length<br />				<span class="token operator">?</span> <span class="token function">h</span><span class="token punctuation">(</span><br />						<span class="token string">"ul"</span><span class="token punctuation">,</span><br />						<span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span><br />						<span class="token operator">...</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />							<span class="token keyword">let</span> lis <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span><br />							data<span class="token punctuation">.</span>links<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">link</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />								lis<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span><br />									<span class="token function">h</span><span class="token punctuation">(</span><br />										<span class="token string">"li"</span><span class="token punctuation">,</span><br />										<span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span><br />										<span class="token function">h</span><span class="token punctuation">(</span><br />											<span class="token string">"a"</span><span class="token punctuation">,</span><br />											<span class="token punctuation">{</span><br />												<span class="token literal-property property">href</span><span class="token operator">:</span> link<span class="token punctuation">.</span>href<span class="token punctuation">,</span><br />												<span class="token literal-property property">target</span><span class="token operator">:</span> <span class="token string">"_blank"</span><span class="token punctuation">,</span><br />											<span class="token punctuation">}</span><span class="token punctuation">,</span><br />											link<span class="token punctuation">.</span>linkText<br />										<span class="token punctuation">)</span><span class="token punctuation">,</span><br />										<span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string"> </span><span class="token template-punctuation string">`</span></span> <span class="token operator">+</span> link<span class="token punctuation">.</span>extraText<br />									<span class="token punctuation">)</span><br />								<span class="token punctuation">)</span><span class="token punctuation">;</span><br />							<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />							<span class="token keyword">return</span> lis<span class="token punctuation">;</span><br />						<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">(</span><span class="token punctuation">)</span><br />				  <span class="token punctuation">)</span><br />				<span class="token operator">:</span> <span class="token keyword">null</span><br />		<span class="token punctuation">)</span><span class="token punctuation">;</span><br />		<span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">appendChild</span><span class="token punctuation">(</span>timelineDescription<span class="token punctuation">)</span><span class="token punctuation">;</span><br />		<span class="token keyword">let</span> innerContent <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">".inner-description"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />		innerContent<span class="token punctuation">.</span>innerHTML <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>data<span class="token punctuation">.</span>content<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span><br />	<span class="token punctuation">}</span><br />	<span class="token function">connectedCallback</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />		<span class="token keyword">let</span> data <span class="token operator">=</span> <span class="token constant">JSON</span><span class="token punctuation">.</span><span class="token function">parse</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">getAttribute</span><span class="token punctuation">(</span><span class="token string">"data-buildobj"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token punctuation">}</span><br />	<span class="token function">constructor</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />		<span class="token comment">// Always call super first in constructor</span><br />		<span class="token keyword">super</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />		<span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">setAttribute</span><span class="token punctuation">(</span><span class="token string">"aria-hidden"</span><span class="token punctuation">,</span> <span class="token string">"false"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />		<span class="token keyword">this</span><span class="token punctuation">.</span>classList<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span><span class="token string">"timeline-entry"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />		<span class="token keyword">this</span><span class="token punctuation">.</span>classList<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span><span class="token string">"odd"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />		<span class="token comment">// Element functionality written in here</span><br />	<span class="token punctuation">}</span><br /><span class="token punctuation">}</span><br /><br />customElements<span class="token punctuation">.</span><span class="token function">define</span><span class="token punctuation">(</span><span class="token string">"timeline-item"</span><span class="token punctuation">,</span> TimelineItem<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p id="code-skip-day-11-building-on-individual-items-5">Originally what I was going to do is set the JSON into the custom element and then use <code>connectedCallback</code> to build it when it attaches to the DOM, the <code>constructor</code> here for the custom HTML element sets up the element with the basic classes and attributes I need. It really works well here and is straightforward.</p>
<p>This approach is fine, and works with both types of custom HTML elements if I wanted to use the <code>is: </code> based construction of HTML elements. But <code>div</code> and this element here is pretty basic and so doesn't need that approach. I also should really construct the element before I attach it, as the DOM would run smoother that way.</p>
<p>Also, something unexpected has happened here, when I ran this with the if statements occasionally casting nulls I discovered something unexpected. <code>append</code> seems to cast <code>null</code> as a string.</p>
<p>Oh Javascript and your weird casting of various falsys into unexpected stuff.</p>
<p>Ok, so, let's remove the <code>null</code> strings from my DOM first. The spread operator <code>...</code> turns the passed <code>children</code> into an array. So I can use array sanitization technique. Let's just <code>filter(Boolean)</code>. <code>append</code> may cast <code>null</code> weirdly, but <code>filter</code> should handle this just fine.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/context-timelines/day-11-building-on-individual-items/#code-skip-day-11-building-on-individual-items-4" id="skip-to-code-skip-day-11-building-on-individual-items-4" class="skip-link">Skip code block ▼</a></p>
<pre class="language-js"><code class="language-js"><span class="token keyword">function</span> <span class="token function">h</span><span class="token punctuation">(</span><span class="token parameter">tag<span class="token punctuation">,</span> attrs<span class="token punctuation">,</span> <span class="token operator">...</span>children</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />	<span class="token keyword">var</span> el <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">createElement</span><span class="token punctuation">(</span>tag<span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">isPlainObject</span><span class="token punctuation">(</span>attrs<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />		<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">let</span> k <span class="token keyword">in</span> attrs<span class="token punctuation">)</span> <span class="token punctuation">{</span><br />			<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">typeof</span> attrs<span class="token punctuation">[</span>k<span class="token punctuation">]</span> <span class="token operator">===</span> <span class="token string">"function"</span><span class="token punctuation">)</span><br />				el<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span>k<span class="token punctuation">,</span> attrs<span class="token punctuation">[</span>k<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />			<span class="token keyword">else</span> el<span class="token punctuation">.</span><span class="token function">setAttribute</span><span class="token punctuation">(</span>k<span class="token punctuation">,</span> attrs<span class="token punctuation">[</span>k<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />		<span class="token punctuation">}</span><br />	<span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>attrs<span class="token punctuation">)</span> <span class="token punctuation">{</span><br />		children <span class="token operator">=</span> <span class="token punctuation">[</span>attrs<span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">concat</span><span class="token punctuation">(</span>children<span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token punctuation">}</span><br />	children <span class="token operator">=</span> children<span class="token punctuation">.</span><span class="token function">filter</span><span class="token punctuation">(</span>Boolean<span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">let</span> child <span class="token keyword">of</span> children<span class="token punctuation">)</span> el<span class="token punctuation">.</span><span class="token function">append</span><span class="token punctuation">(</span>child<span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token keyword">return</span> el<span class="token punctuation">;</span><br /><span class="token punctuation">}</span></code></pre>
<p id="code-skip-day-11-building-on-individual-items-4">Bingo, that works!</p>
<p>Now let's set up the custom element with a custom setter to handle the passage of a complex data object into it.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/context-timelines/day-11-building-on-individual-items/#code-skip-day-11-building-on-individual-items-3" id="skip-to-code-skip-day-11-building-on-individual-items-3" class="skip-link">Skip code block ▼</a></p>
<pre class="language-js"><code class="language-js"><br /><span class="token keyword">class</span> <span class="token class-name">TimelineItem</span> <span class="token keyword">extends</span> <span class="token class-name">HTMLElement</span> <span class="token punctuation">{</span><br />	<span class="token function">elBuilder</span><span class="token punctuation">(</span><span class="token parameter">data</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />		console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">"Set data "</span><span class="token punctuation">,</span> data<span class="token punctuation">)</span><span class="token punctuation">;</span><br />		<span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">setAttribute</span><span class="token punctuation">(</span><span class="token string">"data-tags"</span><span class="token punctuation">,</span> data<span class="token punctuation">.</span>tags<span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span><span class="token string">","</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />		<span class="token keyword">let</span> timelineIcon <span class="token operator">=</span> <span class="token function">h</span><span class="token punctuation">(</span><br />			<span class="token string">"div"</span><span class="token punctuation">,</span><br />			<span class="token punctuation">{</span><br />				<span class="token keyword">class</span><span class="token operator">:</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">timeline-icon </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>data<span class="token punctuation">.</span>color<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span><br />			<span class="token punctuation">}</span><span class="token punctuation">,</span><br />			data<span class="token operator">?.</span>faicon<br />				<span class="token operator">?</span> <span class="token function">h</span><span class="token punctuation">(</span><span class="token string">"i"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span><br />						<span class="token keyword">class</span><span class="token operator">:</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">fas fa-</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>data<span class="token punctuation">.</span>faicon<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span><br />						<span class="token string-property property">"aria-hidden"</span><span class="token operator">:</span> <span class="token string">"true"</span><span class="token punctuation">,</span><br />				  <span class="token punctuation">}</span><span class="token punctuation">)</span><br />				<span class="token operator">:</span> <span class="token keyword">null</span><br />		<span class="token punctuation">)</span><span class="token punctuation">;</span><br />		<span class="token keyword">if</span> <span class="token punctuation">(</span>data<span class="token punctuation">.</span>color<span class="token punctuation">)</span> timelineIcon<span class="token punctuation">.</span>classList<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span>data<span class="token punctuation">.</span>color<span class="token punctuation">)</span><span class="token punctuation">;</span><br />		<span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">appendChild</span><span class="token punctuation">(</span>timelineIcon<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br />		<span class="token keyword">let</span> timelineDescription <span class="token operator">=</span> <span class="token function">h</span><span class="token punctuation">(</span><br />			<span class="token string">"div"</span><span class="token punctuation">,</span><br />			<span class="token punctuation">{</span><br />				<span class="token keyword">class</span><span class="token operator">:</span> <span class="token string">"timeline-description"</span><span class="token punctuation">,</span><br />			<span class="token punctuation">}</span><span class="token punctuation">,</span><br />			<span class="token function">h</span><span class="token punctuation">(</span><br />				<span class="token string">"span"</span><span class="token punctuation">,</span><br />				<span class="token punctuation">{</span> <span class="token keyword">class</span><span class="token operator">:</span> <span class="token string">"timestamp"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span><br />				<span class="token function">h</span><span class="token punctuation">(</span><span class="token string">"time"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">datetime</span><span class="token operator">:</span> data<span class="token punctuation">.</span>date <span class="token punctuation">}</span><span class="token punctuation">,</span> data<span class="token punctuation">.</span>humanReadableDate<span class="token punctuation">)</span><br />			<span class="token punctuation">)</span><span class="token punctuation">,</span><br />			<span class="token function">h</span><span class="token punctuation">(</span><br />				<span class="token string">"h2"</span><span class="token punctuation">,</span><br />				<span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span><br />				<span class="token function">h</span><span class="token punctuation">(</span><br />					<span class="token string">"a"</span><span class="token punctuation">,</span><br />					<span class="token punctuation">{</span> <span class="token literal-property property">id</span><span class="token operator">:</span> data<span class="token punctuation">.</span>slug<span class="token punctuation">,</span> <span class="token literal-property property">href</span><span class="token operator">:</span> data<span class="token punctuation">.</span>slug <span class="token punctuation">}</span><span class="token punctuation">,</span><br />					<span class="token function">h</span><span class="token punctuation">(</span><span class="token string">"i"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token keyword">class</span><span class="token operator">:</span> <span class="token string">"fas fa-link"</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><br />				<span class="token punctuation">)</span><span class="token punctuation">,</span><br />				data<span class="token punctuation">.</span>title<br />			<span class="token punctuation">)</span><span class="token punctuation">,</span><br />			data<span class="token punctuation">.</span>image<br />				<span class="token operator">?</span> <span class="token function">h</span><span class="token punctuation">(</span><br />						<span class="token string">"div"</span><span class="token punctuation">,</span><br />						<span class="token punctuation">{</span> <span class="token keyword">class</span><span class="token operator">:</span> <span class="token string">"captioned-image image-right"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span><br />						<span class="token function">h</span><span class="token punctuation">(</span><br />							data<span class="token punctuation">.</span>image<span class="token punctuation">.</span>link <span class="token operator">?</span> <span class="token string">"a"</span> <span class="token operator">:</span> <span class="token string">"span"</span><span class="token punctuation">,</span><br />							<span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span><br />							<span class="token function">h</span><span class="token punctuation">(</span><span class="token string">"img"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span><br />								<span class="token literal-property property">src</span><span class="token operator">:</span> data<span class="token punctuation">.</span>image<span class="token punctuation">.</span>src<span class="token punctuation">,</span><br />								<span class="token literal-property property">alt</span><span class="token operator">:</span> data<span class="token punctuation">.</span>image<span class="token punctuation">.</span>alt<span class="token punctuation">,</span><br />							<span class="token punctuation">}</span><span class="token punctuation">)</span><br />						<span class="token punctuation">)</span><span class="token punctuation">,</span><br />						<span class="token function">h</span><span class="token punctuation">(</span><span class="token string">"span"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token keyword">class</span><span class="token operator">:</span> <span class="token string">"caption"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> data<span class="token punctuation">.</span>image<span class="token punctuation">.</span>caption<span class="token punctuation">)</span><br />				  <span class="token punctuation">)</span><br />				<span class="token operator">:</span> <span class="token keyword">null</span><span class="token punctuation">,</span><br />			data<span class="token punctuation">.</span>isBasedOn <span class="token operator">&amp;&amp;</span> data<span class="token punctuation">.</span>customLink<br />				<span class="token operator">?</span> <span class="token function">h</span><span class="token punctuation">(</span><br />						<span class="token string">"a"</span><span class="token punctuation">,</span><br />						<span class="token punctuation">{</span> <span class="token literal-property property">target</span><span class="token operator">:</span> <span class="token string">"_blank"</span><span class="token punctuation">,</span> <span class="token literal-property property">href</span><span class="token operator">:</span> <span class="token string">"data.customLink"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span><br />						<span class="token string">"Read the article"</span><br />				  <span class="token punctuation">)</span><br />				<span class="token operator">:</span> <span class="token keyword">null</span><span class="token punctuation">,</span><br />			<span class="token function">h</span><span class="token punctuation">(</span><span class="token string">"span"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token keyword">class</span><span class="token operator">:</span> <span class="token string">"inner-description"</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br />			data<span class="token operator">?.</span>links<span class="token punctuation">.</span>length<br />				<span class="token operator">?</span> <span class="token function">h</span><span class="token punctuation">(</span><br />						<span class="token string">"ul"</span><span class="token punctuation">,</span><br />						<span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span><br />						<span class="token operator">...</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />							<span class="token keyword">let</span> lis <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span><br />							data<span class="token punctuation">.</span>links<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">link</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />								lis<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span><br />									<span class="token function">h</span><span class="token punctuation">(</span><br />										<span class="token string">"li"</span><span class="token punctuation">,</span><br />										<span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span><br />										<span class="token function">h</span><span class="token punctuation">(</span><br />											<span class="token string">"a"</span><span class="token punctuation">,</span><br />											<span class="token punctuation">{</span><br />												<span class="token literal-property property">href</span><span class="token operator">:</span> link<span class="token punctuation">.</span>href<span class="token punctuation">,</span><br />												<span class="token literal-property property">target</span><span class="token operator">:</span> <span class="token string">"_blank"</span><span class="token punctuation">,</span><br />											<span class="token punctuation">}</span><span class="token punctuation">,</span><br />											link<span class="token punctuation">.</span>linkText<br />										<span class="token punctuation">)</span><span class="token punctuation">,</span><br />										<span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string"> </span><span class="token template-punctuation string">`</span></span> <span class="token operator">+</span> link<span class="token punctuation">.</span>extraText<br />									<span class="token punctuation">)</span><br />								<span class="token punctuation">)</span><span class="token punctuation">;</span><br />							<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />							<span class="token keyword">return</span> lis<span class="token punctuation">;</span><br />						<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">(</span><span class="token punctuation">)</span><br />				  <span class="token punctuation">)</span><br />				<span class="token operator">:</span> <span class="token keyword">null</span><br />		<span class="token punctuation">)</span><span class="token punctuation">;</span><br />		<span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">appendChild</span><span class="token punctuation">(</span>timelineDescription<span class="token punctuation">)</span><span class="token punctuation">;</span><br />		<span class="token keyword">let</span> innerContent <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">".inner-description"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />		innerContent<span class="token punctuation">.</span>innerHTML <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>data<span class="token punctuation">.</span>content<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span><br />	<span class="token punctuation">}</span><br />	<span class="token keyword">set</span> <span class="token function">itembuild</span><span class="token punctuation">(</span><span class="token parameter">data</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />		<span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">elBuilder</span><span class="token punctuation">(</span>data<span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token punctuation">}</span><br />	<span class="token function">constructor</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />		<span class="token comment">// Always call super first in constructor</span><br />		<span class="token keyword">super</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />		console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">"Custom Element Setup"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />		<span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">setAttribute</span><span class="token punctuation">(</span><span class="token string">"aria-hidden"</span><span class="token punctuation">,</span> <span class="token string">"false"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />		<span class="token keyword">this</span><span class="token punctuation">.</span>classList<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span><span class="token string">"timeline-entry"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />		<span class="token keyword">this</span><span class="token punctuation">.</span>classList<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span><span class="token string">"odd"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />		<span class="token comment">// Element functionality written in here</span><br />	<span class="token punctuation">}</span><br /><span class="token punctuation">}</span></code></pre>
<p id="code-skip-day-11-building-on-individual-items-3">Now I can pull the individual objects out of the JSON endpoint and set them up with a very simple set, <code>itemDOMObj.itembuild = item;</code>. See how cool it is that I can just set the object into the DOM element and it sets up the rest?</p>
<p>Now, to make this as efficent as possible I want to set the DOM elements up as fast as possible and then place them on the page as soon as the DOM is ready. For that, I need to use <code>DOMContentLoaded</code> right after I've finished building my objects. I could use <code>onload</code>, but only one function can be set to that property. If I use it then I might forget down the line and replace the function by accident. Using the Event Listener is the way to go.</p>
<p>First I set up the objects.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/context-timelines/day-11-building-on-individual-items/#code-skip-day-11-building-on-individual-items-2" id="skip-to-code-skip-day-11-building-on-individual-items-2" class="skip-link">Skip code block ▼</a></p>
<pre class="language-js"><code class="language-js"><span class="token keyword">let</span> <span class="token function-variable function">preload</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />	<span class="token function">fetch</span><span class="token punctuation">(</span>window<span class="token punctuation">.</span>timelineAPI<span class="token punctuation">)</span><br />		<span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">response</span><span class="token punctuation">)</span> <span class="token operator">=></span> response<span class="token punctuation">.</span><span class="token function">json</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><br />		<span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">data</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />			console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>data<span class="token punctuation">)</span><span class="token punctuation">;</span><br />			<span class="token keyword">let</span> homeItemFound <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">;</span><br />			window<span class="token punctuation">.</span>timelinePrepends <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span><br />			window<span class="token punctuation">.</span>timelineAppends <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span><br />			<span class="token keyword">const</span> TimelineEl <span class="token operator">=</span> customElements<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string">"timeline-item"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />			data<span class="token punctuation">.</span>items<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">item</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />				console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">"process this data"</span><span class="token punctuation">,</span> item<span class="token punctuation">)</span><span class="token punctuation">;</span><br />				<span class="token keyword">let</span> itemDOMObj <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">TimelineEl</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// document.createElement("timeline-item");</span><br />				<span class="token comment">// itemDOMObj.setAttribute("data-buildobj", JSON.stringify(item));</span><br />				itemDOMObj<span class="token punctuation">.</span>itembuild <span class="token operator">=</span> item<span class="token punctuation">;</span><br />				<span class="token keyword">if</span> <span class="token punctuation">(</span>item<span class="token punctuation">.</span>slug <span class="token operator">==</span> window<span class="token punctuation">.</span>timelineHomeItemSlug<span class="token punctuation">)</span> <span class="token punctuation">{</span><br />					homeItemFound <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">;</span><br />				<span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span><br />					<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>homeItemFound<span class="token punctuation">)</span> <span class="token punctuation">{</span><br />						window<span class="token punctuation">.</span>timelinePrepends<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span>itemDOMObj<span class="token punctuation">)</span><span class="token punctuation">;</span><br />					<span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span><br />						window<span class="token punctuation">.</span>timelineAppends<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span>itemDOMObj<span class="token punctuation">)</span><span class="token punctuation">;</span><br />					<span class="token punctuation">}</span><br />				<span class="token punctuation">}</span><br />			<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />			console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>document<span class="token punctuation">.</span>readyState<span class="token punctuation">)</span><span class="token punctuation">;</span><br />			<span class="token keyword">if</span> <span class="token punctuation">(</span>document<span class="token punctuation">.</span>readyState <span class="token operator">!=</span> <span class="token string">"loading"</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />				console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">"Document ready"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />				<span class="token function">singleItemPageFill</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />			<span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span><br />				document<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><br />					<span class="token string">"DOMContentLoaded"</span><span class="token punctuation">,</span><br />					singleItemPageFill<br />				<span class="token punctuation">)</span><span class="token punctuation">;</span><br />			<span class="token punctuation">}</span><br />		<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
<p id="code-skip-day-11-building-on-individual-items-2">I have to set up placing these on the page and I'm going to use <code>scrollIntoView()</code> on the DOM element to keep it centered. There will be some movement inside the viewport, but it will be very minimal (I hope).</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/context-timelines/day-11-building-on-individual-items/#code-skip-day-11-building-on-individual-items-1" id="skip-to-code-skip-day-11-building-on-individual-items-1" class="skip-link">Skip code block ▼</a></p>
<pre class="language-js"><code class="language-js"><span class="token keyword">function</span> <span class="token function">singleItemPageFill</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />	<span class="token comment">/* We have JS! */</span><br />	console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">"onload trigger"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token keyword">var</span> root <span class="token operator">=</span> document<span class="token punctuation">.</span>documentElement<span class="token punctuation">;</span><br />	root<span class="token punctuation">.</span>classList<span class="token punctuation">.</span><span class="token function">remove</span><span class="token punctuation">(</span><span class="token string">"no-js"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br />	<span class="token keyword">let</span> container <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">"section article.timeline"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token keyword">let</span> homeItem <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span>window<span class="token punctuation">.</span>timelineHomeItemSlug<span class="token punctuation">)</span><span class="token punctuation">;</span><br />	container<span class="token punctuation">.</span><span class="token function">prepend</span><span class="token punctuation">(</span><span class="token operator">...</span>window<span class="token punctuation">.</span>timelinePrepends<span class="token punctuation">)</span><span class="token punctuation">;</span><br />	homeItem<span class="token punctuation">.</span><span class="token function">scrollIntoView</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />	container<span class="token punctuation">.</span><span class="token function">append</span><span class="token punctuation">(</span><span class="token operator">...</span>window<span class="token punctuation">.</span>timelineAppends<span class="token punctuation">)</span><span class="token punctuation">;</span><br />	homeItem<span class="token punctuation">.</span><span class="token function">scrollIntoView</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />	homeItem<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">".timeline-description"</span><span class="token punctuation">)</span><span class="token punctuation">.</span>style<span class="token punctuation">.</span>border <span class="token operator">=</span><br />		<span class="token string">"2px solid var(--border-base)"</span><span class="token punctuation">;</span><br />	console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">"Build complete"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token function">reflowEntries</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token comment">// Clean up</span><br />	document<span class="token punctuation">.</span><span class="token function">removeEventListener</span><span class="token punctuation">(</span><span class="token string">"DOMContentLoaded"</span><span class="token punctuation">,</span> singleItemPageFill<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span></code></pre>
<p id="code-skip-day-11-building-on-individual-items-1">Ok, we're good to go! It fills in great!</p>
<p><code>git commit -am &quot;Getting standalone timeline item pages working and using variables more actively throughout&quot;</code></p>
]]></content:encoded>
	</item>
	
	<item>
		<title>Context Center Timelines - Day 10 - Setting up individual timeline items starter pages.</title>
		<link>https://fightwithtools.dev/posts/projects/context-timelines/day-10-back-to-individual-timeline-items/?source=rss</link>
		<pubDate>Sat, 29 Oct 2022 02:59:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/projects/context-timelines/day-10-back-to-individual-timeline-items/</guid>
		<description>Initial individual pages for expansion.</description>
		<content:encoded><![CDATA[<h2 id="project-scope-and-todos" tabindex="-1">Project Scope and ToDos</h2>
<ol>
<li>Create timeline pages where one can see the whole timeline of a particular event</li>
<li>Give timeline items type or category icons so that you can easily scan what is happening.</li>
<li>Allow the user to enter the timeline at any individually sharable link of an event and seamlessly scroll up and down</li>
</ol>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Deliver timelines as a plugin that can be extended by other Eleventy users</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Auto-create social-media-ready screenshots of a timeline item</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Integrate with Contexter to have context-full link cards in the timeline</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Leverage the Live Blog format of Schema dot org</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Allow each entry to be its own Markdown file</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Handle SASS instead of CSS</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Fast Scroller by Month and Year</li>
</ul>
<h2 id="day-10" tabindex="-1">Day 10</h2>
<p>Ok, I want to set it up the entry page. I've got the whole page looking like an empty timeline, but I need the individual item filled in.</p>
<p>To do that, I'll need to pull the entry off of the global object. To make it so I can reuse my templates, I'll need to cast the entry into the right object.</p>
<p>I seem to be able to set it up during the Eleventy Computed phase, but placing it on the <code>entry</code> object just lets it get overwritten down the line apparently.</p>
<p>Let's try using the <code>console</code> filter to see what the object is on the page.</p>
<p>Hmmm it isn't getting overwritten in the template, it's getting overwritten during the eleventyComputed phase by... I think my own changes? I'll have to break the link between the objects. I can cast it to a string and back. Then set the <code>entry</code> object at the template level instead.</p>
<p>It looks like this might work? But now I'm getting a new error <code>Cannot read property 'posts' of undefined</code> but I don't know where a <code>posts</code> property could be coming from.</p>
<p>Huh, looks like it is my debug tool getting empty values. What's happening to my new object.</p>
<p>I can fix that, but when I echo the new object I'm building, I'm getting the overwritten object still. What is happening?</p>
<p>It looks like somehow the object is being overwritten globally. My timeline is no itself broken along with the individual item. But what could be doing that? Why is it only the title?</p>
<p>Ok, let's just create a new object instead of trying to overwrite the built in properties. That seems to work, but I'm still missing some fields.</p>
<p>It means I'm going to have to do some weird extra stuff where I set variables for use in the various reusable template parts. Ok, plenty to do, especially around the <code>content</code> property, which acts pretty oddly.</p>
<p>But it does look like it is working!</p>
<p><code>git commit -am &quot;Getting standalone timeline item pages working and using variables more actively throughout&quot;</code></p>
]]></content:encoded>
	</item>
	
	<item>
		<title>Context Center Timelines - Day 9 - Setting up a JSON API for filling in single timeline item pages</title>
		<link>https://fightwithtools.dev/posts/projects/context-timelines/day-9-set-up-endpoint-timeline-apis/?source=rss</link>
		<pubDate>Sat, 08 Oct 2022 02:59:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/projects/context-timelines/day-9-set-up-endpoint-timeline-apis/</guid>
		<description>Stretching the limits of Nunjucks by using it to create valid JSON.</description>
		<content:encoded><![CDATA[<h2 id="project-scope-and-todos" tabindex="-1">Project Scope and ToDos</h2>
<ol>
<li>Create timeline pages where one can see the whole timeline of a particular event</li>
<li>Give timeline items type or category icons so that you can easily scan what is happening.</li>
<li>Allow the user to enter the timeline at any individually sharable link of an event and seamlessly scroll up and down</li>
</ol>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Deliver timelines as a plugin that can be extended by other Eleventy users</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Auto-create social-media-ready screenshots of a timeline item</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Integrate with Contexter to have context-full link cards in the timeline</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Leverage the Live Blog format of Schema dot org</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Allow each entry to be its own Markdown file</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Handle SASS instead of CSS</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Fast Scroller by Month and Year</li>
</ul>
<h2 id="day-9" tabindex="-1">Day 9</h2>
<p>Ok, so to do what I want to do with single Timeline items that can expand into the whole timeline, I'm going to need to have an API with the remaining timeline items. There doesn't seem to be much out there for building JSON using Nunjucks, but I think that's what I'll try to do here.</p>
<p>Setting up a folder for <code>json</code> in layouts and using a similar naming style.</p>
<p>The one big problem is default loops have tailing commas. I need some way to avoid that happening.</p>
<p>Jinja, which Nunjucks is based on, <a href="https://stackoverflow.com/questions/11974318/how-to-output-a-comma-delimited-list-in-jinja-python-template" target="_blank">seems to have a <code>loop.last</code> variable</a> that lets you know if you are on the last step of a loop. Nunjucks doesn't seem to have this. But it does <a href="https://mozilla.github.io/nunjucks/templating.html#last" target="_blank">seem to have a <code>last</code> filter one can apply to an array to get the last element</a>. Ok, I can use that instead.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/context-timelines/day-9-set-up-endpoint-timeline-apis/#code-skip-day-9-set-up-endpoint-timeline-apis-2" id="skip-to-code-skip-day-9-set-up-endpoint-timeline-apis-2" class="skip-link">Skip code block ▼</a></p>
<pre class="language-liquid"><code class="language-liquid"></code></pre>
<p id="code-skip-day-9-set-up-endpoint-timeline-apis-2">This takes my filters list and outputs them as strings followed by a comma, except for the last one. Looks like this works, even for more complex objects!</p>
<p>Quick note that tripped me up here, if the list is sorted then it needs to be sorted before the <code>last</code> filter is applied, like so:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/context-timelines/day-9-set-up-endpoint-timeline-apis/#code-skip-day-9-set-up-endpoint-timeline-apis-1" id="skip-to-code-skip-day-9-set-up-endpoint-timeline-apis-1" class="skip-link">Skip code block ▼</a></p>
<pre class="language-liquid"><code class="language-liquid"></code></pre>
<p id="code-skip-day-9-set-up-endpoint-timeline-apis-1">This is mostly looking good, but my content text is not being escaped properly. It looks like <a href="https://www.benjaminrancourt.ca/how-to-generate-a-complete-json-file-with-nunjucks/" target="_blank">I'm not the only one to deal with this</a> and filtering it through <code> | dump | safe</code> does seem to work. I just need to remember to allow it to generate its own quote marks.</p>
<p>Looking good. This is a nice place to take a break. We can go back to the individual timeline items next coding session.</p>
<p><code>git commit -am &quot;Set up JSON endpoints for timelines&quot;</code></p>
]]></content:encoded>
	</item>
	
	<item>
		<title>Context Center Timelines - Day 8 - Detour to dealing with image retrieval breaking my build process</title>
		<link>https://fightwithtools.dev/posts/projects/context-timelines/day-8-fix-image-retrieve/?source=rss</link>
		<pubDate>Thu, 08 Sep 2022 02:59:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/projects/context-timelines/day-8-fix-image-retrieve/</guid>
		<description>Something weird is happening in promises.</description>
		<content:encoded><![CDATA[<h2 id="project-scope-and-todos" tabindex="-1">Project Scope and ToDos</h2>
<ol>
<li>Create timeline pages where one can see the whole timeline of a particular event</li>
<li>Give timeline items type or category icons so that you can easily scan what is happening.</li>
<li>Allow the user to enter the timeline at any individually sharable link of an event and seamlessly scroll up and down</li>
</ol>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Deliver timelines as a plugin that can be extended by other Eleventy users</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Auto-create social-media-ready screenshots of a timeline item</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Integrate with Contexter to have context-full link cards in the timeline</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Leverage the Live Blog format of Schema dot org</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Allow each entry to be its own Markdown file</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Handle SASS instead of CSS</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Fast Scroller by Month and Year</li>
</ul>
<h2 id="day-8" tabindex="-1">Day 8</h2>
<p>Looks like I'm getting a different error this time.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/context-timelines/day-8-fix-image-retrieve/#code-skip-day-8-fix-image-retrieve-3" id="skip-to-code-skip-day-8-fix-image-retrieve-3" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript"><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">Error</span><span class="token template-punctuation string">`</span></span> was thrown<span class="token operator">:</span><br /><span class="token punctuation">[</span>11ty<span class="token punctuation">]</span>     Error<span class="token operator">:</span> <span class="token constant">ENOENT</span><span class="token operator">:</span> no such file or directory<span class="token punctuation">,</span> open <span class="token string">'/Users/zuckerscharffa/Dev/context-center/_contexterCache/images/httpstwittercomFoldableHumanstatus1464821797392551945/FDIsE-VUYAIbPyk.png'</span><br />        at Object<span class="token punctuation">.</span><span class="token function">openSync</span> <span class="token punctuation">(</span>fs<span class="token punctuation">.</span>js<span class="token operator">:</span><span class="token number">498</span><span class="token operator">:</span><span class="token number">3</span><span class="token punctuation">)</span><br />        at Object<span class="token punctuation">.</span><span class="token function">writeFileSync</span> <span class="token punctuation">(</span>fs<span class="token punctuation">.</span>js<span class="token operator">:</span><span class="token number">1524</span><span class="token operator">:</span><span class="token number">35</span><span class="token punctuation">)</span><br />        at <span class="token operator">/</span>Users<span class="token operator">/</span>zuckerscharffa<span class="token operator">/</span>Dev<span class="token operator">/</span>context<span class="token operator">-</span>center<span class="token operator">/</span>_custom<span class="token operator">-</span>plugins<span class="token operator">/</span>markdown<span class="token operator">-</span>contexter<span class="token operator">/</span>image<span class="token operator">-</span>handler<span class="token punctuation">.</span>js<span class="token operator">:</span><span class="token number">176</span><span class="token operator">:</span><span class="token number">10</span><br />        at <span class="token function">runMicrotasks</span> <span class="token punctuation">(</span><span class="token operator">&lt;</span>anonymous<span class="token operator">></span><span class="token punctuation">)</span><br />        at <span class="token function">processTicksAndRejections</span> <span class="token punctuation">(</span>internal<span class="token operator">/</span>process<span class="token operator">/</span>task_queues<span class="token punctuation">.</span>js<span class="token operator">:</span><span class="token number">95</span><span class="token operator">:</span><span class="token number">5</span><span class="token punctuation">)</span><br /><span class="token punctuation">[</span>11ty<span class="token punctuation">]</span> Unhandled rejection <span class="token keyword">in</span> <span class="token literal-property property">promise</span><span class="token operator">:</span> <span class="token punctuation">(</span>more <span class="token keyword">in</span> <span class="token constant">DEBUG</span> output<span class="token punctuation">)</span><br /><span class="token punctuation">[</span>11ty<span class="token punctuation">]</span> <span class="token operator">></span> <span class="token constant">ENOENT</span><span class="token operator">:</span> no such file or directory<span class="token punctuation">,</span> open <span class="token string">'/Users/zuckerscharffa/Dev/context-center/_contexterCache/images/httpstwittercomFoldableHumanstatus1464821797392551945/FBSA8vKVIAUJOn6.png'</span></code></pre>
<p id="code-skip-day-8-fix-image-retrieve-3">Ok, it looks like the folders at hand in this Twitter Image handling aren't being created. Looks like I missed a folder create event.</p>
<p>Ok, moving to use <code>reject</code> on a promise to keep the error chain consistent. I think this may have resolved it? Or maybe not.</p>
<p>I'm now getting a Nunjucks error.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/context-timelines/day-8-fix-image-retrieve/#code-skip-day-8-fix-image-retrieve-2" id="skip-to-code-skip-day-8-fix-image-retrieve-2" class="skip-link">Skip code block ▼</a></p>
<pre class="language-js"><code class="language-js"><span class="token punctuation">[</span>11ty<span class="token punctuation">]</span> Writing docs<span class="token operator">/</span>timegate<span class="token operator">/</span>https<span class="token operator">:</span><span class="token operator">/</span>www<span class="token punctuation">.</span>th<span class="token operator">/</span>_custom<span class="token operator">-</span>plugins<span class="token operator">/</span>timelinety<span class="token operator">/</span>src<span class="token operator">/</span>layouts<span class="token operator">/</span>timeline<span class="token operator">-</span>item<span class="token punctuation">.</span>njk<span class="token punctuation">)</span><br />      Template render error<span class="token operator">:</span> <span class="token punctuation">(</span><span class="token operator">/</span>Users<span class="token operator">/</span>zuckerscharffa<span class="token operator">/</span>Dev<span class="token operator">/</span>context<span class="token operator">-</span>center<span class="token operator">/</span>_custom<span class="token operator">-</span>plugins<span class="token operator">/</span>timelinety<span class="token operator">/</span>src<span class="token operator">/</span>layouts<span class="token operator">/</span>timeline<span class="token operator">-</span>item<span class="token operator">-</span>wrapper<span class="token punctuation">.</span>njk<span class="token punctuation">)</span><br />      Template render error<span class="token operator">:</span> <span class="token punctuation">(</span><span class="token operator">/</span>Users<span class="token operator">/</span>zuckerscharffa<span class="token operator">/</span>Dev<span class="token operator">/</span>context<span class="token operator">-</span>center<span class="token operator">/</span>_custom<span class="token operator">-</span>plugins<span class="token operator">/</span>timelinety<span class="token operator">/</span>src<span class="token operator">/</span>layouts<span class="token operator">/</span>timeline<span class="token operator">-</span>filters<span class="token punctuation">.</span>njk<span class="token punctuation">)</span> <span class="token punctuation">[</span>Line <span class="token number">21</span><span class="token punctuation">,</span> Column <span class="token number">50</span><span class="token punctuation">]</span><br />      attempted to output <span class="token keyword">null</span> or <span class="token keyword">undefined</span> value<br />        at Object<span class="token punctuation">.</span><span class="token function">_prettifyError</span> <span class="token punctuation">(</span><span class="token operator">/</span>Users<span class="token operator">/</span>zuckerscharffa<span class="token operator">/</span>Dev<span class="token operator">/</span>context<span class="token operator">-</span>center<span class="token operator">/</span>node_modules<span class="token operator">/</span>nunjucks<span class="token operator">/</span>src<span class="token operator">/</span>lib<span class="token punctuation">.</span>js<span class="token operator">:</span><span class="token number">36</span><span class="token operator">:</span><span class="token number">11</span><span class="token punctuation">)</span><br />        at <span class="token operator">/</span>Users<span class="token operator">/</span>zuckerscharffa<span class="token operator">/</span>Dev<span class="token operator">/</span>context<span class="token operator">-</span>center<span class="token operator">/</span>node_modules<span class="token operator">/</span>nunjucks<span class="token operator">/</span>src<span class="token operator">/</span>environment<span class="token punctuation">.</span>js<span class="token operator">:</span><span class="token number">563</span><span class="token operator">:</span><span class="token number">19</span><br />        at <span class="token function">eval</span> <span class="token punctuation">(</span>eval at <span class="token function">_compile</span> <span class="token punctuation">(</span><span class="token operator">/</span>Users<span class="token operator">/</span>zuckerscharffa<span class="token operator">/</span>Dev<span class="token operator">/</span>context<span class="token operator">-</span>center<span class="token operator">/</span>node_modules<span class="token operator">/</span>nunjucks<span class="token operator">/</span>src<span class="token operator">/</span>environment<span class="token punctuation">.</span>js<span class="token operator">:</span><span class="token number">633</span><span class="token operator">:</span><span class="token number">18</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token operator">&lt;</span>anonymous<span class="token operator">></span><span class="token operator">:</span><span class="token number">19</span><span class="token operator">:</span><span class="token number">11</span><span class="token punctuation">)</span><br />        at <span class="token operator">/</span>Users<span class="token operator">/</span>zuckerscharffa<span class="token operator">/</span>Dev<span class="token operator">/</span>context<span class="token operator">-</span>center<span class="token operator">/</span>node_modules<span class="token operator">/</span>nunjucks<span class="token operator">/</span>src<span class="token operator">/</span>environment<span class="token punctuation">.</span>js<span class="token operator">:</span><span class="token number">571</span><span class="token operator">:</span><span class="token number">11</span><br />        at <span class="token function">eval</span> <span class="token punctuation">(</span>eval at <span class="token function">_compile</span> <span class="token punctuation">(</span><span class="token operator">/</span>Users<span class="token operator">/</span>zuckerschaeblockcrypto<span class="token punctuation">.</span>com<span class="token operator">/</span>linked<span class="token operator">/</span><span class="token number">133982</span><span class="token operator">/</span>world<span class="token operator">-</span>wildlife<span class="token operator">-</span>fund<span class="token operator">-</span>pulls<span class="token operator">-</span>conservation<span class="token operator">-</span>focused<span class="token operator">-</span>nft<span class="token operator">-</span>project<span class="token operator">-</span>after<span class="token operator">-</span>backlash<span class="token operator">/</span>index<span class="token punctuation">.</span>html from <span class="token punctuation">.</span><span class="token operator">/</span>src<span class="token operator">/</span>archives<span class="token punctuation">.</span><span class="token function">md</span> <span class="token punctuation">(</span>njk<span class="token punctuation">)</span></code></pre>
<p id="code-skip-day-8-fix-image-retrieve-2">Ok, it looks like Twitter Object stuff is totally borked. I'll need to check media objects for a URL before I try and do any processing on them and return false if they don't have them.</p>
<p>That resolves a bunch of the errors, but my build is still failing. What now? Ok, setting my Nunjucks config to <code>throwOnUndefined</code> as false lets the site build. But if it is supposed to throw on undefined where is the error?</p>
<p>Ok, looks like my handling of filters in the standalone timeline item isn't working. I can fix that, but it is still failing. Something in the timeline-item I think.</p>
<p>I think I've got all the checks in place.</p>
<p>Now I need to make sure that I'm properly populating timeline entry pages with both timeline and timeline item info.</p>
<p>Here's the resulting object</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/context-timelines/day-8-fix-image-retrieve/#code-skip-day-8-fix-image-retrieve-1" id="skip-to-code-skip-day-8-fix-image-retrieve-1" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript"><span class="token punctuation">{</span><br />  <span class="token literal-property property">defaults</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />    <span class="token literal-property property">layout</span><span class="token operator">:</span> <span class="token string">'default.njk'</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">title</span><span class="token operator">:</span> <span class="token string">'Site Title'</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">description</span><span class="token operator">:</span> <span class="token string">'Site Description'</span><br />  <span class="token punctuation">}</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">site</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />    <span class="token literal-property property">lang</span><span class="token operator">:</span> <span class="token string">'en-US'</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">github</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">build_revision</span><span class="token operator">:</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token literal-property property">build_sha</span><span class="token operator">:</span> <span class="token number">1</span> <span class="token punctuation">}</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">site_url</span><span class="token operator">:</span> <span class="token string">'http://localhost:8082'</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">site_domain</span><span class="token operator">:</span> <span class="token string">'context.center'</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">site_name</span><span class="token operator">:</span> <span class="token string">'Context Center'</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">description</span><span class="token operator">:</span> <span class="token string">'Context Center Description'</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">featuredImage</span><span class="token operator">:</span> <span class="token string">'context.center/img/nyc_noir.jpg'</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">author</span><span class="token operator">:</span> <span class="token string">'Aram Zucker-Scharff'</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">authorPhoto</span><span class="token operator">:</span> <span class="token string">'https://raw.githubusercontent.com/AramZS/aramzs.github.io/master/_includes/Aram-Zucker-Scharff-square.jpg'</span><br />  <span class="token punctuation">}</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">timelinesConfig</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />    <span class="token literal-property property">domainName</span><span class="token operator">:</span> <span class="token string">'http://localhost:8082'</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">timelineOutFolder</span><span class="token operator">:</span> <span class="token string">'timeline'</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">outDir</span><span class="token operator">:</span> <span class="token string">'/Users/zuckerscharffa/Dev/context-center/docs'</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">layoutFolderDepth</span><span class="token operator">:</span> <span class="token string">'../../'</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">timelinesInFolder</span><span class="token operator">:</span> <span class="token string">'/Users/zuckerscharffa/Dev/context-center/src/timeline'</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">customCSS</span><span class="token operator">:</span> <span class="token string">'assets/css/template-timeline.css'</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">jsPath</span><span class="token operator">:</span> <span class="token string">'http://localhost:8082/assets/timelines/js'</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">cssPath</span><span class="token operator">:</span> <span class="token string">'http://localhost:8082/assets/timelines/css'</span><br />  <span class="token punctuation">}</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">globalTimelines</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />    <span class="token literal-property property">covid</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />      <span class="token literal-property property">timeline</span><span class="token operator">:</span> <span class="token string">'covid'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">title</span><span class="token operator">:</span> <span class="token string">'COVID Timeline'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">description</span><span class="token operator">:</span> <span class="token string">'A Timeline about COVID as it was reported, maintained on Context Center'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">tags</span><span class="token operator">:</span> <span class="token punctuation">[</span>Array<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">categories</span><span class="token operator">:</span> <span class="token punctuation">[</span>Array<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">filters</span><span class="token operator">:</span> <span class="token punctuation">[</span>Array<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">doNotUseFilters</span><span class="token operator">:</span> <span class="token punctuation">[</span>Array<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">date</span><span class="token operator">:</span> <span class="token string">'Last Modified'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">layout</span><span class="token operator">:</span> <span class="token string">'timeline-standalone-item'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">header</span><span class="token operator">:</span> <span class="token string">"Let's talk about the history of COVID"</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">color</span><span class="token operator">:</span> <span class="token string">'grey'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">shortdate</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">slug</span><span class="token operator">:</span> <span class="token string">'covid'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">timelineSlug</span><span class="token operator">:</span> <span class="token string">'timeline-covid'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">timelineUrl</span><span class="token operator">:</span> <span class="token string">'covid'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">timelineName</span><span class="token operator">:</span> <span class="token string">'COVID Timeline'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">url</span><span class="token operator">:</span> <span class="token string">'http://localhost:8082/timelines/covid'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">count</span><span class="token operator">:</span> <span class="token number">68</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">lastUpdatedPost</span><span class="token operator">:</span> <span class="token number">1661569183000</span><br />    <span class="token punctuation">}</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">monkeypox</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />      <span class="token literal-property property">timeline</span><span class="token operator">:</span> <span class="token string">'monkeypox'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">title</span><span class="token operator">:</span> <span class="token string">'Monkeypox Timeline'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">description</span><span class="token operator">:</span> <span class="token string">'A Timeline about Monkeypox as it was reported, maintained on Context Center'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">tags</span><span class="token operator">:</span> <span class="token punctuation">[</span>Array<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">categories</span><span class="token operator">:</span> <span class="token punctuation">[</span>Array<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">filters</span><span class="token operator">:</span> <span class="token punctuation">[</span>Array<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">doNotUseFilters</span><span class="token operator">:</span> <span class="token punctuation">[</span>Array<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">date</span><span class="token operator">:</span> <span class="token string">'Last Modified'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">layout</span><span class="token operator">:</span> <span class="token string">'timeline-standalone-item'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">header</span><span class="token operator">:</span> <span class="token string">"Let's talk about the history of Monkeypox"</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">color</span><span class="token operator">:</span> <span class="token string">'grey'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">shortdate</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">slug</span><span class="token operator">:</span> <span class="token string">'monkeypox'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">timelineSlug</span><span class="token operator">:</span> <span class="token string">'timeline-monkeypox'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">timelineUrl</span><span class="token operator">:</span> <span class="token string">'monkeypox'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">timelineName</span><span class="token operator">:</span> <span class="token string">'Monkeypox Timeline'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">url</span><span class="token operator">:</span> <span class="token string">'http://localhost:8082/timelines/monkeypox'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">count</span><span class="token operator">:</span> <span class="token number">1</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">lastUpdatedPost</span><span class="token operator">:</span> <span class="token number">0</span><br />    <span class="token punctuation">}</span><br />  <span class="token punctuation">}</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">eleventy</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />    <span class="token literal-property property">env</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />      <span class="token literal-property property">config</span><span class="token operator">:</span> <span class="token string">'/Users/zuckerscharffa/Dev/context-center/.eleventy.js'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">root</span><span class="token operator">:</span> <span class="token string">'/Users/zuckerscharffa/Dev/context-center'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">source</span><span class="token operator">:</span> <span class="token string">'cli'</span><br />    <span class="token punctuation">}</span><br />  <span class="token punctuation">}</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">pkg</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />    <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'context-center'</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">version</span><span class="token operator">:</span> <span class="token string">'1.0.0'</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">description</span><span class="token operator">:</span> <span class="token string">'A center for context.'</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">main</span><span class="token operator">:</span> <span class="token string">'index.js'</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">scripts</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />      <span class="token literal-property property">test</span><span class="token operator">:</span> <span class="token string">'echo "Error: no test specified" &amp;&amp; exit 1'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">build</span><span class="token operator">:</span> <span class="token string">'eleventy'</span><span class="token punctuation">,</span><br />      <span class="token string-property property">'build-with-log-debug'</span><span class="token operator">:</span> <span class="token string">'DEBUG=Eleventy:Template* npx @11ty/eleventy --serve --port=8082 2>&amp;1 | tee ./buildlog.txt'</span><span class="token punctuation">,</span><br />      <span class="token string-property property">'build-with-log'</span><span class="token operator">:</span> <span class="token string">'npx @11ty/eleventy --serve --port=8082 | tee ./buildlog.txt'</span><br />    <span class="token punctuation">}</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">keywords</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">author</span><span class="token operator">:</span> <span class="token string">''</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">license</span><span class="token operator">:</span> <span class="token string">'ISC'</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">devDependencies</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />      <span class="token string-property property">'@11ty/eleventy'</span><span class="token operator">:</span> <span class="token string">'^1.0.0'</span><span class="token punctuation">,</span><br />      <span class="token string-property property">'@11ty/eleventy-navigation'</span><span class="token operator">:</span> <span class="token string">'^0.2.0'</span><span class="token punctuation">,</span><br />      <span class="token string-property property">'@11ty/eleventy-plugin-rss'</span><span class="token operator">:</span> <span class="token string">'^1.1.1'</span><span class="token punctuation">,</span><br />      <span class="token string-property property">'@quasibit/eleventy-plugin-sitemap'</span><span class="token operator">:</span> <span class="token string">'^2.1.4'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">del</span><span class="token operator">:</span> <span class="token string">'^2.2.2'</span><span class="token punctuation">,</span><br />      <span class="token string-property property">'markdown-it'</span><span class="token operator">:</span> <span class="token string">'^10.0.0'</span><span class="token punctuation">,</span><br />      <span class="token string-property property">'markdown-it-replace-link'</span><span class="token operator">:</span> <span class="token string">'^1.1.0'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">sass</span><span class="token operator">:</span> <span class="token string">'^1.34.1'</span><br />    <span class="token punctuation">}</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">dependencies</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />      <span class="token string-property property">'@11ty/eleventy-upgrade-help'</span><span class="token operator">:</span> <span class="token string">'^1.0.1'</span><span class="token punctuation">,</span><br />      <span class="token string-property property">'cross-spawn'</span><span class="token operator">:</span> <span class="token string">'^7.0.3'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">dotenv</span><span class="token operator">:</span> <span class="token string">'^10.0.0'</span><span class="token punctuation">,</span><br />      <span class="token string-property property">'eleventy-plugin-dart-sass'</span><span class="token operator">:</span> <span class="token string">'^1.0.3'</span><span class="token punctuation">,</span><br />      <span class="token string-property property">'eleventy-plugin-toc'</span><span class="token operator">:</span> <span class="token string">'^1.1.5'</span><span class="token punctuation">,</span><br />      <span class="token string-property property">'gray-matter'</span><span class="token operator">:</span> <span class="token string">'^4.0.3'</span><span class="token punctuation">,</span><br />      <span class="token string-property property">'link-contexter'</span><span class="token operator">:</span> <span class="token string">'^0.5.1'</span><span class="token punctuation">,</span><br />      <span class="token string-property property">'markdown-it-anchor'</span><span class="token operator">:</span> <span class="token string">'^8.1.2'</span><span class="token punctuation">,</span><br />      <span class="token string-property property">'markdown-it-find-and-replace'</span><span class="token operator">:</span> <span class="token string">'^1.0.2'</span><span class="token punctuation">,</span><br />      <span class="token string-property property">'markdown-it-regexp'</span><span class="token operator">:</span> <span class="token string">'^0.4.0'</span><span class="token punctuation">,</span><br />      <span class="token string-property property">'music-metadata'</span><span class="token operator">:</span> <span class="token string">'^7.11.4'</span><span class="token punctuation">,</span><br />      <span class="token string-property property">'normalize-path'</span><span class="token operator">:</span> <span class="token string">'^3.0.0'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">nunjucks</span><span class="token operator">:</span> <span class="token string">'^3.2.3'</span><span class="token punctuation">,</span><br />      <span class="token string-property property">'sanitize-filename'</span><span class="token operator">:</span> <span class="token string">'^1.6.3'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">slugify</span><span class="token operator">:</span> <span class="token string">'^1.6.0'</span><br />    <span class="token punctuation">}</span><br />  <span class="token punctuation">}</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">eleventyComputed</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />    <span class="token literal-property property">applyThis</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">timelineCheck</span><span class="token operator">:</span> <span class="token punctuation">[</span>Function<span class="token operator">:</span> timelineCheck<span class="token punctuation">]</span> <span class="token punctuation">}</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">title</span><span class="token operator">:</span> <span class="token punctuation">[</span>Function<span class="token operator">:</span> title<span class="token punctuation">]</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">description</span><span class="token operator">:</span> <span class="token punctuation">[</span>Function<span class="token operator">:</span> description<span class="token punctuation">]</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">tags</span><span class="token operator">:</span> <span class="token punctuation">[</span>Function<span class="token operator">:</span> tags<span class="token punctuation">]</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">categories</span><span class="token operator">:</span> <span class="token punctuation">[</span>Function<span class="token operator">:</span> categories<span class="token punctuation">]</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">filters</span><span class="token operator">:</span> <span class="token punctuation">[</span>Function<span class="token operator">:</span> filters<span class="token punctuation">]</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">date</span><span class="token operator">:</span> <span class="token punctuation">[</span>Function<span class="token operator">:</span> date<span class="token punctuation">]</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">header</span><span class="token operator">:</span> <span class="token punctuation">[</span>Function<span class="token operator">:</span> header<span class="token punctuation">]</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">color</span><span class="token operator">:</span> <span class="token punctuation">[</span>Function<span class="token operator">:</span> color<span class="token punctuation">]</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">shortdate</span><span class="token operator">:</span> <span class="token punctuation">[</span>Function<span class="token operator">:</span> shortdate<span class="token punctuation">]</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">lastUpdatedPost</span><span class="token operator">:</span> <span class="token punctuation">[</span>Function<span class="token operator">:</span> lastUpdatedPost<span class="token punctuation">]</span><br />  <span class="token punctuation">}</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">layout</span><span class="token operator">:</span> <span class="token string">'timeline-standalone-item'</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">description</span><span class="token operator">:</span> <span class="token string">'The GOP battles over a trillion-dollar stimulus deal. Ahead of the November election, President Trump guts a landmark environmental law. And, how to avoid a devastating potential kink in the vaccine supply chain.'</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">tags</span><span class="token operator">:</span> <span class="token punctuation">[</span><br />    <span class="token string">'timeline'</span><span class="token punctuation">,</span><br />    <span class="token string">'Monkeypox'</span><span class="token punctuation">,</span><br />    <span class="token string">'Health'</span><span class="token punctuation">,</span><br />    <span class="token string">'Medicine'</span><span class="token punctuation">,</span><br />    <span class="token string">'Stimulus'</span><span class="token punctuation">,</span><br />    <span class="token string">'Markets'</span><br />  <span class="token punctuation">]</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">date</span><span class="token operator">:</span> <span class="token number">2020</span><span class="token operator">-</span><span class="token number">06</span><span class="token operator">-</span>22T16<span class="token operator">:</span><span class="token number">00</span><span class="token operator">:</span><span class="token number">00</span><span class="token punctuation">.</span>100Z<span class="token punctuation">,</span><br />  <span class="token literal-property property">timeline</span><span class="token operator">:</span> <span class="token string">'monkeypox'</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">title</span><span class="token operator">:</span> <span class="token string">'A looming deadline for tens of millions of Americans'</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">categories</span><span class="token operator">:</span> <span class="token punctuation">[</span> <span class="token string">'News'</span> <span class="token punctuation">]</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">filters</span><span class="token operator">:</span> <span class="token punctuation">[</span> <span class="token string">'USA'</span> <span class="token punctuation">]</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">doNotUseFilters</span><span class="token operator">:</span> <span class="token punctuation">[</span> <span class="token string">'4 and under'</span> <span class="token punctuation">]</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">header</span><span class="token operator">:</span> <span class="token string">"Let's talk about the history of Monkeypox"</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">color</span><span class="token operator">:</span> <span class="token string">'grey'</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">shortdate</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">dateAdded</span><span class="token operator">:</span> <span class="token number">2022</span><span class="token operator">-</span><span class="token number">08</span><span class="token operator">-</span>09T02<span class="token operator">:</span><span class="token number">59</span><span class="token operator">:</span><span class="token number">43</span><span class="token punctuation">.</span>100Z<span class="token punctuation">,</span><br />  <span class="token literal-property property">isBasedOn</span><span class="token operator">:</span> <span class="token string">'https://www.washingtonpost.com/podcasts/post-reports/a-looming-deadline-for-tens-of-millions-americans/'</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">page</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />    <span class="token literal-property property">date</span><span class="token operator">:</span> <span class="token number">2020</span><span class="token operator">-</span><span class="token number">06</span><span class="token operator">-</span>22T16<span class="token operator">:</span><span class="token number">00</span><span class="token operator">:</span><span class="token number">00</span><span class="token punctuation">.</span>100Z<span class="token punctuation">,</span><br />    <span class="token literal-property property">inputPath</span><span class="token operator">:</span> <span class="token string">'./src/timeline/monkeypox/a-looming-deadline-for-tens-of-millions-americans.md'</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">fileSlug</span><span class="token operator">:</span> <span class="token string">'a-looming-deadline-for-tens-of-millions-americans'</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">filePathStem</span><span class="token operator">:</span> <span class="token string">'/timeline/monkeypox/a-looming-deadline-for-tens-of-millions-americans'</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">outputFileExtension</span><span class="token operator">:</span> <span class="token keyword">undefined</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">url</span><span class="token operator">:</span> <span class="token string">'/timeline/monkeypox/a-looming-deadline-for-tens-of-millions-americans/'</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">outputPath</span><span class="token operator">:</span> <span class="token string">'docs/timeline/monkeypox/a-looming-deadline-for-tens-of-millions-americans/index.html'</span><br />  <span class="token punctuation">}</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">collections</span><span class="token operator">:</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">applyThis</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">timelineCheck</span><span class="token operator">:</span> <span class="token string">''</span> <span class="token punctuation">}</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">lastUpdatedPost</span><span class="token operator">:</span> <span class="token string">''</span><br /><span class="token punctuation">}</span></code></pre>
<p id="code-skip-day-8-fix-image-retrieve-1">Ok, have to do some translation from the globalTimeline object to the post context. The next step is setting up the <code>entry</code> object.</p>
<p><code>git commit -am &quot;Progressing timeline with fixes to contexter plugin and translating the object of the top timeline properly&quot;</code></p>
]]></content:encoded>
	</item>
	
	<item>
		<title>Context Center Timelines - Day 7 - Detour to dealing with image retrieval breaking my build process</title>
		<link>https://fightwithtools.dev/posts/projects/context-timelines/day-7-urls-of-individual-timelines/?source=rss</link>
		<pubDate>Mon, 05 Sep 2022 02:59:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/projects/context-timelines/day-7-urls-of-individual-timelines/</guid>
		<description>Something weird is happening in promises.</description>
		<content:encoded><![CDATA[<h2 id="project-scope-and-todos" tabindex="-1">Project Scope and ToDos</h2>
<ol>
<li>Create timeline pages where one can see the whole timeline of a particular event</li>
<li>Give timeline items type or category icons so that you can easily scan what is happening.</li>
<li>Allow the user to enter the timeline at any individually sharable link of an event and seamlessly scroll up and down</li>
</ol>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Deliver timelines as a plugin that can be extended by other Eleventy users</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Auto-create social-media-ready screenshots of a timeline item</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Integrate with Contexter to have context-full link cards in the timeline</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Leverage the Live Blog format of Schema dot org</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Allow each entry to be its own Markdown file</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Handle SASS instead of CSS</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Fast Scroller by Month and Year</li>
</ul>
<h2 id="day-7" tabindex="-1">Day 7</h2>
<p>Ok, there are two parts to figuring out how the individual URLs work. The first is to have the individual URLs available to copy from the timeline itself.</p>
<p>First lets get back to a running local env. Looks like <code>timeline-item</code>'s data cascade at the template level is having some issues. Says <code>timeline</code> is missing from the following functions:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/context-timelines/day-7-urls-of-individual-timelines/#code-skip-day-7-urls-of-individual-timelines-4" id="skip-to-code-skip-day-7-urls-of-individual-timelines-4" class="skip-link">Skip code block ▼</a></p>
<pre class="language-js"><code class="language-js"><span class="token literal-property property">applyThis</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />    <span class="token function-variable function">timelineCheck</span><span class="token operator">:</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">siteContext</span><span class="token punctuation">)</span><span class="token punctuation">{</span><br />        <span class="token keyword">if</span> <span class="token punctuation">(</span>siteContext<span class="token punctuation">)</span><span class="token punctuation">{</span><br />            console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">"Global check"</span><span class="token punctuation">,</span> siteContext<span class="token punctuation">.</span>globalTimelines<span class="token punctuation">,</span> <span class="token string">'for timeline'</span><span class="token punctuation">,</span> siteContext<span class="token operator">?.</span>timeline<span class="token punctuation">,</span> <span class="token string">' and global object is '</span><span class="token punctuation">,</span> siteContext<span class="token punctuation">)</span><br />        <span class="token punctuation">}</span><br />    <span class="token punctuation">}</span><span class="token punctuation">,</span><br /><span class="token punctuation">}</span><span class="token punctuation">,</span><br /><span class="token function-variable function">timelineData</span><span class="token operator">:</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">siteContext</span><span class="token punctuation">)</span><span class="token punctuation">{</span><br />    <span class="token keyword">if</span> <span class="token punctuation">(</span>siteContext<span class="token operator">?.</span>timeline <span class="token operator">&amp;&amp;</span> siteContext<span class="token operator">?.</span>globalTimelines<span class="token punctuation">.</span><span class="token function">hasOwnProperty</span><span class="token punctuation">(</span>siteContext<span class="token punctuation">.</span>timeline<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">{</span><br />        <span class="token keyword">return</span> siteContext<span class="token punctuation">.</span>globalTimelines<span class="token punctuation">[</span>timeline<span class="token punctuation">]</span><br />    <span class="token punctuation">}</span><br /><span class="token punctuation">}</span><span class="token punctuation">,</span></code></pre>
<p id="code-skip-day-7-urls-of-individual-timelines-4">Hmmm, even removing that I'm still having the build process fail. Looks like there is another problem. Maybe a problem with the archive page retrieval process.</p>
<p>Yeah, looks like it is throwing an error as part of the HTTP response check.</p>
<p>Last thing in the log is this function:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/context-timelines/day-7-urls-of-individual-timelines/#code-skip-day-7-urls-of-individual-timelines-3" id="skip-to-code-skip-day-7-urls-of-individual-timelines-3" class="skip-link">Skip code block ▼</a></p>
<pre class="language-js"><code class="language-js"><span class="token keyword">const</span> <span class="token function-variable function">checkStatus</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">response</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />	<span class="token keyword">if</span> <span class="token punctuation">(</span>response<span class="token punctuation">.</span>ok<span class="token punctuation">)</span> <span class="token punctuation">{</span><br />		<span class="token comment">// response.status >= 200 &amp;&amp; response.status &lt; 300</span><br />		<span class="token keyword">return</span> response<span class="token punctuation">;</span><br />	<span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span><br />		console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">"HTTP response internals"</span><span class="token punctuation">,</span> response<span class="token punctuation">.</span>internals<span class="token punctuation">)</span><span class="token punctuation">;</span><br />		<span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">HTTPResponseError</span><span class="token punctuation">(</span>response<span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token punctuation">}</span><br /><span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
<p id="code-skip-day-7-urls-of-individual-timelines-3">There should be plenty of places where this gets caught, but it doesn't seem to be catched properly. Instead it is crashing the build. Ok so I don't see any useful information. It looks like there's a problem there but I don't know what it is. Let's get more information and pass it through that function. We'll need the URL to understand what's going on. I'll rewrite the status check in order to emit the URL into the log.</p>
<p>Ok, interesting. It looks like the problem is specifically with retrieving a PNG file. Ok, I fixed the problem with fetchUrl not being caught a while back, but I only did it with pages. I missed catching the error with images. That must be where the problem is here. Ok, let's see if this is a fix.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/context-timelines/day-7-urls-of-individual-timelines/#code-skip-day-7-urls-of-individual-timelines-2" id="skip-to-code-skip-day-7-urls-of-individual-timelines-2" class="skip-link">Skip code block ▼</a></p>
<pre class="language-js"><code class="language-js"><span class="token keyword">const</span> <span class="token function-variable function">getImageAndWriteLocally</span> <span class="token operator">=</span> <span class="token keyword">async</span> <span class="token punctuation">(</span><span class="token parameter">url<span class="token punctuation">,</span> imageCacheFile</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />	<span class="token keyword">try</span> <span class="token punctuation">{</span><br />		<span class="token keyword">const</span> responseImage <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token function">fetchUrl</span><span class="token punctuation">(</span>url<span class="token punctuation">)</span><span class="token punctuation">;</span><br />		<span class="token keyword">if</span> <span class="token punctuation">(</span>responseImage<span class="token punctuation">)</span> <span class="token punctuation">{</span><br />			<span class="token keyword">const</span> buffer <span class="token operator">=</span> <span class="token keyword">await</span> responseImage<span class="token punctuation">.</span><span class="token function">buffer</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />			fs<span class="token punctuation">.</span><span class="token function">writeFileSync</span><span class="token punctuation">(</span>imageCacheFile<span class="token punctuation">,</span> buffer<span class="token punctuation">)</span><span class="token punctuation">;</span><br />			<span class="token keyword">return</span> imageCacheFile<span class="token punctuation">;</span><br />		<span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span><br />			<span class="token keyword">return</span> <span class="token boolean">false</span><span class="token punctuation">;</span><br />		<span class="token punctuation">}</span><br />	<span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span>e<span class="token punctuation">)</span> <span class="token punctuation">{</span><br />		<span class="token keyword">return</span> <span class="token boolean">false</span><span class="token punctuation">;</span><br />	<span class="token punctuation">}</span><br /><span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
<p id="code-skip-day-7-urls-of-individual-timelines-2">That doesn't seem to have done it. It is still the same error causing the problem, but it isn't properly resolving. I should be able to return <code>false</code> in the catch statement and be done with this as my error handling?</p>
<p>It looks like I have identified the right function. When I add more logging to downstream error handling it doesn't show up. So the system is indeed breaking at this function. I need to reconfigure the try to capture only the specific <code>await</code> function that is having a problem I guess. I'd hoped returning a <code>false</code> would be fine, but it seems the Error is still bubbling up.</p>
<p>Let me get closer to the metal and try returning an actual promise.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/context-timelines/day-7-urls-of-individual-timelines/#code-skip-day-7-urls-of-individual-timelines-1" id="skip-to-code-skip-day-7-urls-of-individual-timelines-1" class="skip-link">Skip code block ▼</a></p>
<pre class="language-js"><code class="language-js"><span class="token keyword">const</span> <span class="token function-variable function">getImageAndWriteLocally</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">url<span class="token punctuation">,</span> imageCacheFile</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />	<span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">Promise</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">resolve<span class="token punctuation">,</span> reject</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />		<span class="token function">fetchUrl</span><span class="token punctuation">(</span>url<span class="token punctuation">)</span><br />			<span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">responseImage</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />				<span class="token keyword">if</span> <span class="token punctuation">(</span>responseImage<span class="token punctuation">)</span> <span class="token punctuation">{</span><br />					responseImage<span class="token punctuation">.</span><span class="token function">buffer</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">buffer</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />						fs<span class="token punctuation">.</span><span class="token function">writeFileSync</span><span class="token punctuation">(</span>imageCacheFile<span class="token punctuation">,</span> buffer<span class="token punctuation">)</span><span class="token punctuation">;</span><br />						<span class="token function">resolve</span><span class="token punctuation">(</span>imageCacheFile<span class="token punctuation">)</span><span class="token punctuation">;</span><br />					<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />				<span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span><br />					<span class="token function">resolve</span><span class="token punctuation">(</span><span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />				<span class="token punctuation">}</span><br />			<span class="token punctuation">}</span><span class="token punctuation">)</span><br />			<span class="token punctuation">.</span><span class="token function">catch</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">error</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />				console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">"Image write failed "</span><span class="token punctuation">,</span> error<span class="token punctuation">)</span><span class="token punctuation">;</span><br />				<span class="token function">resolve</span><span class="token punctuation">(</span><span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />			<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p id="code-skip-day-7-urls-of-individual-timelines-1">Ok, now it is giving me better information. But still not working.</p>
<p><code>git commit -am &quot;Build process is breaking for something to do with image retrieval.&quot;</code></p>
]]></content:encoded>
	</item>
	
	<item>
		<title>Context Center Timelines - Day 6 - Combining Timeline data with individual Timeline items</title>
		<link>https://fightwithtools.dev/posts/projects/context-timelines/day-6-individual-timeline-items/?source=rss</link>
		<pubDate>Thu, 18 Aug 2022 02:59:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/projects/context-timelines/day-6-individual-timeline-items/</guid>
		<description>I need to combine data from one Eleventy collection with another, but without creating an additional collection.</description>
		<content:encoded><![CDATA[<h2 id="project-scope-and-todos" tabindex="-1">Project Scope and ToDos</h2>
<ol>
<li>Create timeline pages where one can see the whole timeline of a particular event</li>
<li>Give timeline items type or category icons so that you can easily scan what is happening.</li>
<li>Allow the user to enter the timeline at any individually sharable link of an event and seamlessly scroll up and down</li>
</ol>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Deliver timelines as a plugin that can be extended by other Eleventy users</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Auto-create social-media-ready screenshots of a timeline item</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Integrate with Contexter to have context-full link cards in the timeline</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Leverage the Live Blog format of Schema dot org</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Allow each entry to be its own Markdown file</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Handle SASS instead of CSS</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Fast Scroller by Month and Year</li>
</ul>
<h2 id="day-6" tabindex="-1">Day 6</h2>
<p>Now that I've extracted the shared components betweeen the overall timeline page and the potential individual item pages I need to set up the indiviual timeline pages.</p>
<p>I'll need to set up a way to query the other pages so that they can be populated into the individual timeline pages, but that means getting the overall timeline object, and all its info, into the individual timeline pages. I'll have to do this when setting up the collection. But the collection is pre-created by the JSON at the level of each folder. I'll need to figure out a way to either not do that or to enhance the collection.</p>
<p>I tried setting up a new collection, but the existing collection formed by the setup of folders inside <code>src</code> is still activating. I could move it outside of the src folder, but I don't like that idea and it doesn't make a lot of sense. I could use <code>eleventyExcludeFromCollections: true</code> to remove it from the collections system and add it in manually, but I don't like that approach at all.</p>
<p data-wordfix="true">As far as I can tell, there's <a href="https://www.11ty.dev/docs/collections/#advanced-custom-filtering-and-sorting" target="_blank">no way</a> to 'enhance' a preexisting collection?</p>
<p>Ok, I tried a few ways around it and I think the best approach here is to instead add the timelines' data to the global site configuration object. I can then pull it during the build process executed at the template level for eleventyComputer data. For better or worse this is a function that is only available at later versions of Eleventy so this will lock the plugin to those versions.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/context-timelines/day-6-individual-timeline-items/#code-skip-day-6-individual-timeline-items-1" id="skip-to-code-skip-day-6-individual-timeline-items-1" class="skip-link">Skip code block ▼</a></p>
<pre class="language-js"><code class="language-js">eleventyConfig<span class="token punctuation">.</span><span class="token function">addGlobalData</span><span class="token punctuation">(</span><br />	<span class="token string">"globalTimelines"</span><span class="token punctuation">,</span><br />	timelines<span class="token punctuation">.</span><span class="token function">reduce</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">previousValue<span class="token punctuation">,</span> currentValue</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />		<span class="token comment">//console.log("reduce", previousValue, currentValue);</span><br />		previousValue<span class="token punctuation">[</span>currentValue<span class="token punctuation">.</span>timeline<span class="token punctuation">]</span> <span class="token operator">=</span> currentValue<span class="token punctuation">;</span><br />		<span class="token keyword">return</span> previousValue<span class="token punctuation">;</span><br />	<span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">)</span><br /><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p id="code-skip-day-6-individual-timeline-items-1"><code>git commit -am &quot;Setting up a new timeline and getting the data from individual timelines on the global object&quot;</code></p>
]]></content:encoded>
	</item>
	
	<item>
		<title>Context Center Timelines - Day 5 - Making Templates More Useful and Accessible to Site Developers.</title>
		<link>https://fightwithtools.dev/posts/projects/context-timelines/day-5-setting-up-templates-that-can-be-extended-by-nunjucks/?source=rss</link>
		<pubDate>Thu, 11 Aug 2022 02:59:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/projects/context-timelines/day-5-setting-up-templates-that-can-be-extended-by-nunjucks/</guid>
		<description>Setting up better versions of the timeline templates that can be extended by the site in use</description>
		<content:encoded><![CDATA[<h2 id="project-scope-and-todos" tabindex="-1">Project Scope and ToDos</h2>
<ol>
<li>Create timeline pages where one can see the whole timeline of a particular event</li>
<li>Give timeline items type or category icons so that you can easily scan what is happening.</li>
<li>Allow the user to enter the timeline at any individually sharable link of an event and seamlessly scroll up and down</li>
</ol>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Deliver timelines as a plugin that can be extended by other Eleventy users</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Auto-create social-media-ready screenshots of a timeline item</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Integrate with Contexter to have context-full link cards in the timeline</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Leverage the Live Blog format of Schema dot org</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Allow each entry to be its own Markdown file</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Handle SASS instead of CSS</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Fast Scroller by Month and Year</li>
</ul>
<h2 id="day-5" tabindex="-1">Day 5</h2>
<p>I realized that extending sites using the plugins, including my own, might want to insert stuff in the templates, like a nav.</p>
<p data-wordfix="true">Thankfully, Nunjucks templates in Eleventy can do some really interesting things.</p>
<p>I was hoping I could treat it like it was all in one location. However, it doesn't seem to be the case. I can create a filepath to it from my site directory like:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/context-timelines/day-5-setting-up-templates-that-can-be-extended-by-nunjucks/#code-skip-day-5-setting-up-templates-that-can-be-extended-by-nunjucks-3" id="skip-to-code-skip-day-5-setting-up-templates-that-can-be-extended-by-nunjucks-3" class="skip-link">Skip code block ▼</a></p>
<pre class="language-liquid"><code class="language-liquid">{%<span class="token templateTag"> include <span class="token string">"../../_custom-plugins/timelinety/src/layouts/timeline-base.njk"</span> </span>%}</code></pre>
<p id="code-skip-day-5-setting-up-templates-that-can-be-extended-by-nunjucks-3">Oh, but the actual <code>js</code> block (that starts and ends with <code>---</code>) that can be at the top of the <code>njk</code> file has to <em>only</em> be at the top of the top most template file. So I can't use or extend a template that contains that. I'll have to further destructure my templates so that I can use them effectively.</p>
<p>Now I have <code>timeline.njk</code> which can be used by someone who wants an out-of-the-box timeline. It looks like this:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/context-timelines/day-5-setting-up-templates-that-can-be-extended-by-nunjucks/#code-skip-day-5-setting-up-templates-that-can-be-extended-by-nunjucks-2" id="skip-to-code-skip-day-5-setting-up-templates-that-can-be-extended-by-nunjucks-2" class="skip-link">Skip code block ▼</a></p>
<pre class="language-liquid"><code class="language-liquid">---js<br />{<br />    eleventyComputed: {<br />        applyThis: {<br />            timelineCheck: function(siteContext){<br />                if (siteContext){<br />                    console.log(siteContext.timeline, "Global check")<br />                }<br />            },<br />        },<br />        title: function(siteContext){<br />            if (siteContext?.timeline)<br />                return siteContext.timeline.title<br /><br />            return '';<br />        },<br />        description: function(siteContext){<br />            if (siteContext?.timeline)<br />                return siteContext.timeline.description<br /><br />            return '';<br />        },<br />        tags: function(siteContext){<br />            if (siteContext?.timeline)<br />                return siteContext.timeline.tags<br /><br />            return [];<br />        },<br />        categories: function(siteContext){<br />            if (siteContext?.timeline)<br />                return siteContext.timeline.categories<br /><br />            return '';<br />        },<br />        filters: function(siteContext){<br />            if (siteContext?.timeline)<br />                return siteContext.timeline.filters<br /><br />            return [];<br />        },<br />        date: function(siteContext){<br />            if (siteContext?.timeline)<br />                return siteContext.timeline.date<br /><br />            return "Last Modified";<br />        },<br />        header: function(siteContext){<br />            if (siteContext?.timeline)<br />                return siteContext.timeline.header<br /><br />            return [];<br />        },<br />        color: function(siteContext){<br />            if (siteContext?.timeline)<br />                return siteContext.timeline.color<br /><br />            return 'grey';<br />        },<br />        shortdate: function(siteContext){<br />            if (siteContext?.timeline)<br />                return siteContext.timeline.shortdate<br /><br />            return false;<br />        },<br />        lastUpdatedPost: function(siteContext){<br />            if (siteContext?.timeline)<br />                return siteContext.timeline.lastUpdatedPost<br /><br />            return false;<br />        },<br />    }<br />}<br />---<br />{%<span class="token templateTag"> include <span class="token string">"./timeline-wrapper.njk"</span> </span>%}<br /></code></pre>
<p id="code-skip-day-5-setting-up-templates-that-can-be-extended-by-nunjucks-2"><code>timeline-wrapper.njk</code> which can be extended by someone who wants to use it in their own template and even has some nice Nunjucks blocks that can be used to overwrite the header or the nav. They'll have to pull in their own version of the <code>---js</code> block of course.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/context-timelines/day-5-setting-up-templates-that-can-be-extended-by-nunjucks/#code-skip-day-5-setting-up-templates-that-can-be-extended-by-nunjucks-1" id="skip-to-code-skip-day-5-setting-up-templates-that-can-be-extended-by-nunjucks-1" class="skip-link">Skip code block ▼</a></p>
<pre class="language-liquid"><code class="language-liquid"><span class="token doctype"><span class="token punctuation">&lt;!</span><span class="token doctype-tag">DOCTYPE</span> <span class="token name">html</span><span class="token punctuation">></span></span><br /><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>html</span> <span class="token attr-name">lang</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>en<span class="token punctuation">"</span></span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>no-js<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><br />    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>head</span><span class="token punctuation">></span></span><br />    {%<span class="token templateTag"> block head </span>%}<br /><br />        {%<span class="token templateTag"> include <span class="token string">"./head.njk"</span> </span>%}<br /><br />    {%<span class="token templateTag"> endblock </span>%}<br />    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>head</span><span class="token punctuation">></span></span><br />    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>body</span><span class="token punctuation">></span></span><br />    {%<span class="token templateTag"> block nav </span>%}<br />        <span class="token comment">&lt;!-- &lt;nav>&lt;a href="{{timelinesConfig.domainName}}">Return to Home&lt;/a>&lt;/nav> --></span><br />    {%<span class="token templateTag"> endblock </span>%}<br />    {%<span class="token templateTag"> include <span class="token string">"./timeline-base.njk"</span> </span>%}<br />    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>body</span><span class="token punctuation">></span></span><br /><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>html</span><span class="token punctuation">></span></span></code></pre>
<p id="code-skip-day-5-setting-up-templates-that-can-be-extended-by-nunjucks-1">I have the previously created <code>head.njk</code> that I cas use as the default setup for the HEAD element. Then I have <code>timeline-base.njk</code> and that has the core timeline setup, which itself has the previously set up <code>timeline-entry.njk</code>.</p>
<p>It's a little complicated, but I think that's the best way to handle the logical file separations and also allow future developers to extend it.</p>
<p>Ok, but now I need to reorganize my styles a little so I can get the Nav in there and have it look the same as the rest of the site.</p>
<p>That will mean pulling out the nav styles into their own SASS file that I can include in the timeline SASS file, as well as grabbing some of the color rules on <code>:root</code> and some of the other style rules on the base SASS. This will essentially allow me to encapsulate the nav.</p>
<p><code>git commit -am &quot;Restructure timeline templates and SASS code to support new configuration.&quot;</code></p>
]]></content:encoded>
	</item>
	
	<item>
		<title>Context Center Timelines - Day 4 - Making Template Elements Ready to Use for Other Templates.</title>
		<link>https://fightwithtools.dev/posts/projects/context-timelines/day-4-making-template-elements-ready-for-further-use/?source=rss</link>
		<pubDate>Tue, 09 Aug 2022 02:59:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/projects/context-timelines/day-4-making-template-elements-ready-for-further-use/</guid>
		<description>Setting up better versions of the timeline templates</description>
		<content:encoded><![CDATA[<h2 id="project-scope-and-todos" tabindex="-1">Project Scope and ToDos</h2>
<ol>
<li>Create timeline pages where one can see the whole timeline of a particular event</li>
<li>Give timeline items type or category icons so that you can easily scan what is happening.</li>
<li>Allow the user to enter the timeline at any individually sharable link of an event and seamlessly scroll up and down</li>
</ol>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Deliver timelines as a plugin that can be extended by other Eleventy users</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Auto-create social-media-ready screenshots of a timeline item</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Integrate with Contexter to have context-full link cards in the timeline</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Leverage the Live Blog format of Schema dot org</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Allow each entry to be its own Markdown file</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Handle SASS instead of CSS</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Fast Scroller by Month and Year</li>
</ul>
<h2 id="day-4" tabindex="-1">Day 4</h2>
<p>Ok, so first step is to separate out some of the basics of each template so that they can be reused.</p>
<p><code>git commit -am &quot;Setting up timeline shared Nunjucks components&quot;</code></p>
<p>This is the first step towards getting individual timeline item pages working, making sure I can reuse them easily and maintain them easily.</p>
<p>Next I need to make sure those elements have everything in place and can be generalized properly out to individual pages.</p>
<p>Looks like the filter isn't working as well as I'd hoped. For one thing I'd like to make it so tags naturally flow into filters. That's going to mean further changing the build of the timeline object.</p>
<p>First, I'll pull the Timeline object:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/context-timelines/day-4-making-template-elements-ready-for-further-use/#code-skip-day-4-making-template-elements-ready-for-further-use-4" id="skip-to-code-skip-day-4-making-template-elements-ready-for-further-use-4" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">let</span> filterSet <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token operator">...</span>timelineData<span class="token punctuation">.</span>filters<span class="token punctuation">]</span><span class="token punctuation">;</span></code></pre>
<p id="code-skip-day-4-making-template-elements-ready-for-further-use-4">I might want to have filters set explicitly instead of just tags, so let's support both.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/context-timelines/day-4-making-template-elements-ready-for-further-use/#code-skip-day-4-making-template-elements-ready-for-further-use-3" id="skip-to-code-skip-day-4-making-template-elements-ready-for-further-use-3" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">if</span> <span class="token punctuation">(</span>mdObject<span class="token punctuation">.</span>data<span class="token punctuation">.</span><span class="token function">hasOwnProperty</span><span class="token punctuation">(</span><span class="token string">"filters"</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />	filterSet <span class="token operator">=</span> filterSet<span class="token punctuation">.</span><span class="token function">concat</span><span class="token punctuation">(</span>mdObject<span class="token punctuation">.</span>data<span class="token punctuation">.</span>filters<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span><br />	filterSet <span class="token operator">=</span> filterSet<span class="token punctuation">.</span><span class="token function">concat</span><span class="token punctuation">(</span>mdObject<span class="token punctuation">.</span>data<span class="token punctuation">.</span>tags<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span></code></pre>
<p id="code-skip-day-4-making-template-elements-ready-for-further-use-3">This will let me set filters explicitly on a timeline item object, but otherwise default to tags.</p>
<p>Next, there may be some tags or filters I want to exclude without explicitly setting up the filter argument on a timeline object. Let's create a timeline-level set of exclusions for filter names.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/context-timelines/day-4-making-template-elements-ready-for-further-use/#code-skip-day-4-making-template-elements-ready-for-further-use-2" id="skip-to-code-skip-day-4-making-template-elements-ready-for-further-use-2" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">if</span> <span class="token punctuation">(</span>timelineData<span class="token punctuation">.</span><span class="token function">hasOwnProperty</span><span class="token punctuation">(</span><span class="token string">"doNotUseFilters"</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />	filterSet <span class="token operator">=</span> filterSet<span class="token punctuation">.</span><span class="token function">filter</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">el</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />		<span class="token keyword">return</span> <span class="token operator">!</span>timelineData<span class="token punctuation">.</span>doNotUseFilters<span class="token punctuation">.</span><span class="token function">includes</span><span class="token punctuation">(</span>el<span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span></code></pre>
<p id="code-skip-day-4-making-template-elements-ready-for-further-use-2">Ok, that looks good. It's working the way I'd hoped and giving me a lot of options. Only one issue with the timeline pages now, it seems the sort isn't working as I'd precisely hoped. But it should, I'm using the normal date field for these posts.</p>
<p>For tracking when a page was last updated, I added a field - <code>dateAdded</code>. That's being used to generate a new template element that says when the page was last updated. That's good and it is working. However, for some reason one of the posts isn't falling into the date sort properly.</p>
<p>...</p>
<p>Ok, I played around with it some more and multiple posts aren't showing up properly in order and I don't know why. I am not sure what the reason was, I had assumed collections sort by date by default... but something in my site was going wrong. It does look like sorting it explicitly seems to fix the problem.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/context-timelines/day-4-making-template-elements-ready-for-further-use/#code-skip-day-4-making-template-elements-ready-for-further-use-1" id="skip-to-code-skip-day-4-making-template-elements-ready-for-further-use-1" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript">timelines<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">timelineObj</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />  eleventyConfig<span class="token punctuation">.</span><span class="token function">addCollection</span><span class="token punctuation">(</span><br />  	<span class="token string">"timeline-"</span> <span class="token operator">+</span> timelineObj<span class="token punctuation">.</span>timeline<span class="token punctuation">,</span><br />  	<span class="token punctuation">(</span><span class="token parameter">collection</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />  		<span class="token keyword">const</span> collectionFiltered <span class="token operator">=</span> collection<br />  			<span class="token punctuation">.</span><span class="token function">getAll</span><span class="token punctuation">(</span><span class="token punctuation">)</span><br />  			<span class="token punctuation">.</span><span class="token function">filter</span><span class="token punctuation">(</span><br />  				<span class="token punctuation">(</span><span class="token parameter">item</span><span class="token punctuation">)</span> <span class="token operator">=></span> item<span class="token punctuation">.</span>data<span class="token punctuation">.</span>timeline <span class="token operator">===</span> timelineObj<span class="token punctuation">.</span>timeline<br />  			<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br />  		collectionFiltered<span class="token punctuation">.</span><span class="token function">sort</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">a<span class="token punctuation">,</span> b</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />  			<span class="token keyword">if</span> <span class="token punctuation">(</span>a<span class="token punctuation">.</span>date <span class="token operator">></span> b<span class="token punctuation">.</span>date<span class="token punctuation">)</span> <span class="token keyword">return</span> <span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">;</span><br />  			<span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>a<span class="token punctuation">.</span>date <span class="token operator">&lt;</span> b<span class="token punctuation">.</span>date<span class="token punctuation">)</span> <span class="token keyword">return</span> <span class="token number">1</span><span class="token punctuation">;</span><br />  			<span class="token keyword">else</span> <span class="token keyword">return</span> <span class="token number">0</span><span class="token punctuation">;</span><br />  		<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br />  		<span class="token keyword">return</span> collectionFiltered<span class="token punctuation">;</span><br />  	<span class="token punctuation">}</span><br />  <span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p id="code-skip-day-4-making-template-elements-ready-for-further-use-1">Good stuff. The ordering is working now.</p>
<p><code>git commit -am &quot;Adding new COVID entries for testing&quot;</code></p>
]]></content:encoded>
	</item>
	
	<item>
		<title>Context Center Timelines - Day 3 - Integrate Contexter and add data to the timeline page.</title>
		<link>https://fightwithtools.dev/posts/projects/context-timelines/day-3-integrate-contexter-timeline-pages-metadata/?source=rss</link>
		<pubDate>Tue, 26 Jul 2022 02:59:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/projects/context-timelines/day-3-integrate-contexter-timeline-pages-metadata/</guid>
		<description>Setting up context-rich timeline collections and layouts now with archiving and more metadata</description>
		<content:encoded><![CDATA[<h2 id="project-scope-and-todos" tabindex="-1">Project Scope and ToDos</h2>
<ol>
<li>Create timeline pages where one can see the whole timeline of a particular event</li>
<li>Give timeline items type or category icons so that you can easily scan what is happening.</li>
<li>Allow the user to enter the timeline at any individually sharable link of an event and seamlessly scroll up and down</li>
</ol>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Deliver timelines as a plugin that can be extended by other Eleventy users</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Auto-create social-media-ready screenshots of a timeline item</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Integrate with Contexter to have context-full link cards in the timeline</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Leverage the Live Blog format of Schema dot org</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Allow each entry to be its own Markdown file</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Handle SASS instead of CSS</li>
</ul>
<h2 id="day-3" tabindex="-1">Day 3</h2>
<p>Ok, after playing around with the CSS for a bit I think I've got the basic layout working. Now I need to get the metadata passed on to the page. First I should take the JSON file and merge it in to the timeline object I'm creating.</p>
<p>I've been passing this data in through the MD file, but I should be able to handle it in the NJK file with a <code>js</code> header.</p>
<p>Previously I've been setting up self executing functions, however, it looks like I no longer need to do that. And if I pass these functions inside the <code>eleventyComputed</code> object I'll get access to the global data.</p>
<p>I was able to verify it using a custom function that I passed into there. It looks like this.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/context-timelines/day-3-integrate-contexter-timeline-pages-metadata/#code-skip-day-3-integrate-contexter-timeline-pages-metadata-2" id="skip-to-code-skip-day-3-integrate-contexter-timeline-pages-metadata-2" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript"><span class="token punctuation">{</span><br />    <span class="token literal-property property">eleventyComputed</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />        <span class="token literal-property property">applyThis</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />            <span class="token function-variable function">timelineCheck</span><span class="token operator">:</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">siteContext</span><span class="token punctuation">)</span><span class="token punctuation">{</span><br />                <span class="token keyword">if</span> <span class="token punctuation">(</span>siteContext<span class="token punctuation">)</span><span class="token punctuation">{</span><br />                    console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>siteContext<span class="token punctuation">.</span>timeline<span class="token punctuation">,</span> <span class="token string">"Global check"</span><span class="token punctuation">)</span><br />                <span class="token punctuation">}</span><br />            <span class="token punctuation">}</span><span class="token punctuation">,</span><br />        <span class="token punctuation">}</span><span class="token punctuation">,</span><br />        <span class="token function-variable function">title</span><span class="token operator">:</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">siteContext</span><span class="token punctuation">)</span><span class="token punctuation">{</span><br />            <span class="token keyword">if</span> <span class="token punctuation">(</span>siteContext<span class="token operator">?.</span>timeline<span class="token punctuation">)</span><br />                <span class="token keyword">return</span> siteContext<span class="token punctuation">.</span>timeline<span class="token punctuation">.</span>title<br /><br />            <span class="token keyword">return</span> <span class="token string">''</span><span class="token punctuation">;</span><br />        <span class="token punctuation">}</span><span class="token punctuation">,</span><br />        <span class="token function-variable function">description</span><span class="token operator">:</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">siteContext</span><span class="token punctuation">)</span><span class="token punctuation">{</span><br />            <span class="token keyword">if</span> <span class="token punctuation">(</span>siteContext<span class="token operator">?.</span>timeline<span class="token punctuation">)</span><br />                <span class="token keyword">return</span> siteContext<span class="token punctuation">.</span>timeline<span class="token punctuation">.</span>description<br /><br />            <span class="token keyword">return</span> <span class="token string">''</span><span class="token punctuation">;</span><br />        <span class="token punctuation">}</span><span class="token punctuation">,</span><br />        <span class="token function-variable function">tags</span><span class="token operator">:</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">siteContext</span><span class="token punctuation">)</span><span class="token punctuation">{</span><br />            <span class="token keyword">if</span> <span class="token punctuation">(</span>siteContext<span class="token operator">?.</span>timeline<span class="token punctuation">)</span><br />                <span class="token keyword">return</span> siteContext<span class="token punctuation">.</span>timeline<span class="token punctuation">.</span>tags<br /><br />            <span class="token keyword">return</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span><br />        <span class="token punctuation">}</span><span class="token punctuation">,</span><br />        <span class="token function-variable function">categories</span><span class="token operator">:</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">siteContext</span><span class="token punctuation">)</span><span class="token punctuation">{</span><br />            <span class="token keyword">if</span> <span class="token punctuation">(</span>siteContext<span class="token operator">?.</span>timeline<span class="token punctuation">)</span><br />                <span class="token keyword">return</span> siteContext<span class="token punctuation">.</span>timeline<span class="token punctuation">.</span>categories<br /><br />            <span class="token keyword">return</span> <span class="token string">''</span><span class="token punctuation">;</span><br />        <span class="token punctuation">}</span><span class="token punctuation">,</span><br />        <span class="token function-variable function">filters</span><span class="token operator">:</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">siteContext</span><span class="token punctuation">)</span><span class="token punctuation">{</span><br />            <span class="token keyword">if</span> <span class="token punctuation">(</span>siteContext<span class="token operator">?.</span>timeline<span class="token punctuation">)</span><br />                <span class="token keyword">return</span> siteContext<span class="token punctuation">.</span>timeline<span class="token punctuation">.</span>filters<br /><br />            <span class="token keyword">return</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span><br />        <span class="token punctuation">}</span><span class="token punctuation">,</span><br />        <span class="token function-variable function">date</span><span class="token operator">:</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">siteContext</span><span class="token punctuation">)</span><span class="token punctuation">{</span><br />            <span class="token keyword">if</span> <span class="token punctuation">(</span>siteContext<span class="token operator">?.</span>timeline<span class="token punctuation">)</span><br />                <span class="token keyword">return</span> siteContext<span class="token punctuation">.</span>timeline<span class="token punctuation">.</span>date<br /><br />            <span class="token keyword">return</span> <span class="token string">"Last Modified"</span><span class="token punctuation">;</span><br />        <span class="token punctuation">}</span><span class="token punctuation">,</span><br />        <span class="token function-variable function">header</span><span class="token operator">:</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">siteContext</span><span class="token punctuation">)</span><span class="token punctuation">{</span><br />            <span class="token keyword">if</span> <span class="token punctuation">(</span>siteContext<span class="token operator">?.</span>timeline<span class="token punctuation">)</span><br />                <span class="token keyword">return</span> siteContext<span class="token punctuation">.</span>timeline<span class="token punctuation">.</span>header<br /><br />            <span class="token keyword">return</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span><br />        <span class="token punctuation">}</span><span class="token punctuation">,</span><br />        <span class="token function-variable function">color</span><span class="token operator">:</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">siteContext</span><span class="token punctuation">)</span><span class="token punctuation">{</span><br />            <span class="token keyword">if</span> <span class="token punctuation">(</span>siteContext<span class="token operator">?.</span>timeline<span class="token punctuation">)</span><br />                <span class="token keyword">return</span> siteContext<span class="token punctuation">.</span>timeline<span class="token punctuation">.</span>color<br /><br />            <span class="token keyword">return</span> <span class="token string">'grey'</span><span class="token punctuation">;</span><br />        <span class="token punctuation">}</span><span class="token punctuation">,</span><br />        <span class="token function-variable function">shortdate</span><span class="token operator">:</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">siteContext</span><span class="token punctuation">)</span><span class="token punctuation">{</span><br />            <span class="token keyword">if</span> <span class="token punctuation">(</span>siteContext<span class="token operator">?.</span>timeline<span class="token punctuation">)</span><br />                <span class="token keyword">return</span> siteContext<span class="token punctuation">.</span>timeline<span class="token punctuation">.</span>shortdate<br /><br />            <span class="token keyword">return</span> <span class="token boolean">false</span><span class="token punctuation">;</span><br />        <span class="token punctuation">}</span><span class="token punctuation">,</span><br />    <span class="token punctuation">}</span><br /><span class="token punctuation">}</span></code></pre>
<p id="code-skip-day-3-integrate-contexter-timeline-pages-metadata-2">Great! I also want the ability to support the <code>links</code> field for timeline objects, to give me the ability to set links on the timeline. That means passing more complex objects into the YAML head data. How do I do that? I tried passing in an actual object but that doesn't work.</p>
<p>It wasn't obvious to me, but apparently how you handle deeper YAML objects is by passing a blank indented hyphen and indenting the properties beneath that. If you want to pass an object into an object, this is how:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/context-timelines/day-3-integrate-contexter-timeline-pages-metadata/#code-skip-day-3-integrate-contexter-timeline-pages-metadata-1" id="skip-to-code-skip-day-3-integrate-contexter-timeline-pages-metadata-1" class="skip-link">Skip code block ▼</a></p>
<pre class="language-yaml"><code class="language-yaml"><span class="token key atrule">links</span><span class="token punctuation">:</span><br />  <span class="token punctuation">-</span><br />    <span class="token key atrule">href</span><span class="token punctuation">:</span> <span class="token string">"https://www.bostonglobe.com/2022/05/13/metro/new-omicron-variant-ba2121-has-taken-over-massachusetts-heres-what-you-need-know/"</span><span class="token punctuation">,</span><br />    <span class="token key atrule">linkText</span><span class="token punctuation">:</span> <span class="token string">"A new Omicron variant, BA.2.12.1, has taken over in Massachusetts. Here’s what you need to know."</span><span class="token punctuation">,</span><br />    <span class="token key atrule">extraText</span><span class="token punctuation">:</span> <span class="token string">"BA.2.12.1 has exploded"</span></code></pre>
<p id="code-skip-day-3-integrate-contexter-timeline-pages-metadata-1">Notably this structure needs to be all spaces, no tabs. Two spaces before the first hyphen and 4 before each of the properties.</p>
<p>I also want to get it working with my contexter plugin, so I'm going to set up some extra styles to get a start at integrating it and then get the layout type integrated.</p>
<p><code>git commit -am &quot;Timeline improvements plus contexter integration.&quot;</code></p>
]]></content:encoded>
	</item>
	
	<item>
		<title>Context Center Timelines - Day 2 - Layouts and Collections</title>
		<link>https://fightwithtools.dev/posts/projects/context-timelines/day-2-creating-collections-and-layouts/?source=rss</link>
		<pubDate>Sat, 14 May 2022 02:59:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/projects/context-timelines/day-2-creating-collections-and-layouts/</guid>
		<description>Setting up context-rich timeline collections and layouts</description>
		<content:encoded><![CDATA[<h2 id="project-scope-and-todos" tabindex="-1">Project Scope and ToDos</h2>
<ol>
<li>Create timeline pages where one can see the whole timeline of a particular event</li>
<li>Give timeline items type or category icons so that you can easily scan what is happening.</li>
<li>Allow the user to enter the timeline at any individually sharable link of an event and seamlessly scroll up and down</li>
</ol>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Deliver timelines as a plugin that can be extended by other Eleventy users</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Auto-create social-media-ready screenshots of a timeline item</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Integrate with Contexter to have context-full link cards in the timeline</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Leverage the Live Blog format of Schema dot org</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Allow each entry to be its own Markdown file</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Handle SASS instead of CSS</li>
</ul>
<h2 id="bringing-over-the-template-for-the-timeline" tabindex="-1">Bringing over the Template for the Timeline</h2>
<p>So I think it won't be so easy to directly port over the code, even if I transform the EJS to Nunjucks. What's worth doing is seeing if I can transform the data approach so it matches the different structure of content I'm trying to do.</p>
<p>I think I can use the Project structures I have in my devblog as a starting point.</p>
<p>I was really hoping that a plugin could come in and establish some template file, but <a href="https://github.com/11ty/eleventy/blob/e386ec5f70e08254284e76a41dcbc591762282c8/src/TemplateLayoutPathResolver.js#L79" target="_blank">it looks like that can't be done with a simple template alias</a>. Instead I'm going to have to set up some way to handle it as a path relative to the site's <code>_layouts</code> folder. That's pretty awkward. But I do think I can make it work, especially if I pass in the depth I'll have to traverse the file structure up.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/context-timelines/day-2-creating-collections-and-layouts/#code-skip-day-2-creating-collections-and-layouts-2" id="skip-to-code-skip-day-2-creating-collections-and-layouts-2" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript">	<span class="token keyword">const</span> dirs <span class="token operator">=</span> __dirname<span class="token punctuation">.</span><span class="token function">split</span><span class="token punctuation">(</span>process<span class="token punctuation">.</span><span class="token function">cwd</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token keyword">const</span> pluginLayoutPath <span class="token operator">=</span> path<span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span><br />		pluginConfig<span class="token punctuation">.</span>layoutFolderDepth<span class="token punctuation">,</span><br />		dirs<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br />		<span class="token string">"src"</span><span class="token punctuation">,</span><br />		<span class="token string">"layouts"</span><br />	<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p id="code-skip-day-2-creating-collections-and-layouts-2">Yeah, that is not the easiest, but it does look like it works. Definitely not as intended by Eleventy core, but hey, it works. This gets the template system to traverse up from _layouts in my core site by a <code>layoutFolderDepth</code> value of <code>../../</code>. It then travels into the plugin parent folder, the plugin, then--internal to the plugin--<code>src/layouts</code> where my layout folders are.</p>
<p>Once that file path is in place I can use layout aliases that lead to template files local to my plugin folder, like so:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/context-timelines/day-2-creating-collections-and-layouts/#code-skip-day-2-creating-collections-and-layouts-1" id="skip-to-code-skip-day-2-creating-collections-and-layouts-1" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript">	eleventyConfig<span class="token punctuation">.</span><span class="token function">addLayoutAlias</span><span class="token punctuation">(</span><br />		<span class="token string">"timeline"</span><span class="token punctuation">,</span><br />		path<span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span>pluginLayoutPath<span class="token punctuation">,</span> <span class="token string">"timeline.njk"</span><span class="token punctuation">)</span><br />	<span class="token punctuation">)</span><span class="token punctuation">;</span><br />	eleventyConfig<span class="token punctuation">.</span><span class="token function">addLayoutAlias</span><span class="token punctuation">(</span><br />		<span class="token string">"timeline-item"</span><span class="token punctuation">,</span><br />		path<span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span>pluginLayoutPath<span class="token punctuation">,</span> <span class="token string">"timeline-item.njk"</span><span class="token punctuation">)</span><br />	<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p id="code-skip-day-2-creating-collections-and-layouts-1">Nice, that looks good! Now I can just pass in my timelines collection and start building some pages!</p>
<p>Next up, getting those templates actually working.</p>
<p><code>git commit -am &quot;Setting up Context Timeline templates and collections&quot;</code></p>
]]></content:encoded>
	</item>
	
	<item>
		<title>Context Center Timelines - Day 1</title>
		<link>https://fightwithtools.dev/posts/projects/context-timelines/day-1-stepping-back-and-looking-at-what-I-want/?source=rss</link>
		<pubDate>Sat, 14 May 2022 02:59:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/projects/context-timelines/day-1-stepping-back-and-looking-at-what-I-want/</guid>
		<description>Setting up context-rich timelines</description>
		<content:encoded><![CDATA[<h2 id="project-scope-and-todos" tabindex="-1">Project Scope and ToDos</h2>
<ol>
<li>Create timeline pages where one can see the whole timeline of a particular event</li>
<li>Give timeline items type or category icons so that you can easily scan what is happening.</li>
<li>Allow the user to enter the timeline at any individually sharable link of an event and seamlessly scroll up and down</li>
</ol>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Deliver timelines as a plugin that can be extended by other Eleventy users</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Auto-create social-media-ready screenshots of a timeline item</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Integrate with Contexter to have context-full link cards in the timeline</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Leverage the Live Blog format of Schema dot org</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Allow each entry to be its own Markdown file</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Handle SASS instead of CSS</li>
</ul>
<h2 id="setting-up-a-timeline-plugin" tabindex="-1">Setting up a Timeline Plugin?</h2>
<p>Ok, so I really love the work that <a href="http://www.mollywhite.net/" target="_blank">Molly White</a> has put in to create timelines in their work. Molly has created a great starting point in <a href="https://github.com/molly/static-timeline-generator" target="_blank">an open-source 11ty-based timeline project</a> and then <a href="https://github.com/molly/web3-is-going-great" target="_blank">a much more advanced timeline for their coverage of &quot;web3&quot; that is also open-source</a>.</p>
<p>So, I decided to set up a version for myself. I want to build multiple timelines within my context-center site so I set up <a href="https://github.com/AramZS/context-center/tree/timeline" target="_blank">a branch to try and set up a way to do that</a>. My hope is that not only can I set it up for multiple timelines within my own site, but I can also set it up within a plugin that other people (and future sites of mine) can use easily. I haven't really seen templates packaged up this way so this feels like unexplored ground. I think it might be possible, but maybe not! I guess we'll find out.</p>
<p>So first I want to port over Molly's basic timeline work, this gives me a good starting point and lets me avoid the fact that I'm bad at design. I'll set up a timeline plugin and start moving it over. I don't want to deal with trying to do Sass builds inside the plugin so I'll also try to move her Sass work into standard CSS for now.</p>
<p>I've set up a basic plugin structure to start me off and contain the work.</p>
<p>I'll start with the variables.</p>
<p><code>git commit -am &quot;Set up first folder and start porting CSS&quot;</code></p>
]]></content:encoded>
	</item>
	
	<item>
		<title>Day 18: Ok, I used it a whole bunch. Now time to adjust.</title>
		<link>https://fightwithtools.dev/posts/projects/context-pages/day-18-adjusting-from-use/?source=rss</link>
		<pubDate>Mon, 02 May 2022 02:59:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/projects/context-pages/day-18-adjusting-from-use/</guid>
		<description>Better crawling, better tools for the static site generator.</description>
		<content:encoded><![CDATA[<h2 id="project-scope-and-todos" tabindex="-1">Project Scope and ToDos</h2>
<ol>
<li>Take a link and turn it into an oEmbed/Open Graph style share card</li>
<li>Take a link and archive it in the most reliable way</li>
<li>When the link is a tweet, display the tweet but also the whole tweet thread.</li>
<li>When the link is a tweet, archive the tweets, and display them if the live ones are not available.</li>
<li>Capture any embedded retweets in the thread. Capture their thread if one exists</li>
<li>Capture any links in the Tweet</li>
<li>Create the process as an abstract function that returns the data in a savable way</li>
</ol>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Archive links on <a href="http://archive.org/" target="_blank">Archive.org</a> and save the resulting archival links</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Create link IDs that can be used to cache related content</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Integrate it into the site to be able to make context pages here.</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Check if a link is still available at build time and rebuild the block with links to an archived link</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Use v1 Twitter API to get Gifs and videos</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Pull Twitter images into Eleventy archive.</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Add YouTube DL tool.</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Use <a href="https://github.com/oduwsdl/archivenow" target="_blank">https://github.com/oduwsdl/archivenow</a>?</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Improve handoff to <a href="http://archive.org/" target="_blank">Archive.org</a> with <a href="https://twitter.com/Chronotope/status/1517116475601043456" target="_blank">various other methods</a>.</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Contexter needs to read author objects out of Schema dot org JSON-LD blocks.</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Fall back to use Puppeteer</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Fall back to read the version on the Internet Archive</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Do something better when the same link is in the text more than once.</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Allow the user to override a link's metadata with a markdown file.</li>
</ul>
<h2 id="day-18" tabindex="-1">Day 18</h2>
<p>Ok, so I put this project through it's paces by using it over the last monthish. It's working surprisingly well, but I think there are a few issues. The first is that while the Facebook UA works most of the time, it doesn't always. So let's use the work I did in Backreads to try and up my chances of successfully getting a scrape using the standard means, even if I want to eventually drop a headless browser into this process.</p>
<p>I also want to set it up so that the static site generator does the actual build process instead of baking it into the JSON file. I think this process ends up being a little more compelex, but it will make creating updates easier and I think make the whole project more sustainable and easier to support.</p>
<h3 id="get-better-scraping-results" tabindex="-1">Get better scraping results</h3>
<p>Ok, so, when I was experimenting with <a href="https://github.com/AramZS/backreads/" target="_blank">Backreads</a> I found that the right User Agent really made a difference. So I'm going to bring over and clean up some of the logic I worked out there.</p>
<p>The first thing is to bring over a list of User Agents (or UAs) and give myself some tools to select which one to use. When working with Node Fetch before I found that particular URLs were more likely to respond with particular UAs. So I'll build a function to handle that selection process and store a few UAs that might be useful for scraping. I also want to have the option to exclude specific UAs when I've already tried them. Ok so:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/context-pages/day-18-adjusting-from-use/#code-skip-day-18-adjusting-from-use-2" id="skip-to-code-skip-day-18-adjusting-from-use-2" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> ua <span class="token operator">=</span><br />	<span class="token string">"facebookexternalhit/1.1 (+http://www.facebook.com/externalhit_uatext.php)"</span><span class="token punctuation">;</span><br /><br /><br /><span class="token keyword">const</span> <span class="token function-variable function">selectUserAgent</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">link<span class="token punctuation">,</span> shuffleExclude <span class="token operator">=</span> <span class="token boolean">false</span></span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />	<span class="token keyword">let</span> userAgent <span class="token operator">=</span> ua<span class="token punctuation">;</span><br />	<span class="token comment">// https://developers.whatismybrowser.com/useragents/explore/software_type_specific/?utm_source=whatismybrowsercom&amp;utm_medium=internal&amp;utm_campaign=breadcrumbs</span><br />	<span class="token comment">// https://user-agents.net/lookup</span><br />	<span class="token keyword">const</span> userAgents <span class="token operator">=</span> <span class="token punctuation">{</span><br />		<span class="token literal-property property">windows</span><span class="token operator">:</span><br />			<span class="token string">"Mozilla/5.0 (Windows NT 10.0; Win64; x64) "</span> <span class="token operator">+</span><br />			<span class="token string">"AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.149 "</span> <span class="token operator">+</span><br />			<span class="token string">"Safari/537.36"</span><span class="token punctuation">,</span><br />		<span class="token literal-property property">osx14</span><span class="token operator">:</span> <span class="token string">"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36 OPR/72.0.3815.400"</span><span class="token punctuation">,</span><br />		<span class="token literal-property property">firefox</span><span class="token operator">:</span><br />			<span class="token string">"Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:83.0) Gecko/20100101 Firefox/83.0"</span><span class="token punctuation">,</span><br />		<span class="token literal-property property">firefox99</span><span class="token operator">:</span><br />			<span class="token string">"Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:99.0) Gecko/20100101 Firefox/99.0"</span><span class="token punctuation">,</span><br />		<span class="token literal-property property">osx11</span><span class="token operator">:</span> <span class="token string">"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_2) AppleWebKit/601.3.9 (KHTML, like Gecko) Version/9.0.2 Safari/601.3.9"</span><span class="token punctuation">,</span><br />		<span class="token literal-property property">baidu_ua</span><span class="token operator">:</span> <span class="token string">"Baiduspider+(+http://www.baidu.com/search/spider.htm)"</span><span class="token punctuation">,</span><br />		<span class="token literal-property property">googlebot</span><span class="token operator">:</span> <span class="token string">"Googlebot/2.1 (+http://www.google.com/bot.html)"</span><span class="token punctuation">,</span><br />		<span class="token literal-property property">modernGooglebot</span><span class="token operator">:</span><br />			<span class="token string">"UCWEB/2.0 (compatible; Googlebot/2.1; +google.com/bot.html)"</span><span class="token punctuation">,</span><br />		<span class="token literal-property property">pythonRequests</span><span class="token operator">:</span> <span class="token string">"python-requests/2.23.0"</span><span class="token punctuation">,</span><br />		<span class="token literal-property property">facebookRequests</span><span class="token operator">:</span><br />			<span class="token string">"facebookexternalhit/1.1 (+http://www.facebook.com/externalhit_uatext.php)"</span><span class="token punctuation">,</span><br />		<span class="token literal-property property">lighthouse</span><span class="token operator">:</span><br />			<span class="token string">"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko; Google Page Speed Insights) Chrome/41.0.2272.118 Safari/537.36"</span><span class="token punctuation">,</span><br />		<span class="token literal-property property">osx15</span><span class="token operator">:</span> <span class="token string">"Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:77.0) Gecko/20100101 Firefox/77.0"</span><span class="token punctuation">,</span><br />		<span class="token literal-property property">linux</span><span class="token operator">:</span> <span class="token string">"Mozilla/5.0 (X11; Linux x86_64)"</span><span class="token punctuation">,</span><br />		<span class="token literal-property property">mobileBrave</span><span class="token operator">:</span><br />			<span class="token string">"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.38 Safari/537.36 Brave/75"</span><span class="token punctuation">,</span><br />		<span class="token literal-property property">feedReader</span><span class="token operator">:</span><br />			<span class="token string">"Feedspot/1.0 (+https://www.feedspot.com/fs/fetcher; like FeedFetcher-Google)"</span><span class="token punctuation">,</span><br />	<span class="token punctuation">}</span><span class="token punctuation">;</span><br />	<span class="token keyword">const</span> substackERx <span class="token operator">=</span> <span class="token function">RegExp</span><span class="token punctuation">(</span><span class="token string">"email.substack"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token keyword">const</span> substackMGRx <span class="token operator">=</span> <span class="token function">RegExp</span><span class="token punctuation">(</span><span class="token string">"mg2.substack"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token keyword">const</span> washPostRx <span class="token operator">=</span> <span class="token function">RegExp</span><span class="token punctuation">(</span><span class="token string">"s2.washingtonpost.com"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token keyword">const</span> washPostStandardRx <span class="token operator">=</span> <span class="token function">RegExp</span><span class="token punctuation">(</span><span class="token string">"washingtonpost.com"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token keyword">const</span> archiveOrg <span class="token operator">=</span> <span class="token function">RegExp</span><span class="token punctuation">(</span><span class="token string">"archive.org"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token keyword">const</span> bbergLink <span class="token operator">=</span> <span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">link\.mail\.bloombergbusiness\.com</span><span class="token regex-delimiter">/</span></span><span class="token punctuation">;</span><br />	<span class="token keyword">const</span> bberg <span class="token operator">=</span> <span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">bloomberg</span><span class="token regex-delimiter">/</span></span><span class="token punctuation">;</span><br />	<span class="token keyword">const</span> goLink <span class="token operator">=</span> <span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">r\.g-omedia\.com</span><span class="token regex-delimiter">/</span></span><span class="token punctuation">;</span><br />	<span class="token keyword">const</span> logicLink <span class="token operator">=</span> <span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">thelogic\.us12\.list-manage\.com</span><span class="token regex-delimiter">/</span></span><span class="token punctuation">;</span><br /><br />	<span class="token keyword">if</span> <span class="token punctuation">(</span>substackMGRx<span class="token punctuation">.</span><span class="token function">test</span><span class="token punctuation">(</span>link<span class="token punctuation">)</span> <span class="token operator">||</span> substackERx<span class="token punctuation">.</span><span class="token function">test</span><span class="token punctuation">(</span>link<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />		userAgent <span class="token operator">=</span> userAgents<span class="token punctuation">.</span>baidu_ua<span class="token punctuation">;</span><br />	<span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>washPostRx<span class="token punctuation">.</span><span class="token function">test</span><span class="token punctuation">(</span>link<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />		userAgent <span class="token operator">=</span> userAgents<span class="token punctuation">.</span>lighthouse<span class="token punctuation">;</span><br />	<span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>washPostStandardRx<span class="token punctuation">.</span><span class="token function">test</span><span class="token punctuation">(</span>link<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />		userAgent <span class="token operator">=</span> userAgents<span class="token punctuation">.</span>lighthouse<span class="token punctuation">;</span><br />	<span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>bbergLink<span class="token punctuation">.</span><span class="token function">test</span><span class="token punctuation">(</span>link<span class="token punctuation">)</span> <span class="token operator">||</span> goLink<span class="token punctuation">.</span><span class="token function">test</span><span class="token punctuation">(</span>link<span class="token punctuation">)</span> <span class="token operator">||</span> bberg<span class="token punctuation">.</span><span class="token function">test</span><span class="token punctuation">(</span>link<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />		userAgent <span class="token operator">=</span> userAgents<span class="token punctuation">.</span>osx11<span class="token punctuation">;</span><br />	<span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>logicLink<span class="token punctuation">.</span><span class="token function">test</span><span class="token punctuation">(</span>link<span class="token punctuation">)</span> <span class="token operator">||</span> archiveOrg<span class="token punctuation">.</span><span class="token function">test</span><span class="token punctuation">(</span>link<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />		userAgent <span class="token operator">=</span> userAgents<span class="token punctuation">.</span>firefox<span class="token punctuation">;</span><br />	<span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span><br />		<span class="token keyword">const</span> keys <span class="token operator">=</span> Object<span class="token punctuation">.</span><span class="token function">keys</span><span class="token punctuation">(</span>userAgents<span class="token punctuation">)</span><span class="token punctuation">;</span><br />		<span class="token keyword">if</span> <span class="token punctuation">(</span>shuffleExclude<span class="token punctuation">)</span> <span class="token punctuation">{</span><br />			<span class="token keyword">var</span> index <span class="token operator">=</span> keys<span class="token punctuation">.</span><span class="token function">indexOf</span><span class="token punctuation">(</span>shuffleExclude<span class="token punctuation">)</span><span class="token punctuation">;</span><br />			<span class="token keyword">if</span> <span class="token punctuation">(</span>index <span class="token operator">></span> <span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />				keys<span class="token punctuation">.</span><span class="token function">splice</span><span class="token punctuation">(</span>index<span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />			<span class="token punctuation">}</span><br />		<span class="token punctuation">}</span><br />		userAgent <span class="token operator">=</span> keys<span class="token punctuation">[</span>Math<span class="token punctuation">.</span><span class="token function">floor</span><span class="token punctuation">(</span>Math<span class="token punctuation">.</span><span class="token function">random</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">*</span> keys<span class="token punctuation">.</span>length<span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">;</span><br />	<span class="token punctuation">}</span><br />	<span class="token keyword">return</span> userAgent<span class="token punctuation">;</span><br /><span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
<p id="code-skip-day-18-adjusting-from-use-2">This structure should also allow me to add more UAs and more links that respond to them as I go forward and when the link isn't known to me I can just shuffle the User Agent list and pull a random UA from the set.</p>
<p>I also noticed an issue where a number of the URLs would hang on request for unclear reasons. I should set up a way to avoid that. Thankfully, this was <a href="https://github.com/AramZS/backreads/blob/main/lambdas/html-from-email/parsing-tools.js#L301" target="_blank">also something I developed</a> for the Backreads project.</p>
<p>I can set the timeout using the <a href="https://www.npmjs.com/package/abort-controller" target="_blank">AbortController</a> object.</p>
<p>Using this to set my fetch options with an abort signal should work and prevent future hanging of the process (hopefully!).</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/context-pages/day-18-adjusting-from-use/#code-skip-day-18-adjusting-from-use-1" id="skip-to-code-skip-day-18-adjusting-from-use-1" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> controller <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">AbortController</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token keyword">const</span> fetchTimeout <span class="token operator">=</span> <span class="token function">setTimeout</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />	console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">"Request timed out for"</span><span class="token punctuation">,</span> link<span class="token punctuation">,</span> userAgent<span class="token punctuation">)</span><span class="token punctuation">;</span><br />	controller<span class="token punctuation">.</span><span class="token function">abort</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token number">6000</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />finalFetchOptions<span class="token punctuation">.</span>signal <span class="token operator">=</span> controller<span class="token punctuation">.</span>signal<span class="token punctuation">;</span></code></pre>
<p id="code-skip-day-18-adjusting-from-use-1">With this in hand I can also set up a retry process.</p>
<p><code>git commit -m &quot;Setting up UA rotation + retry&quot;</code></p>
<p>Ok, I can incorporate a better header into the Archives request. There is <a href="https://github.com/MaxBittker/nyt-first-said/blob/master/parsers/archive_bounce.py#L17" target="_blank">an option to download via the web archive</a> which might be worth exploring later.</p>
<p><code>git commit -m &quot;Fix request UA setup, add archiver improvements&quot;</code></p>
<h3 id="embed-build-process" tabindex="-1">Embed Build Process</h3>
<p>Ok, so now we should set up functions that can be accessible to the extending program so it can build it's own link blocks. We can also set it up so that the required setup script can be created only once by the subject site.</p>
<p><a target="_blank" href="https://github.com/AramZS/contexter/commit/f9fd14e5caf5d252b7966d916044e1b871e46745" class="git-commit-link"><code>git commit -am &quot;Set up functions that can be extended for other systems to make the link block themselves&quot;</code></a></p>
<p>Ok. While I'm in here I want to avoid situations like Bloomberg where I keep getting back context-less robot blocking pages. Let's set up a check for titles like those that aren't properly giving me status codes.</p>
<p><a target="_blank" href="https://github.com/AramZS/contexter/commit/ba8c72c3b142da938b7d9d82f7c5ca59682a2b9f" class="git-commit-link"><code>git commit -am &quot;Check titles for 404-style responses that don't have the right status codes.&quot;</code></a></p>
<h3 id="unit-tests-now-twitter-embeds-later" tabindex="-1">Unit Tests Now, Twitter Embeds Later</h3>
<p>The other thing I want to do is have better Twitter embeds. That means good styles and not relying on the Twitter scripts, which are pretty awful to load.</p>
<p>But now that I've taken the time to get the unit tests working, that'll have to be for another night.</p>
<p><a target="_blank" href="https://github.com/AramZS/contexter/commit/c51ebaa0f2c90f5d41b13779b4e68e3f36058c72" class="git-commit-link"><code>git commit -am &quot;Getting unit tests back working&quot;</code></a></p>
]]></content:encoded>
	</item>
	
	<item>
		<title>Day 17: Digging deeper into Memento and Restructuring Async Operations</title>
		<link>https://fightwithtools.dev/posts/projects/context-pages/day-17/?source=rss</link>
		<pubDate>Mon, 07 Mar 2022 02:59:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/projects/context-pages/day-17/</guid>
		<description>Am I doing the Memento API right?</description>
		<content:encoded><![CDATA[<h2 id="project-scope-and-todos" tabindex="-1">Project Scope and ToDos</h2>
<ol>
<li>Take a link and turn it into an oEmbed/Open Graph style share card</li>
<li>Take a link and archive it in the most reliable way</li>
<li>When the link is a tweet, display the tweet but also the whole tweet thread.</li>
<li>When the link is a tweet, archive the tweets, and display them if the live ones are not available.</li>
<li>Capture any embedded retweets in the thread. Capture their thread if one exists</li>
<li>Capture any links in the Tweet</li>
<li>Create the process as an abstract function that returns the data in a savable way</li>
</ol>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Archive links on <a href="http://archive.org/" target="_blank">Archive.org</a> and save the resulting archival links</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Create link IDs that can be used to cache related content</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Integrate it into the site to be able to make context pages here.</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Check if a link is still available at build time and rebuild the block with links to an archived link</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Use v1 Twitter API to get Gifs and videos</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Pull Twitter images into Eleventy archive.</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Add YouTube DL tool.</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Use <a href="https://github.com/oduwsdl/archivenow" target="_blank">https://github.com/oduwsdl/archivenow</a>?</li>
</ul>
<h2 id="day-17" tabindex="-1">Day 17</h2>
<p>Ok, so I'm still pretty interested in looking at what I can do with static sites, WARCs and the Memento API. I see I may want to leverage <a href="https://stackoverflow.com/questions/14798589/github-pages-http-headers" target="_blank">mock headers</a>. I found <a href="http://web.archive.org/web/timemap/json/https://aramzs.github.io/fun/2020/11/09/spotify-asks-listeners-to-hack-its-algorithm.html" target="_blank">a sample timemap</a>.</p>
<p>That timemap looks like</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/context-pages/day-17/#code-skip-day-17-1" id="skip-to-code-skip-day-17-1" class="skip-link">Skip code block ▼</a></p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">[</span><br />  <span class="token punctuation">[</span><br />    <span class="token string">"urlkey"</span><span class="token punctuation">,</span><br />    <span class="token string">"timestamp"</span><span class="token punctuation">,</span><br />    <span class="token string">"original"</span><span class="token punctuation">,</span><br />    <span class="token string">"mimetype"</span><span class="token punctuation">,</span><br />    <span class="token string">"statuscode"</span><span class="token punctuation">,</span><br />    <span class="token string">"digest"</span><span class="token punctuation">,</span><br />    <span class="token string">"redirect"</span><span class="token punctuation">,</span><br />    <span class="token string">"robotflags"</span><span class="token punctuation">,</span><br />    <span class="token string">"length"</span><span class="token punctuation">,</span><br />    <span class="token string">"offset"</span><span class="token punctuation">,</span><br />    <span class="token string">"filename"</span><br />  <span class="token punctuation">]</span><span class="token punctuation">,</span><br />  <span class="token punctuation">[</span><br />    <span class="token string">"io,github,aramzs)/fun/2020/11/09/spotify-asks-listeners-to-hack-its-algorithm.html"</span><span class="token punctuation">,</span><br />    <span class="token string">"20201109180955"</span><span class="token punctuation">,</span><br />    <span class="token string">"http://aramzs.github.io/fun/2020/11/09/spotify-asks-listeners-to-hack-its-algorithm.html"</span><span class="token punctuation">,</span><br />    <span class="token string">"text/html"</span><span class="token punctuation">,</span><br />    <span class="token string">"200"</span><span class="token punctuation">,</span><br />    <span class="token string">"S33ZE7G6463ELSCNFYXIYHYXFGHK5HGO"</span><span class="token punctuation">,</span><br />    <span class="token string">"-"</span><span class="token punctuation">,</span><br />    <span class="token string">"-"</span><span class="token punctuation">,</span><br />    <span class="token string">"10524"</span><span class="token punctuation">,</span><br />    <span class="token string">"7139989390"</span><span class="token punctuation">,</span><br />    <span class="token string">"archiveteam_urls_20201109191316_1b954904/urls_20201109191316_1b954904.1604536932.megawarc.warc.zst"</span><br />  <span class="token punctuation">]</span><span class="token punctuation">,</span><br />  <span class="token punctuation">[</span><br />    <span class="token string">"io,github,aramzs)/fun/2020/11/09/spotify-asks-listeners-to-hack-its-algorithm.html"</span><span class="token punctuation">,</span><br />    <span class="token string">"20210308195542"</span><span class="token punctuation">,</span><br />    <span class="token string">"https://aramzs.github.io/fun/2020/11/09/spotify-asks-listeners-to-hack-its-algorithm.html"</span><span class="token punctuation">,</span><br />    <span class="token string">"text/html"</span><span class="token punctuation">,</span><br />    <span class="token string">"200"</span><span class="token punctuation">,</span><br />    <span class="token string">"S33ZE7G6463ELSCNFYXIYHYXFGHK5HGO"</span><span class="token punctuation">,</span><br />    <span class="token string">"-"</span><span class="token punctuation">,</span><br />    <span class="token string">"-"</span><span class="token punctuation">,</span><br />    <span class="token string">"10353"</span><span class="token punctuation">,</span><br />    <span class="token string">"6333153645"</span><span class="token punctuation">,</span><br />    <span class="token string">"archiveteam_urls_20210309153400_0533dba8/urls_20210309153400_0533dba8.1606352862.megawarc.warc.zst"</span><br />  <span class="token punctuation">]</span><span class="token punctuation">,</span><br />  <span class="token punctuation">[</span><br />    <span class="token string">"io,github,aramzs)/fun/2020/11/09/spotify-asks-listeners-to-hack-its-algorithm.html"</span><span class="token punctuation">,</span><br />    <span class="token string">"20210414035818"</span><span class="token punctuation">,</span><br />    <span class="token string">"http://aramzs.github.io/fun/2020/11/09/spotify-asks-listeners-to-hack-its-algorithm.html"</span><span class="token punctuation">,</span><br />    <span class="token string">"text/html"</span><span class="token punctuation">,</span><br />    <span class="token string">"200"</span><span class="token punctuation">,</span><br />    <span class="token string">"S33ZE7G6463ELSCNFYXIYHYXFGHK5HGO"</span><span class="token punctuation">,</span><br />    <span class="token string">"-"</span><span class="token punctuation">,</span><br />    <span class="token string">"-"</span><span class="token punctuation">,</span><br />    <span class="token string">"11973"</span><span class="token punctuation">,</span><br />    <span class="token string">"8278303"</span><span class="token punctuation">,</span><br />    <span class="token string">"CC-MAIN-2021-17-1618038076819.36-0025/CC-MAIN-20210414034544-20210414064544-00514.warc.gz"</span><br />  <span class="token punctuation">]</span><span class="token punctuation">,</span><br />  <span class="token punctuation">[</span><br />    <span class="token string">"io,github,aramzs)/fun/2020/11/09/spotify-asks-listeners-to-hack-its-algorithm.html"</span><span class="token punctuation">,</span><br />    <span class="token string">"20220116021654"</span><span class="token punctuation">,</span><br />    <span class="token string">"https://aramzs.github.io/fun/2020/11/09/spotify-asks-listeners-to-hack-its-algorithm.html"</span><span class="token punctuation">,</span><br />    <span class="token string">"text/html"</span><span class="token punctuation">,</span><br />    <span class="token string">"200"</span><span class="token punctuation">,</span><br />    <span class="token string">"BA22HK45SJSQXS2I5CQUCPDKQJRKFWY4"</span><span class="token punctuation">,</span><br />    <span class="token string">"-"</span><span class="token punctuation">,</span><br />    <span class="token string">"-"</span><span class="token punctuation">,</span><br />    <span class="token string">"12283"</span><span class="token punctuation">,</span><br />    <span class="token string">"579559352"</span><span class="token punctuation">,</span><br />    <span class="token string">"spn2-20220116023030/spn2-20220116004556-wwwb-spn19.us.archive.org-8002.warc.gz"</span><br />  <span class="token punctuation">]</span><span class="token punctuation">,</span><br />  <span class="token punctuation">[</span><br />    <span class="token string">"io,github,aramzs)/fun/2020/11/09/spotify-asks-listeners-to-hack-its-algorithm.html"</span><span class="token punctuation">,</span><br />    <span class="token string">"20220206030455"</span><span class="token punctuation">,</span><br />    <span class="token string">"https://aramzs.github.io/fun/2020/11/09/spotify-asks-listeners-to-hack-its-algorithm.html"</span><span class="token punctuation">,</span><br />    <span class="token string">"warc/revisit"</span><span class="token punctuation">,</span><br />    <span class="token string">"-"</span><span class="token punctuation">,</span><br />    <span class="token string">"BA22HK45SJSQXS2I5CQUCPDKQJRKFWY4"</span><span class="token punctuation">,</span><br />    <span class="token string">"-"</span><span class="token punctuation">,</span><br />    <span class="token string">"-"</span><span class="token punctuation">,</span><br />    <span class="token string">"916"</span><span class="token punctuation">,</span><br />    <span class="token string">"568112967"</span><span class="token punctuation">,</span><br />    <span class="token string">"spn2-20220206032300/spn2-20220206024053-wwwb-spn24.us.archive.org-8000.warc.gz"</span><br />  <span class="token punctuation">]</span><span class="token punctuation">,</span><br />  <span class="token punctuation">[</span><br />    <span class="token string">"io,github,aramzs)/fun/2020/11/09/spotify-asks-listeners-to-hack-its-algorithm.html"</span><span class="token punctuation">,</span><br />    <span class="token string">"20220206185806"</span><span class="token punctuation">,</span><br />    <span class="token string">"https://aramzs.github.io/fun/2020/11/09/spotify-asks-listeners-to-hack-its-algorithm.html"</span><span class="token punctuation">,</span><br />    <span class="token string">"warc/revisit"</span><span class="token punctuation">,</span><br />    <span class="token string">"-"</span><span class="token punctuation">,</span><br />    <span class="token string">"BA22HK45SJSQXS2I5CQUCPDKQJRKFWY4"</span><span class="token punctuation">,</span><br />    <span class="token string">"-"</span><span class="token punctuation">,</span><br />    <span class="token string">"-"</span><span class="token punctuation">,</span><br />    <span class="token string">"921"</span><span class="token punctuation">,</span><br />    <span class="token string">"812868693"</span><span class="token punctuation">,</span><br />    <span class="token string">"spn2-20220206190643/spn2-20220206182209-wwwb-spn24.us.archive.org-8001.warc.gz"</span><br />  <span class="token punctuation">]</span><span class="token punctuation">,</span><br />  <span class="token punctuation">[</span><br />    <span class="token string">"io,github,aramzs)/fun/2020/11/09/spotify-asks-listeners-to-hack-its-algorithm.html"</span><span class="token punctuation">,</span><br />    <span class="token string">"20220206204948"</span><span class="token punctuation">,</span><br />    <span class="token string">"https://aramzs.github.io/fun/2020/11/09/spotify-asks-listeners-to-hack-its-algorithm.html"</span><span class="token punctuation">,</span><br />    <span class="token string">"warc/revisit"</span><span class="token punctuation">,</span><br />    <span class="token string">"-"</span><span class="token punctuation">,</span><br />    <span class="token string">"BA22HK45SJSQXS2I5CQUCPDKQJRKFWY4"</span><span class="token punctuation">,</span><br />    <span class="token string">"-"</span><span class="token punctuation">,</span><br />    <span class="token string">"-"</span><span class="token punctuation">,</span><br />    <span class="token string">"912"</span><span class="token punctuation">,</span><br />    <span class="token string">"52062476"</span><span class="token punctuation">,</span><br />    <span class="token string">"spn2-20220206214458/spn2-20220206204436-wwwb-spn17.us.archive.org-8002.warc.gz"</span><br />  <span class="token punctuation">]</span><span class="token punctuation">,</span><br />  <span class="token punctuation">[</span><br />    <span class="token string">"io,github,aramzs)/fun/2020/11/09/spotify-asks-listeners-to-hack-its-algorithm.html"</span><span class="token punctuation">,</span><br />    <span class="token string">"20220207004047"</span><span class="token punctuation">,</span><br />    <span class="token string">"https://aramzs.github.io/fun/2020/11/09/spotify-asks-listeners-to-hack-its-algorithm.html"</span><span class="token punctuation">,</span><br />    <span class="token string">"warc/revisit"</span><span class="token punctuation">,</span><br />    <span class="token string">"-"</span><span class="token punctuation">,</span><br />    <span class="token string">"BA22HK45SJSQXS2I5CQUCPDKQJRKFWY4"</span><span class="token punctuation">,</span><br />    <span class="token string">"-"</span><span class="token punctuation">,</span><br />    <span class="token string">"-"</span><span class="token punctuation">,</span><br />    <span class="token string">"918"</span><span class="token punctuation">,</span><br />    <span class="token string">"166550557"</span><span class="token punctuation">,</span><br />    <span class="token string">"spn2-20220207012349/spn2-20220207003218-wwwb-spn17.us.archive.org-8001.warc.gz"</span><br />  <span class="token punctuation">]</span><span class="token punctuation">,</span><br />  <span class="token punctuation">[</span><br />    <span class="token string">"io,github,aramzs)/fun/2020/11/09/spotify-asks-listeners-to-hack-its-algorithm.html"</span><span class="token punctuation">,</span><br />    <span class="token string">"20220212181146"</span><span class="token punctuation">,</span><br />    <span class="token string">"https://aramzs.github.io/fun/2020/11/09/spotify-asks-listeners-to-hack-its-algorithm.html"</span><span class="token punctuation">,</span><br />    <span class="token string">"warc/revisit"</span><span class="token punctuation">,</span><br />    <span class="token string">"-"</span><span class="token punctuation">,</span><br />    <span class="token string">"BA22HK45SJSQXS2I5CQUCPDKQJRKFWY4"</span><span class="token punctuation">,</span><br />    <span class="token string">"-"</span><span class="token punctuation">,</span><br />    <span class="token string">"-"</span><span class="token punctuation">,</span><br />    <span class="token string">"919"</span><span class="token punctuation">,</span><br />    <span class="token string">"805489884"</span><span class="token punctuation">,</span><br />    <span class="token string">"spn2-20220212181059/spn2-20220212172701-wwwb-spn15.us.archive.org-8002.warc.gz"</span><br />  <span class="token punctuation">]</span><span class="token punctuation">,</span><br />  <span class="token punctuation">[</span><br />    <span class="token string">"io,github,aramzs)/fun/2020/11/09/spotify-asks-listeners-to-hack-its-algorithm.html"</span><span class="token punctuation">,</span><br />    <span class="token string">"20220218011756"</span><span class="token punctuation">,</span><br />    <span class="token string">"https://aramzs.github.io/fun/2020/11/09/spotify-asks-listeners-to-hack-its-algorithm.html"</span><span class="token punctuation">,</span><br />    <span class="token string">"warc/revisit"</span><span class="token punctuation">,</span><br />    <span class="token string">"-"</span><span class="token punctuation">,</span><br />    <span class="token string">"BA22HK45SJSQXS2I5CQUCPDKQJRKFWY4"</span><span class="token punctuation">,</span><br />    <span class="token string">"-"</span><span class="token punctuation">,</span><br />    <span class="token string">"-"</span><span class="token punctuation">,</span><br />    <span class="token string">"920"</span><span class="token punctuation">,</span><br />    <span class="token string">"364865488"</span><span class="token punctuation">,</span><br />    <span class="token string">"spn2-20220218015755/spn2-20220218004035-wwwb-spn23.us.archive.org-8000.warc.gz"</span><br />  <span class="token punctuation">]</span><span class="token punctuation">,</span><br />  <span class="token punctuation">[</span><br />    <span class="token string">"io,github,aramzs)/fun/2020/11/09/spotify-asks-listeners-to-hack-its-algorithm.html"</span><span class="token punctuation">,</span><br />    <span class="token string">"20220221162143"</span><span class="token punctuation">,</span><br />    <span class="token string">"https://aramzs.github.io/fun/2020/11/09/spotify-asks-listeners-to-hack-its-algorithm.html"</span><span class="token punctuation">,</span><br />    <span class="token string">"warc/revisit"</span><span class="token punctuation">,</span><br />    <span class="token string">"-"</span><span class="token punctuation">,</span><br />    <span class="token string">"BA22HK45SJSQXS2I5CQUCPDKQJRKFWY4"</span><span class="token punctuation">,</span><br />    <span class="token string">"-"</span><span class="token punctuation">,</span><br />    <span class="token string">"-"</span><span class="token punctuation">,</span><br />    <span class="token string">"912"</span><span class="token punctuation">,</span><br />    <span class="token string">"116301727"</span><span class="token punctuation">,</span><br />    <span class="token string">"spn2-20220221163700/spn2-20220221161222-wwwb-spn07.us.archive.org-8001.warc.gz"</span><br />  <span class="token punctuation">]</span><br /><span class="token punctuation">]</span></code></pre>
<p id="code-skip-day-17-1">I'm not sure I'm any more interested in having multiple dates, but it is notable that this includes multiple formats. I think we need to figure out some better way to handle building these files, especially if I also want to generate WARCs or save more images locally.</p>
<p>Looking at the code I have now there's a lot of repetition and overlap and I'm wondering if I need a larger restructure to really support any complex operation. Yeah. Yeah I do.</p>
<p>Also, I'm still hoping for a way to use GitHub Actions to handle the archive process instead of running things locally.</p>
<p>Let's abstract some stuff into functions and see if we can use Promises differently here.</p>
<p>Also, I have a bunch of transformations being made to the incoming cache object from the contexter plugin, but in retrospect, I don't think that's the right approach. It will make it a lot harder to patch. These modifications should instead be happening when the data is added to the collection, if possible. Though there are some restrictions for the in-moment replacement process I guess. I'm not sure what is best to move actually now that I think about it. Let's try just getting the new async process working.</p>
<p>Hmm I'm not sure I can. Having to not have async in the compiler is really quite a problem.</p>
<p>Ok, well, I noticed that the local images for cards were not getting passed through and I attempted to get Twitter images working, but they really don't in the way I approached it.</p>
<p>That said, I think my actual Context objects are solid now? I think that the actual Contexter library (not the Eleventy plugin) is solid enough to push out to the NPM library, even if it isn't really out of beta. Let's do that now so that I can merge this working branch into my production blog.</p>
<p>Hmm... looks like there is already a <code>contexter</code> library on NPM so I'll name it something else. We'll be even more specific and call it <code>link-contexter</code>.</p>
<p>Ok, <a href="https://www.npmjs.com/package/link-contexter" target="_blank">that is set up</a>!</p>
<p>I'm now able to merge this branch of my blog into production!</p>
]]></content:encoded>
	</item>
	
	<item>
		<title>Day 16: Embeds and Archive Pages</title>
		<link>https://fightwithtools.dev/posts/projects/context-pages/day-16/?source=rss</link>
		<pubDate>Tue, 22 Feb 2022 02:59:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/projects/context-pages/day-16/</guid>
		<description>I want to get the data set up in an HTML block a user can style</description>
		<content:encoded><![CDATA[<h2 id="project-scope-and-todos" tabindex="-1">Project Scope and ToDos</h2>
<ol>
<li>Take a link and turn it into an oEmbed/Open Graph style share card</li>
<li>Take a link and archive it in the most reliable way</li>
<li>When the link is a tweet, display the tweet but also the whole tweet thread.</li>
<li>When the link is a tweet, archive the tweets, and display them if the live ones are not available.</li>
<li>Capture any embedded retweets in the thread. Capture their thread if one exists</li>
<li>Capture any links in the Tweet</li>
<li>Create the process as an abstract function that returns the data in a savable way</li>
</ol>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Archive links on <a href="http://archive.org/" target="_blank">Archive.org</a> and save the resulting archival links</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Create link IDs that can be used to cache related content</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Integrate it into the site to be able to make context pages here.</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Check if a link is still available at build time and rebuild the block with links to an archived link</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Use v1 Twitter API to get Gifs and videos</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Pull Twitter images into Eleventy archive.</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Add YouTube DL tool.</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Use <a href="https://github.com/oduwsdl/archivenow" target="_blank">https://github.com/oduwsdl/archivenow</a>?</li>
</ul>
<h2 id="day-16" tabindex="-1">Day 16</h2>
<p>Ok, so I wasn't actively logging the last two days of work because a lot of it was random fiddles that I didn't think would take very long and a bunch of playing around with styling. But it all turned out to take a lot longer than I thought, and ended up more complicated.</p>
<p>First I decided to make a more complex take on the embed HTML based on some stuff I learned from work. Specifically, I decided I wanted to more strongly encapsulate the styles based on <a href="https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_custom_elements" target="_blank">custom</a> <a href="https://developers.google.com/web/fundamentals/web-components/customelements" target="_blank">HTML elements</a> and the <a href="https://developers.google.com/web/fundamentals/web-components/shadowdom" target="_blank">shadow</a> <a href="https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_shadow_DOM" target="_blank">DOM</a>.</p>
<p>I played around a bunch in Glitch with HTML and styles to form the embed design I want for non-oEmbed cards.</p>
<p>I've ended up with the HTML (here filled with sample data):</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/context-pages/day-16/#code-skip-day-16-5" id="skip-to-code-skip-day-16-5" class="skip-link">Skip code block ▼</a></p>
<pre class="language-html"><code class="language-html">    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>contexter-box</span><br />      <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>contexter-box<span class="token punctuation">"</span></span><br />      <span class="token attr-name">itemscope</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span><span class="token punctuation">"</span></span><br />      <span class="token attr-name">itemtype</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>https://schema.org/CreativeWork<span class="token punctuation">"</span></span><br />      <span class="token punctuation">></span></span><br />      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>contexter-thumbnail</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>contexter-box__thumbnail<span class="token punctuation">"</span></span> <span class="token attr-name">slot</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>thumbnail<span class="token punctuation">"</span></span><br />        <span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>img</span><br />          <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>https://github.com/AramZS/aramzs.github.io/blob/master/_includes/beamdown.gif?raw=true<span class="token punctuation">"</span></span><br />          <span class="token attr-name">alt</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span><span class="token punctuation">"</span></span><br />          <span class="token attr-name">itemprop</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>image<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>contexter-thumbnail</span><br />      <span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>contexter-box-head</span><br />        <span class="token attr-name">slot</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>header<span class="token punctuation">"</span></span><br />        <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>contexter-box__head<span class="token punctuation">"</span></span><br />        <span class="token attr-name">itemprop</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>headline<span class="token punctuation">"</span></span><br />        <span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>contexter-box-head</span><br />          <span class="token attr-name">slot</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>header<span class="token punctuation">"</span></span><br />          <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>contexter-box__head<span class="token punctuation">"</span></span><br />          <span class="token attr-name">itemprop</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>headline<span class="token punctuation">"</span></span><br />          <span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>a</span><br />            <span class="token attr-name">is</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>contexter-link<span class="token punctuation">"</span></span><br />            <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>http://aramzs.github.io/jekyll/schema-dot-org/2018/04/27/how-to-make-your-jekyll-site-structured.html<span class="token punctuation">"</span></span><br />            <span class="token attr-name">itemprop</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>url<span class="token punctuation">"</span></span><br />            <span class="token attr-name">target</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>_blank<span class="token punctuation">"</span></span><br />            <span class="token punctuation">></span></span>How to give your Jekyll Site Structured Data for Search with<br />            JSON-LD<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>a</span><br />          <span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>contexter-box-head</span><br />        <span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>contexter-box-head</span><br />      <span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>contexter-byline</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>contexter-box__byline<span class="token punctuation">"</span></span> <span class="token attr-name">slot</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>author<span class="token punctuation">"</span></span><br />        <span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>p-name byline<span class="token punctuation">"</span></span> <span class="token attr-name">rel</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>author<span class="token punctuation">"</span></span> <span class="token attr-name">itemprop</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>author<span class="token punctuation">"</span></span><br />          <span class="token punctuation">></span></span>Aram Zucker-Scharff<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><br />        <span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>contexter-byline</span><br />      <span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>time</span><br />        <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>dt-published published<span class="token punctuation">"</span></span><br />        <span class="token attr-name">slot</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>time<span class="token punctuation">"</span></span><br />        <span class="token attr-name">itemprop</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>datePublished<span class="token punctuation">"</span></span><br />        <span class="token attr-name">datetime</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>2018-04-27T22:00:51.000Z<span class="token punctuation">"</span></span><br />        <span class="token punctuation">></span></span>3/27/2018<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>time</span><br />      <span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>contexter-summary</span><br />        <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>p-summary entry-summary<span class="token punctuation">"</span></span><br />        <span class="token attr-name">itemprop</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>abstract<span class="token punctuation">"</span></span><br />        <span class="token attr-name">slot</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>summary<span class="token punctuation">"</span></span><br />        <span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">></span></span><br />          Let's make your Jekyll site work with Schema.org structured data and<br />          JSON-LD.<br />        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>contexter-summary</span><br />      <span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>contexter-keywordset</span><br />        <span class="token attr-name">itemprop</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>keywords<span class="token punctuation">"</span></span><br />        <span class="token attr-name">slot</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>keywords<span class="token punctuation">"</span></span><br />        <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>contexter-box__keywordset<span class="token punctuation">"</span></span><br />        <span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">rel</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>category tag<span class="token punctuation">"</span></span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>p-category<span class="token punctuation">"</span></span> <span class="token attr-name">itemprop</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>keywords<span class="token punctuation">"</span></span><br />          <span class="token punctuation">></span></span>jekyll<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><br />        <span class="token punctuation">></span></span>,<br />        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">rel</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>category tag<span class="token punctuation">"</span></span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>p-category<span class="token punctuation">"</span></span> <span class="token attr-name">itemprop</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>keywords<span class="token punctuation">"</span></span><br />          <span class="token punctuation">></span></span>schema-dot-org<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><br />        <span class="token punctuation">></span></span>,<br />        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">rel</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>category tag<span class="token punctuation">"</span></span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>p-category<span class="token punctuation">"</span></span> <span class="token attr-name">itemprop</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>keywords<span class="token punctuation">"</span></span><br />          <span class="token punctuation">></span></span>Code<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><br />        <span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>contexter-keywordset</span><br />      <span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>a</span><br />          <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>https://web.archive.org/web/20220219224214/https://aramzs.github.io/jekyll/schema-dot-org/2018/04/27/how-to-make-your-jekyll-site-structured.html<span class="token punctuation">"</span></span><br />          <span class="token attr-name">is</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>contexter-link<span class="token punctuation">"</span></span><br />          <span class="token attr-name">target</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>_blank<span class="token punctuation">"</span></span><br />          <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>read-link archive-link<span class="token punctuation">"</span></span><br />          <span class="token attr-name">itemprop</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>archivedAt<span class="token punctuation">"</span></span><br />             <span class="token attr-name">slot</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>archive-link<span class="token punctuation">"</span></span><br />          <span class="token punctuation">></span></span>Archived<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>a</span><br />        <span class="token punctuation">></span></span><span class="token entity named-entity" title="&nbsp;">&amp;nbsp;</span>|<span class="token entity named-entity" title="&nbsp;">&amp;nbsp;</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>a</span><br />          <span class="token attr-name">is</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>contexter-link<span class="token punctuation">"</span></span><br />          <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>http://aramzs.github.io/jekyll/schema-dot-org/2018/04/27/how-to-make-your-jekyll-site-structured.html<span class="token punctuation">"</span></span><br />          <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>read-link main-link<span class="token punctuation">"</span></span><br />          <span class="token attr-name">itemprop</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>sameAs<span class="token punctuation">"</span></span><br />          <span class="token attr-name">target</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>_blank<span class="token punctuation">"</span></span><br />            <span class="token attr-name">slot</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>read-link<span class="token punctuation">"</span></span><br />          <span class="token punctuation">></span></span>Read<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>a</span><br />        <span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>contexter-box</span><br />    <span class="token punctuation">></span></span></code></pre>
<p id="code-skip-day-16-5">And to make that work, I'll have to insert the following Javascript to make the functionality run with custom HTML elements and add the shadow DOM:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/context-pages/day-16/#code-skip-day-16-4" id="skip-to-code-skip-day-16-4" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript">		window<span class="token punctuation">.</span>contexterSetup <span class="token operator">=</span> window<span class="token punctuation">.</span>contexterSetup <span class="token operator">?</span> window<span class="token punctuation">.</span><span class="token function-variable function">contexterSetup</span> <span class="token operator">:</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />			window<span class="token punctuation">.</span>contexterSetupComplete <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">;</span><br />		<span class="token keyword">class</span> <span class="token class-name">ContexterLink</span> <span class="token keyword">extends</span> <span class="token class-name">HTMLAnchorElement</span> <span class="token punctuation">{</span><br />		<span class="token function">constructor</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />			<span class="token comment">// Always call super first in constructor</span><br />			<span class="token keyword">super</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br />			<span class="token comment">// Element functionality written in here</span><br />		<span class="token punctuation">}</span><br />		<span class="token function">connectedCallback</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />			<span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">setAttribute</span><span class="token punctuation">(</span><span class="token string">"target"</span><span class="token punctuation">,</span> <span class="token string">"_blank"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />		<span class="token punctuation">}</span><br />		<span class="token punctuation">}</span><br />		<span class="token comment">// https://stackoverflow.com/questions/70716734/custom-web-component-that-acts-like-a-link-anchor-tag</span><br />		customElements<span class="token punctuation">.</span><span class="token function">define</span><span class="token punctuation">(</span><span class="token string">"contexter-link"</span><span class="token punctuation">,</span> ContexterLink<span class="token punctuation">,</span> <span class="token punctuation">{</span><br />		<span class="token keyword">extends</span><span class="token operator">:</span> <span class="token string">"a"</span><span class="token punctuation">,</span><br />		<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />		customElements<span class="token punctuation">.</span><span class="token function">define</span><span class="token punctuation">(</span><br />		<span class="token string">"contexter-inner"</span><span class="token punctuation">,</span><br />		<span class="token keyword">class</span> <span class="token class-name">extends</span> HTMLElement <span class="token punctuation">{</span><br />			<span class="token function">constructor</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />			<span class="token comment">// Always call super first in constructor</span><br />			<span class="token keyword">super</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />			<span class="token comment">// Element functionality written in here</span><br />			<span class="token punctuation">}</span><br />			<span class="token function">attributeChangedCallback</span><span class="token punctuation">(</span><span class="token parameter">name<span class="token punctuation">,</span> oldValue<span class="token punctuation">,</span> newValue</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /><br />			<span class="token punctuation">}</span><br />			<span class="token function">connectedCallback</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />			<span class="token keyword">this</span><span class="token punctuation">.</span>className <span class="token operator">=</span> <span class="token string">"contexter-box__inner"</span><span class="token punctuation">;</span><br />			<span class="token punctuation">}</span><br />		<span class="token punctuation">}</span><br />		<span class="token punctuation">)</span><span class="token punctuation">;</span><br />		customElements<span class="token punctuation">.</span><span class="token function">define</span><span class="token punctuation">(</span><br />		<span class="token string">"contexter-thumbnail"</span><span class="token punctuation">,</span><br />		<span class="token keyword">class</span> <span class="token class-name">extends</span> HTMLElement <span class="token punctuation">{</span><br />			<span class="token function">constructor</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />			<span class="token comment">// Always call super first in constructor</span><br />			<span class="token keyword">super</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />			<span class="token comment">// Element functionality written in here</span><br />			<span class="token punctuation">}</span><br />			<span class="token function">attributeChangedCallback</span><span class="token punctuation">(</span><span class="token parameter">name<span class="token punctuation">,</span> oldValue<span class="token punctuation">,</span> newValue</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /><br />			<span class="token punctuation">}</span><br />			<span class="token function">connectedCallback</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />			<span class="token keyword">this</span><span class="token punctuation">.</span>className <span class="token operator">=</span> <span class="token string">"contexter-box__thumbnail"</span><span class="token punctuation">;</span><br />			<span class="token punctuation">}</span><br />		<span class="token punctuation">}</span><br />		<span class="token punctuation">)</span><span class="token punctuation">;</span><br />		customElements<span class="token punctuation">.</span><span class="token function">define</span><span class="token punctuation">(</span><br />		<span class="token string">"contexter-byline"</span><span class="token punctuation">,</span><br />		<span class="token keyword">class</span> <span class="token class-name">extends</span> HTMLElement <span class="token punctuation">{</span><br />			<span class="token function">constructor</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />			<span class="token comment">// Always call super first in constructor</span><br />			<span class="token keyword">super</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />			<span class="token comment">// Element functionality written in here</span><br />			<span class="token punctuation">}</span><br />			<span class="token function">attributeChangedCallback</span><span class="token punctuation">(</span><span class="token parameter">name<span class="token punctuation">,</span> oldValue<span class="token punctuation">,</span> newValue</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /><br />			<span class="token punctuation">}</span><br />			<span class="token function">connectedCallback</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />			<span class="token keyword">this</span><span class="token punctuation">.</span>className <span class="token operator">=</span> <span class="token string">"contexter-box__byline"</span><span class="token punctuation">;</span><br />			<span class="token punctuation">}</span><br />		<span class="token punctuation">}</span><br />		<span class="token punctuation">)</span><span class="token punctuation">;</span><br />		customElements<span class="token punctuation">.</span><span class="token function">define</span><span class="token punctuation">(</span><br />		<span class="token string">"contexter-keywordset"</span><span class="token punctuation">,</span><br />		<span class="token keyword">class</span> <span class="token class-name">extends</span> HTMLElement <span class="token punctuation">{</span><br />			<span class="token function">constructor</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />			<span class="token comment">// Always call super first in constructor</span><br />			<span class="token keyword">super</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />			<span class="token comment">// Element functionality written in here</span><br />			<span class="token punctuation">}</span><br />			<span class="token function">attributeChangedCallback</span><span class="token punctuation">(</span><span class="token parameter">name<span class="token punctuation">,</span> oldValue<span class="token punctuation">,</span> newValue</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /><br />			<span class="token punctuation">}</span><br />			<span class="token function">connectedCallback</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />			<span class="token keyword">this</span><span class="token punctuation">.</span>className <span class="token operator">=</span> <span class="token string">"contexter-box__keywordset"</span><span class="token punctuation">;</span><br />			<span class="token punctuation">}</span><br />		<span class="token punctuation">}</span><br />		<span class="token punctuation">)</span><span class="token punctuation">;</span><br />		customElements<span class="token punctuation">.</span><span class="token function">define</span><span class="token punctuation">(</span><br />		<span class="token string">"contexter-linkset"</span><span class="token punctuation">,</span><br />		<span class="token keyword">class</span> <span class="token class-name">extends</span> HTMLElement <span class="token punctuation">{</span><br />			<span class="token function">constructor</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />			<span class="token comment">// Always call super first in constructor</span><br />			<span class="token keyword">super</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />			<span class="token comment">// Element functionality written in here</span><br />			<span class="token punctuation">}</span><br />			<span class="token function">attributeChangedCallback</span><span class="token punctuation">(</span><span class="token parameter">name<span class="token punctuation">,</span> oldValue<span class="token punctuation">,</span> newValue</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /><br />			<span class="token punctuation">}</span><br />			<span class="token function">connectedCallback</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />			<span class="token keyword">this</span><span class="token punctuation">.</span>className <span class="token operator">=</span> <span class="token string">"contexter-box__linkset"</span><span class="token punctuation">;</span><br />			<span class="token punctuation">}</span><br />		<span class="token punctuation">}</span><br />		<span class="token punctuation">)</span><span class="token punctuation">;</span><br />		customElements<span class="token punctuation">.</span><span class="token function">define</span><span class="token punctuation">(</span><br />		<span class="token string">"contexter-meta"</span><span class="token punctuation">,</span><br />		<span class="token keyword">class</span> <span class="token class-name">extends</span> HTMLElement <span class="token punctuation">{</span><br />			<span class="token function">constructor</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />			<span class="token comment">// Always call super first in constructor</span><br />			<span class="token keyword">super</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />			<span class="token comment">// Element functionality written in here</span><br />			<span class="token punctuation">}</span><br />			<span class="token function">attributeChangedCallback</span><span class="token punctuation">(</span><span class="token parameter">name<span class="token punctuation">,</span> oldValue<span class="token punctuation">,</span> newValue</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /><br />			<span class="token punctuation">}</span><br />			<span class="token function">connectedCallback</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />			<span class="token keyword">this</span><span class="token punctuation">.</span>className <span class="token operator">=</span> <span class="token string">"contexter-box__meta"</span><span class="token punctuation">;</span><br />			<span class="token punctuation">}</span><br />		<span class="token punctuation">}</span><br />		<span class="token punctuation">)</span><span class="token punctuation">;</span><br />		customElements<span class="token punctuation">.</span><span class="token function">define</span><span class="token punctuation">(</span><br />		<span class="token string">"contexter-summary"</span><span class="token punctuation">,</span><br />		<span class="token keyword">class</span> <span class="token class-name">extends</span> HTMLElement <span class="token punctuation">{</span><br />			<span class="token function">constructor</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />			<span class="token comment">// Always call super first in constructor</span><br />			<span class="token keyword">super</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />			<span class="token comment">// Element functionality written in here</span><br />			<span class="token punctuation">}</span><br />			<span class="token function">attributeChangedCallback</span><span class="token punctuation">(</span><span class="token parameter">name<span class="token punctuation">,</span> oldValue<span class="token punctuation">,</span> newValue</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /><br />			<span class="token punctuation">}</span><br />			<span class="token function">connectedCallback</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />			<span class="token keyword">this</span><span class="token punctuation">.</span>className <span class="token operator">=</span> <span class="token string">"p-summary entry-summary"</span><span class="token punctuation">;</span><br />			<span class="token punctuation">}</span><br />		<span class="token punctuation">}</span><br />		<span class="token punctuation">)</span><span class="token punctuation">;</span><br />		customElements<span class="token punctuation">.</span><span class="token function">define</span><span class="token punctuation">(</span><br />		<span class="token string">"contexter-box-head"</span><span class="token punctuation">,</span><br />		<span class="token keyword">class</span> <span class="token class-name">extends</span> HTMLElement <span class="token punctuation">{</span><br />			<span class="token function">constructor</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />			<span class="token comment">// Always call super first in constructor</span><br />			<span class="token keyword">super</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br />			<span class="token comment">// Element functionality written in here</span><br />			<span class="token punctuation">}</span><br />			<span class="token function">connectedCallback</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />			<span class="token keyword">this</span><span class="token punctuation">.</span>className <span class="token operator">=</span> <span class="token string">"contexter-box__head"</span><span class="token punctuation">;</span><br />			<span class="token punctuation">}</span><br />		<span class="token punctuation">}</span><br />		<span class="token punctuation">)</span><span class="token punctuation">;</span><br />		customElements<span class="token punctuation">.</span><span class="token function">define</span><span class="token punctuation">(</span><br />		<span class="token string">"contexter-box-inner"</span><span class="token punctuation">,</span><br />		<span class="token keyword">class</span> <span class="token class-name">extends</span> HTMLElement <span class="token punctuation">{</span><br />			<span class="token function">constructor</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />			<span class="token comment">// Always call super first in constructor</span><br />			<span class="token keyword">super</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br />			<span class="token comment">// Element functionality written in here</span><br />			<span class="token punctuation">}</span><br />			<span class="token function">connectedCallback</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />			<span class="token punctuation">}</span><br />		<span class="token punctuation">}</span><br />		<span class="token punctuation">)</span><span class="token punctuation">;</span><br />		<span class="token comment">// https://developers.google.com/web/fundamentals/web-components/best-practices</span><br />		<span class="token keyword">class</span> <span class="token class-name">ContexterBox</span> <span class="token keyword">extends</span> <span class="token class-name">HTMLElement</span> <span class="token punctuation">{</span><br />		<span class="token function">constructor</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />			<span class="token comment">// Always call super first in constructor</span><br />			<span class="token keyword">super</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />			<span class="token keyword">this</span><span class="token punctuation">.</span>first <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">;</span><br />			<span class="token keyword">this</span><span class="token punctuation">.</span>shadow <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">attachShadow</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">mode</span><span class="token operator">:</span> <span class="token string">"open"</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />		<span class="token punctuation">}</span><br />		<span class="token function">connectedCallback</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />			<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>first<span class="token punctuation">)</span><span class="token punctuation">{</span><br />			<span class="token keyword">this</span><span class="token punctuation">.</span>first <span class="token operator">=</span> <span class="token boolean">false</span><br />			<span class="token keyword">var</span> style <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">createElement</span><span class="token punctuation">(</span><span class="token string">"style"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />			style<span class="token punctuation">.</span>innerHTML <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string"><br />					:host {<br />						--background: #f5f6f7;<br />						--border: darkblue;<br />						--blue: #0000ee;<br />						--font-color: black;<br />						--inner-border: black;<br />						font-family: Franklin,Arial,Helvetica,sans-serif;<br />						font-size: 14px;<br />						background: var(--background);<br />						width: 600px;<br />						color: var(--font-color);<br />						min-height: 90px;<br />						display: block;<br />						padding: 8px;<br />						border: 1px solid var(--border);<br />						cursor: pointer;<br />						box-sizing: border-box;<br />						margin: 6px;<br />						contain: content;<br />					}<br /><br />					// can only select top-level nodes with slotted<br />					::slotted(*) {<br />						max-width: 100%;<br />						display:block;<br />					}<br />					::slotted([slot=thumbnail]) {<br />						max-width: 100%;<br />						display:block;<br />					}<br />					::slotted([slot=header]) {<br />						width: 100%;<br />						font-size: 1.25rem;<br />						font-weight: bold;<br />						display:block;<br />						margin-bottom: 6px;<br />					}<br />					::slotted([slot=author]) {<br />						max-width: 50%;<br />						font-size: 12px;<br />						display:inline-block;<br />						float: left;<br />					}<br />					::slotted([slot=time]) {<br />						max-width: 50%;<br />						font-size: 12px;<br />						display:inline-block;<br />						float: right;<br />					}<br />					::slotted([slot=summary]) {<br />						width: 100%;<br />						margin-top: 6px;<br />						padding: 10px 2px;<br />						border-top: 1px solid var(--inner-border);<br />						font-size: 15px;<br />						display:inline-block;<br />						margin-bottom: 6px;<br />					}<br />					contexter-meta {<br />						height: auto;<br />						margin-bottom: 4px;<br />						width: 100%;<br />						display: grid;<br />						position: relative;<br />						min-height: 16px;<br />						grid-template-columns: repeat(2, 1fr);<br />					}<br />					::slotted([slot=keywords]) {<br />						width: 80%;<br />						padding: 2px 4px;<br />						border-top: 1px solid var(--inner-border);<br />						font-size: 11px;<br />						display: block;<br />						float: right;<br />						font-style: italic;<br />						text-align: right;<br />						grid-column: 2/2;<br />						grid-row: 1;<br />						align-self: end;<br />						justify-self: end;<br />					}<br />					::slotted([slot=archive-link]) {<br />						font-size: 1em;<br />						display: inline;<br />					}<br />					::slotted([slot=archive-link])::after {<br />						content: "|";<br />						display: inline;<br />						color: var(--font-color);<br />						text-decoration: none;<br />						margin: 0 .5em;<br />					}<br />					::slotted([slot=read-link]) {<br />						font-size: 1em;<br />						display: inline;<br />					}<br />					contexter-linkset {<br />						width: 80%;<br />						padding: 2px 4px;<br />						font-size: 13px;<br />						float: left;<br />						font-weight: bold;<br />						grid-row: 1;<br />						grid-column: 1/2;<br />						align-self: end;<br />						justify-self: start;<br />					}<br />					/* Extra small devices (phones, 600px and down) */<br />					@media only screen and (max-width: 600px) {<br />						:host {<br />						width: 310px;<br />						}<br />					}<br />					/* Small devices (portrait tablets and large phones, 600px and up) */<br />					@media only screen and (min-width: 600px) {...}<br />					/* Medium devices (landscape tablets, 768px and up) */<br />					@media only screen and (min-width: 768px) {...}<br />					/* Large devices (laptops/desktops, 992px and up) */<br />					@media only screen and (min-width: 992px) {...}<br />					/* Extra large devices (large laptops and desktops, 1200px and up) */<br />					@media only screen and (min-width: 1200px) {...}<br />					@media (prefers-color-scheme: dark){<br />						:host {<br />						--background: #354150;<br />						--border: #1f2b37;<br />						--blue: #55b0ff;<br />						--font-color: #ffffff;<br />						--inner-border: #787a7c;<br />						background: var(--background);<br />						border: 1px solid var(--border)<br />						}<br />					}<br />				</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span><br />			<span class="token keyword">var</span> lightDomStyle <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">createElement</span><span class="token punctuation">(</span><span class="token string">"style"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />			lightDomStyle<span class="token punctuation">.</span>innerHTML <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string"><br />					contexter-box {<br />						contain: content;<br />					}<br />					contexter-box .read-link {<br />						font-weight: bold;<br />					}<br />					contexter-box a {<br />						color: #0000ee;<br />					}<br />					contexter-box img {<br />						width: 100%;<br />						border: 0;<br />						padding: 0;<br />						margin: 0;<br />					}<br />					/* Extra small devices (phones, 600px and down) */<br />					@media only screen and (max-width: 600px) {...}<br />					/* Small devices (portrait tablets and large phones, 600px and up) */<br />					@media only screen and (min-width: 600px) {...}<br />					/* Medium devices (landscape tablets, 768px and up) */<br />					@media only screen and (min-width: 768px) {...}<br />					/* Large devices (laptops/desktops, 992px and up) */<br />					@media only screen and (min-width: 992px) {...}<br />					/* Extra large devices (large laptops and desktops, 1200px and up) */<br />					@media only screen and (min-width: 1200px) {...}<br />					@media (prefers-color-scheme: dark){<br />						contexter-box a {<br />						color: #55b0ff;<br />						}<br />					}<br />			</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span><br />			<span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">appendChild</span><span class="token punctuation">(</span>lightDomStyle<span class="token punctuation">)</span><span class="token punctuation">;</span><br />			<span class="token comment">//https://stackoverflow.com/questions/49678342/css-how-to-target-slotted-siblings-in-shadow-dom-root</span><br />			<span class="token keyword">this</span><span class="token punctuation">.</span>shadow<span class="token punctuation">.</span><span class="token function">appendChild</span><span class="token punctuation">(</span>style<span class="token punctuation">)</span><span class="token punctuation">;</span><br />			<span class="token comment">// https://developers.google.com/web/fundamentals/web-components/shadowdom</span><br />			<span class="token comment">// https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_templates_and_slots</span><br />			<span class="token keyword">const</span> innerContainer <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">createElement</span><span class="token punctuation">(</span><span class="token string">"contexter-box-inner"</span><span class="token punctuation">)</span><br />			<span class="token keyword">this</span><span class="token punctuation">.</span>shadow<span class="token punctuation">.</span><span class="token function">appendChild</span><span class="token punctuation">(</span>innerContainer<span class="token punctuation">)</span><br />			<span class="token comment">// https://javascript.info/slots-composition</span><br />			<span class="token keyword">const</span> innerSlotThumbnail <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">createElement</span><span class="token punctuation">(</span><span class="token string">'slot'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />			innerSlotThumbnail<span class="token punctuation">.</span>name <span class="token operator">=</span> <span class="token string">"thumbnail"</span><br />			innerContainer<span class="token punctuation">.</span><span class="token function">appendChild</span><span class="token punctuation">(</span>innerSlotThumbnail<span class="token punctuation">)</span><br />			<span class="token keyword">const</span> innerSlotHeader <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">createElement</span><span class="token punctuation">(</span><span class="token string">'slot'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />			innerSlotHeader<span class="token punctuation">.</span>name <span class="token operator">=</span> <span class="token string">"header"</span><br />			innerContainer<span class="token punctuation">.</span><span class="token function">appendChild</span><span class="token punctuation">(</span>innerSlotHeader<span class="token punctuation">)</span><br />			<span class="token keyword">const</span> innerSlotAuthor <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">createElement</span><span class="token punctuation">(</span><span class="token string">'slot'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />			innerSlotAuthor<span class="token punctuation">.</span>name <span class="token operator">=</span> <span class="token string">"author"</span><br />			innerContainer<span class="token punctuation">.</span><span class="token function">appendChild</span><span class="token punctuation">(</span>innerSlotAuthor<span class="token punctuation">)</span><br />			<span class="token keyword">const</span> innerSlotTime <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">createElement</span><span class="token punctuation">(</span><span class="token string">'slot'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />			innerSlotTime<span class="token punctuation">.</span>name <span class="token operator">=</span> <span class="token string">"time"</span><br />			innerContainer<span class="token punctuation">.</span><span class="token function">appendChild</span><span class="token punctuation">(</span>innerSlotTime<span class="token punctuation">)</span><br />			<span class="token keyword">const</span> innerSlotSummary <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">createElement</span><span class="token punctuation">(</span><span class="token string">'slot'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />			innerSlotSummary<span class="token punctuation">.</span>name <span class="token operator">=</span> <span class="token string">"summary"</span><br />			innerContainer<span class="token punctuation">.</span><span class="token function">appendChild</span><span class="token punctuation">(</span>innerSlotSummary<span class="token punctuation">)</span><br /><br />			<span class="token keyword">const</span> metaContainer <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">createElement</span><span class="token punctuation">(</span><span class="token string">"contexter-meta"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />			innerContainer<span class="token punctuation">.</span><span class="token function">appendChild</span><span class="token punctuation">(</span>metaContainer<span class="token punctuation">)</span><br /><br />			<span class="token keyword">const</span> innerSlotInfo <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">createElement</span><span class="token punctuation">(</span><span class="token string">'slot'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />			innerSlotInfo<span class="token punctuation">.</span>name <span class="token operator">=</span> <span class="token string">"keywords"</span><br />			metaContainer<span class="token punctuation">.</span><span class="token function">appendChild</span><span class="token punctuation">(</span>innerSlotInfo<span class="token punctuation">)</span><br /><br />			<span class="token keyword">const</span> linkContainer <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">createElement</span><span class="token punctuation">(</span><span class="token string">"contexter-linkset"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />			metaContainer<span class="token punctuation">.</span><span class="token function">appendChild</span><span class="token punctuation">(</span>linkContainer<span class="token punctuation">)</span><br />			<span class="token keyword">const</span> innerSlotArchiveLink <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">createElement</span><span class="token punctuation">(</span><span class="token string">'slot'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />			innerSlotArchiveLink<span class="token punctuation">.</span>name <span class="token operator">=</span> <span class="token string">"archive-link"</span><br />			linkContainer<span class="token punctuation">.</span><span class="token function">appendChild</span><span class="token punctuation">(</span>innerSlotArchiveLink<span class="token punctuation">)</span><br />			<span class="token keyword">const</span> innerSlotReadLink <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">createElement</span><span class="token punctuation">(</span><span class="token string">'slot'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />			innerSlotReadLink<span class="token punctuation">.</span>name <span class="token operator">=</span> <span class="token string">"read-link"</span><br />			linkContainer<span class="token punctuation">.</span><span class="token function">appendChild</span><span class="token punctuation">(</span>innerSlotReadLink<span class="token punctuation">)</span><br /><br />			<span class="token keyword">this</span><span class="token punctuation">.</span>className <span class="token operator">=</span> <span class="token string">"contexter-box"</span><span class="token punctuation">;</span><br />			<span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function-variable function">onclick</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />				<span class="token comment">// console.log('Click on block', this)</span><br />				<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>e<span class="token punctuation">.</span>target<span class="token punctuation">.</span>className<span class="token punctuation">.</span><span class="token function">includes</span><span class="token punctuation">(</span><span class="token string">'read-link'</span><span class="token punctuation">)</span> <span class="token operator">&amp;&amp;</span> <span class="token operator">!</span>e<span class="token punctuation">.</span>target<span class="token punctuation">.</span>className<span class="token punctuation">.</span><span class="token function">includes</span><span class="token punctuation">(</span><span class="token string">'title-link'</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />				<span class="token keyword">const</span> mainLinks <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">querySelectorAll</span><span class="token punctuation">(</span><span class="token string">'a.main-link'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />				<span class="token comment">// console.log('mainLink', e, mainLinks)</span><br />				mainLinks<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">click</span><span class="token punctuation">(</span><span class="token punctuation">)</span><br />				<span class="token punctuation">}</span><br />			<span class="token punctuation">}</span><br />			<span class="token punctuation">}</span><br />		<span class="token punctuation">}</span><br />		<span class="token punctuation">}</span><br /><br />		customElements<span class="token punctuation">.</span><span class="token function">define</span><span class="token punctuation">(</span><span class="token string">"contexter-box"</span><span class="token punctuation">,</span> ContexterBox<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span><br /><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>window<span class="token punctuation">.</span>contexterSetupComplete<span class="token punctuation">)</span><span class="token punctuation">{</span><br />	window<span class="token punctuation">.</span><span class="token function">contexterSetup</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span></code></pre>
<p id="code-skip-day-16-4">You can see here I've made the entire box clickable by capturing any clicks (not on the archive link) and routing them to the Read link</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/context-pages/day-16/#code-skip-day-16-3" id="skip-to-code-skip-day-16-3" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript">	<span class="token keyword">const</span> mainLinks <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">querySelectorAll</span><span class="token punctuation">(</span><span class="token string">'a.main-link'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />	mainLinks<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">click</span><span class="token punctuation">(</span><span class="token punctuation">)</span></code></pre>
<p id="code-skip-day-16-3">I also don't want to re-run this script when there are multiple embeds so I encapsulate it inside a function call with a window level check that is set the first time I set up the script:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/context-pages/day-16/#code-skip-day-16-2" id="skip-to-code-skip-day-16-2" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>window<span class="token punctuation">.</span>contexterSetupComplete<span class="token punctuation">)</span><span class="token punctuation">{</span><br />	window<span class="token punctuation">.</span><span class="token function">contexterSetup</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span></code></pre>
<p id="code-skip-day-16-2">I originally set the links in a single element that contained both links. But I realized that I should <a href="https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_templates_and_slots" target="_blank">slot</a> them separately, to allow me to actively insert the archive link at another step for my Eleventy site's archive pages.</p>
<p>I had to <a href="https://github.com/AramZS/contexter/commit/291723fedaff8ba161937ce2f14802972e05fc01#diff-ad1cab4880eef9b423964380f642350431350ddddf8f3ffd30572e0875ee2fb0R38" target="_blank">fix my access of element properties</a>, <a href="https://github.com/AramZS/contexter/commit/291723fedaff8ba161937ce2f14802972e05fc01#diff-ad1cab4880eef9b423964380f642350431350ddddf8f3ffd30572e0875ee2fb0R314" target="_blank">check the readability object as a backup</a> for some of the finalizedMeta data, and <a href="https://github.com/AramZS/contexter/commit/291723fedaff8ba161937ce2f14802972e05fc01#diff-ad1cab4880eef9b423964380f642350431350ddddf8f3ffd30572e0875ee2fb0R494" target="_blank">fix the oembed for Twitter</a> so <a href="https://developer.twitter.com/en/docs/twitter-for-websites/embedded-tweets/overview" target="_blank">it doesn't show replies in a thread</a> that already includes replies.</p>
<p>I want to bring images used in the embeds local to the site. <a href="https://github.com/AramZS/devblog/commit/7e80d4e9a508e0c0c50f4e58d2417c05a89802b8" target="_blank">This turned out a lot harder than I expected</a>.</p>
<p>I pulled tweets in easily enough, but realized <a href="https://github.com/AramZS/devblog/commit/014f41df54410348ca11a66eb985b088c54467c3" target="_blank">I needed to print the author data for the Tweet to really make the archive readable</a>.</p>
<p>Now that I have a local archive, I can take advantage of the slot at the point where I build the collection. If I don't have the archive link from Wayback I can use my own site's archive.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/context-pages/day-16/#code-skip-day-16-1" id="skip-to-code-skip-day-16-1" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">if</span> <span class="token punctuation">(</span><br />	<span class="token operator">!</span>contextData<span class="token punctuation">.</span>data<span class="token punctuation">.</span>archivedData<span class="token punctuation">.</span>link <span class="token operator">&amp;&amp;</span><br />	<span class="token operator">!</span>contextData<span class="token punctuation">.</span>data<span class="token punctuation">.</span>twitterObj<br /><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />	contextData<span class="token punctuation">.</span>htmlEmbed <span class="token operator">=</span><br />		contextData<span class="token punctuation">.</span>htmlEmbed<span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span><br />			<span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">&lt;/contexter-box></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span><br />			<span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">&lt;a href="</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>options<span class="token punctuation">.</span>domain<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">/</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>options<span class="token punctuation">.</span>publicPath<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">/</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>contextData<span class="token punctuation">.</span>sanitizedLink<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">" is="contexter-link" target="_blank" class="read-link archive-link" itemprop="archivedAt" slot="archive-link">Archived&lt;/a>&lt;/contexter-box></span><span class="token template-punctuation string">`</span></span><br />		<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span></code></pre>
<p id="code-skip-day-16-1">Oops, I also need to <a href="https://github.com/AramZS/devblog/commit/b0d06bed36ff3a8c3c215c5fe28dbbf744faabf3" target="_blank">add that to the initial build of in-article embeds too</a>.</p>
<p>Ok, things are looking good! This is a good place to stop!</p>
]]></content:encoded>
	</item>
	
	<item>
		<title>Day 15: Working with Eleventy's Compiler </title>
		<link>https://fightwithtools.dev/posts/projects/context-pages/day-15/?source=rss</link>
		<pubDate>Fri, 18 Feb 2022 02:59:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/projects/context-pages/day-15/</guid>
		<description>I want to get the data set up in an HTML block a user can style</description>
		<content:encoded><![CDATA[<h2 id="project-scope-and-todos" tabindex="-1">Project Scope and ToDos</h2>
<ol>
<li>Take a link and turn it into an oEmbed/Open Graph style share card</li>
<li>Take a link and archive it in the most reliable way</li>
<li>When the link is a tweet, display the tweet but also the whole tweet thread.</li>
<li>When the link is a tweet, archive the tweets, and display them if the live ones are not available.</li>
<li>Capture any embedded retweets in the thread. Capture their thread if one exists</li>
<li>Capture any links in the Tweet</li>
<li>Create the process as an abstract function that returns the data in a savable way</li>
</ol>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Archive links on <a href="http://archive.org/" target="_blank">Archive.org</a> and save the resulting archival links</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Create link IDs that can be used to cache related content</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Integrate it into the site to be able to make context pages here.</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Check if a link is still available at build time and rebuild the block with links to an archived link</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Use v1 Twitter API to get Gifs and videos</li>
</ul>
<h2 id="day-15" tabindex="-1">Day 15</h2>
<p>Ok, so I've figured out that I may want to try something different this time, instead of sitting it inside of the markdown-it process, I can use Eleventy. My hope is that at some point I can attach these promises to something that can resolve them within the build process, but I'm not seeing a way yet.</p>
<p>It looks like the right direction is setting up a custom renderer, the original docs said it worked on async, but it <a href="https://github.com/11ty/eleventy/issues/2217" target="_blank">doesn't work on async</a> apparently, at least for now. So I think I'm going to have to pursue the same strategy I did in the past with the Markdown Github links, cache and reprocess opportunistically.</p>
<p>Ok, so the setup as an extension:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/context-pages/day-15/#code-skip-day-15-7" id="skip-to-code-skip-day-15-7" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript">eleventyConfig<span class="token punctuation">.</span><span class="token function">addExtension</span><span class="token punctuation">(</span>options<span class="token punctuation">.</span>extension<span class="token punctuation">,</span> <span class="token punctuation">{</span><br />	<span class="token literal-property property">read</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span><br />	<span class="token literal-property property">compile</span><span class="token operator">:</span> compiler<span class="token punctuation">,</span><br /><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p id="code-skip-day-15-7">It looks like I can't use the <code>defaultRenderer</code> with the <code>inputContent</code> argument that is the first argument sent into the compiler. So I'm going to need to use the already set-up markdown object.</p>
<p>Hmmm, easiest way to handle it is to pass the Markdown-It object into my plugin's options.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/context-pages/day-15/#code-skip-day-15-6" id="skip-to-code-skip-day-15-6" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript">eleventyConfig<span class="token punctuation">.</span><span class="token function">addPlugin</span><span class="token punctuation">(</span><span class="token function">require</span><span class="token punctuation">(</span><span class="token string">"./_custom-plugins/markdown-contexter"</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token punctuation">{</span><br />	<span class="token literal-property property">existingRenderer</span><span class="token operator">:</span> markdownSetup<span class="token punctuation">,</span><br /><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p id="code-skip-day-15-6">Ok, I've got Markdown-It working in my Eleventy extension, but it screwing up my other Markdown extension because it doesn't have anything set into the <code>env</code>. The object I need for my other markdown project in the <code>env</code> property looks like this:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/context-pages/day-15/#code-skip-day-15-5" id="skip-to-code-skip-day-15-5" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript"><span class="token punctuation">{</span><br />    <span class="token literal-property property">defaults</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">layout</span><span class="token operator">:</span> <span class="token string">'default.njk'</span><span class="token punctuation">,</span> <span class="token literal-property property">description</span><span class="token operator">:</span> <span class="token string">'Talking about code'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">description</span><span class="token operator">:</span> <span class="token string">'I want to get the data set up in an HTML block a user can style'</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">layout</span><span class="token operator">:</span> <span class="token string">'post.njk'</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">projects</span><span class="token operator">:</span> <span class="token punctuation">[</span> <span class="token punctuation">[</span>Object<span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">[</span>Object<span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">[</span>Object<span class="token punctuation">]</span> <span class="token punctuation">]</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">site</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />      <span class="token literal-property property">lang</span><span class="token operator">:</span> <span class="token string">'en-US'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">github</span><span class="token operator">:</span> <span class="token punctuation">[</span>Object<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">site_url</span><span class="token operator">:</span> <span class="token string">'http://localhost:8080'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">site_name</span><span class="token operator">:</span> <span class="token string">'Fight With Tools: A Dev Blog'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">description</span><span class="token operator">:</span> <span class="token string">'A site opening up my development process to all.'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">featuredImage</span><span class="token operator">:</span> <span class="token string">'nyc_noir.jpg'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">aramPhoto</span><span class="token operator">:</span> <span class="token string">'https://raw.githubusercontent.com/AramZS/aramzs.github.io/master/_includes/Aram-Zucker-Scharff-square.jpg'</span><br />    <span class="token punctuation">}</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">eleventy</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">env</span><span class="token operator">:</span> <span class="token punctuation">[</span>Object<span class="token punctuation">]</span> <span class="token punctuation">}</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">pkg</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />      <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'fightwithtooldev'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">version</span><span class="token operator">:</span> <span class="token string">'1.0.0'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">description</span><span class="token operator">:</span> <span class="token string">"This is the repo for Aram ZS's developer notes and log, keeping track of code experiments and decisions."</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">main</span><span class="token operator">:</span> <span class="token string">'index.js'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">scripts</span><span class="token operator">:</span> <span class="token punctuation">[</span>Object<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">keywords</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">author</span><span class="token operator">:</span> <span class="token string">''</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">license</span><span class="token operator">:</span> <span class="token string">'ISC'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">devDependencies</span><span class="token operator">:</span> <span class="token punctuation">[</span>Object<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">dependencies</span><span class="token operator">:</span> <span class="token punctuation">[</span>Object<span class="token punctuation">]</span><br />    <span class="token punctuation">}</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">tags</span><span class="token operator">:</span> <span class="token punctuation">[</span><br />      <span class="token string">'posts'</span><span class="token punctuation">,</span><br />      <span class="token string">'projects'</span><span class="token punctuation">,</span><br />      <span class="token string">'Node'</span><span class="token punctuation">,</span><br />      <span class="token string">'WiP'</span><span class="token punctuation">,</span><br />      <span class="token string">'archiving'</span><span class="token punctuation">,</span><br />      <span class="token string">'embeds'</span><span class="token punctuation">,</span><br />      <span class="token string">'Twitter'</span><br />    <span class="token punctuation">]</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">date</span><span class="token operator">:</span> <span class="token number">2022</span><span class="token operator">-</span><span class="token number">02</span><span class="token operator">-</span>07T02<span class="token operator">:</span><span class="token number">59</span><span class="token operator">:</span><span class="token number">43</span><span class="token punctuation">.</span>100Z<span class="token punctuation">,</span><br />    <span class="token literal-property property">project</span><span class="token operator">:</span> <span class="token string">'Context Pages'</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">repo</span><span class="token operator">:</span> <span class="token string">'https://github.com/AramZS/contexter'</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">featuredImage</span><span class="token operator">:</span> <span class="token string">'radial_crosshair.jpg'</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">title</span><span class="token operator">:</span> <span class="token string">'Day 14: Testing the Contexter in action'</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">page</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />      <span class="token literal-property property">date</span><span class="token operator">:</span> <span class="token number">2022</span><span class="token operator">-</span><span class="token number">02</span><span class="token operator">-</span>07T02<span class="token operator">:</span><span class="token number">59</span><span class="token operator">:</span><span class="token number">43</span><span class="token punctuation">.</span>100Z<span class="token punctuation">,</span><br />      <span class="token literal-property property">inputPath</span><span class="token operator">:</span> <span class="token string">'./src/posts/projects/context-pages/day-14.md'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">fileSlug</span><span class="token operator">:</span> <span class="token string">'day-14'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">filePathStem</span><span class="token operator">:</span> <span class="token string">'/posts/projects/context-pages/day-14'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">outputFileExtension</span><span class="token operator">:</span> <span class="token keyword">undefined</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">url</span><span class="token operator">:</span> <span class="token string">'/posts/projects/context-pages/day-14/'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">outputPath</span><span class="token operator">:</span> <span class="token string">'docs/posts/projects/context-pages/day-14/index.html'</span><br />    <span class="token punctuation">}</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">collections</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />      <span class="token literal-property property">all</span><span class="token operator">:</span> <span class="token punctuation">[</span>Array<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">blogroll</span><span class="token operator">:</span> <span class="token punctuation">[</span>Array<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token string-property property">'Personal Blog'</span><span class="token operator">:</span> <span class="token punctuation">[</span>Array<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">links</span><span class="token operator">:</span> <span class="token punctuation">[</span>Array<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token string-property property">'Code Reference'</span><span class="token operator">:</span> <span class="token punctuation">[</span>Array<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">Sass</span><span class="token operator">:</span> <span class="token punctuation">[</span>Array<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token string-property property">'11ty'</span><span class="token operator">:</span> <span class="token punctuation">[</span>Array<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token constant">NPM</span><span class="token operator">:</span> <span class="token punctuation">[</span>Array<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token string-property property">'Product Output'</span><span class="token operator">:</span> <span class="token punctuation">[</span>Array<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token string-property property">'Tech Critical'</span><span class="token operator">:</span> <span class="token punctuation">[</span>Array<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">Blockchain</span><span class="token operator">:</span> <span class="token punctuation">[</span>Array<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">Cryptocurrency</span><span class="token operator">:</span> <span class="token punctuation">[</span>Array<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">posts</span><span class="token operator">:</span> <span class="token punctuation">[</span>Array<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">Writing</span><span class="token operator">:</span> <span class="token punctuation">[</span>Array<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">Collaboration</span><span class="token operator">:</span> <span class="token punctuation">[</span>Array<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token string-property property">'Open Source'</span><span class="token operator">:</span> <span class="token punctuation">[</span>Array<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token string-property property">'Ad Tech'</span><span class="token operator">:</span> <span class="token punctuation">[</span>Array<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token string-property property">'BAd Tech'</span><span class="token operator">:</span> <span class="token punctuation">[</span>Array<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token string-property property">'Broken By Design'</span><span class="token operator">:</span> <span class="token punctuation">[</span>Array<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">projects</span><span class="token operator">:</span> <span class="token punctuation">[</span>Array<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">Node</span><span class="token operator">:</span> <span class="token punctuation">[</span>Array<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">WiP</span><span class="token operator">:</span> <span class="token punctuation">[</span>Array<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">Analytics</span><span class="token operator">:</span> <span class="token punctuation">[</span>Array<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">Privacy</span><span class="token operator">:</span> <span class="token punctuation">[</span>Array<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">Metrics</span><span class="token operator">:</span> <span class="token punctuation">[</span>Array<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">archiving</span><span class="token operator">:</span> <span class="token punctuation">[</span>Array<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">Twitter</span><span class="token operator">:</span> <span class="token punctuation">[</span>Array<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">embeds</span><span class="token operator">:</span> <span class="token punctuation">[</span>Array<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">oembed</span><span class="token operator">:</span> <span class="token punctuation">[</span>Array<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">opengraph</span><span class="token operator">:</span> <span class="token punctuation">[</span>Array<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">metadata</span><span class="token operator">:</span> <span class="token punctuation">[</span>Array<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">hcard</span><span class="token operator">:</span> <span class="token punctuation">[</span>Array<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token constant">RDF</span><span class="token operator">:</span> <span class="token punctuation">[</span>Array<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token string-property property">'JSON-LD'</span><span class="token operator">:</span> <span class="token punctuation">[</span>Array<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token string-property property">'Schema Dot Org'</span><span class="token operator">:</span> <span class="token punctuation">[</span>Array<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token string-property property">'Structured Data'</span><span class="token operator">:</span> <span class="token punctuation">[</span>Array<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">Markdown</span><span class="token operator">:</span> <span class="token punctuation">[</span>Array<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token string-property property">'Markdown-It'</span><span class="token operator">:</span> <span class="token punctuation">[</span>Array<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token string-property property">'Internet Archive'</span><span class="token operator">:</span> <span class="token punctuation">[</span>Array<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">fetch</span><span class="token operator">:</span> <span class="token punctuation">[</span>Array<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">research</span><span class="token operator">:</span> <span class="token punctuation">[</span>Array<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token string-property property">'Memento API'</span><span class="token operator">:</span> <span class="token punctuation">[</span>Array<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">Starters</span><span class="token operator">:</span> <span class="token punctuation">[</span>Array<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">dinky</span><span class="token operator">:</span> <span class="token punctuation">[</span>Array<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">nvm</span><span class="token operator">:</span> <span class="token punctuation">[</span>Array<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token string-property property">'GitHub Pages'</span><span class="token operator">:</span> <span class="token punctuation">[</span>Array<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">Nunjucks</span><span class="token operator">:</span> <span class="token punctuation">[</span>Array<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">Shortcodes</span><span class="token operator">:</span> <span class="token punctuation">[</span>Array<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token string-property property">'GitHub Actions'</span><span class="token operator">:</span> <span class="token punctuation">[</span>Array<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token constant">CSS</span><span class="token operator">:</span> <span class="token punctuation">[</span>Array<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token constant">GPC</span><span class="token operator">:</span> <span class="token punctuation">[</span>Array<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token string-property property">'Dart Sass'</span><span class="token operator">:</span> <span class="token punctuation">[</span>Array<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token constant">SEO</span><span class="token operator">:</span> <span class="token punctuation">[</span>Array<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token constant">SMO</span><span class="token operator">:</span> <span class="token punctuation">[</span>Array<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token constant">YAML</span><span class="token operator">:</span> <span class="token punctuation">[</span>Array<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">Aggregation</span><span class="token operator">:</span> <span class="token punctuation">[</span>Array<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">Mustache</span><span class="token operator">:</span> <span class="token punctuation">[</span>Array<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token string-property property">'Code Blocks'</span><span class="token operator">:</span> <span class="token punctuation">[</span>Array<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">a11y</span><span class="token operator">:</span> <span class="token punctuation">[</span>Array<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">GitHub</span><span class="token operator">:</span> <span class="token punctuation">[</span>Array<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token string-property property">'GitHub API'</span><span class="token operator">:</span> <span class="token punctuation">[</span>Array<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">Prism</span><span class="token operator">:</span> <span class="token punctuation">[</span>Array<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token string-property property">'Source Maps'</span><span class="token operator">:</span> <span class="token punctuation">[</span>Array<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">Sitemaps</span><span class="token operator">:</span> <span class="token punctuation">[</span>Array<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">Cachebreak</span><span class="token operator">:</span> <span class="token punctuation">[</span>Array<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">Mocha</span><span class="token operator">:</span> <span class="token punctuation">[</span>Array<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token constant">RSS</span><span class="token operator">:</span> <span class="token punctuation">[</span>Array<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token string-property property">'Cache breaking'</span><span class="token operator">:</span> <span class="token punctuation">[</span>Array<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">Retros</span><span class="token operator">:</span> <span class="token punctuation">[</span>Array<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token string-property property">'30m'</span><span class="token operator">:</span> <span class="token punctuation">[</span>Array<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token constant">SCSS</span><span class="token operator">:</span> <span class="token punctuation">[</span>Array<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">tagList</span><span class="token operator">:</span> <span class="token punctuation">[</span>Array<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">deepLinkPostsList</span><span class="token operator">:</span> <span class="token punctuation">[</span>Array<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">projectsPages</span><span class="token operator">:</span> <span class="token punctuation">[</span>Array<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">deepProjectPostsList</span><span class="token operator">:</span> <span class="token punctuation">[</span>Array<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">postsPages</span><span class="token operator">:</span> <span class="token punctuation">[</span>Array<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">deepTagList</span><span class="token operator">:</span> <span class="token punctuation">[</span>Array<span class="token punctuation">]</span><br />    <span class="token punctuation">}</span><br />  <span class="token punctuation">}</span><br /><span class="token punctuation">}</span></code></pre>
<p id="code-skip-day-15-5">Ok, where can I get it?</p>
<p>My <code>compiler</code> function only gets the basic data, the file path and content. But of course, the Markdown-It function has to get this data at some point? How does it even get set?</p>
<p>Looks like <a href="https://markdown-it.github.io/markdown-it/#MarkdownIt.render" target="_blank">env gets passed into the Markdown-It render function</a>. Ok, what's the <code>data</code> argument that gets passed into the function I return from the compiler?</p>
<p>Let's log it.</p>
<p>Bingo! Ok, so we're going to have a bit of a complicated set up, the function that handles rendering the contexter output and passing it into the Markdown-It object is going to have to be pre-defined and passed into the returned function.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/context-pages/day-15/#code-skip-day-15-4" id="skip-to-code-skip-day-15-4" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript">	<span class="token keyword">const</span> <span class="token function-variable function">reMarkdown</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">inputContent<span class="token punctuation">,</span> data</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />		<span class="token keyword">if</span> <span class="token punctuation">(</span><br />			inputContent<span class="token punctuation">.</span><span class="token function">includes</span><span class="token punctuation">(</span><br />				<span class="token string">"https://twitter.com/Chronotope/status/1402628536121319424"</span><br />			<span class="token punctuation">)</span><br />		<span class="token punctuation">)</span> <span class="token punctuation">{</span><br />			console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">"inputContent Process"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />			<span class="token keyword">let</span> pContext <span class="token operator">=</span> <span class="token function">contexter</span><span class="token punctuation">(</span><br />				<span class="token string">"https://twitter.com/Chronotope/status/1485620069229027329"</span><br />			<span class="token punctuation">)</span><span class="token punctuation">;</span><br />		<span class="token punctuation">}</span><br />		<span class="token comment">// 2nd argument sets env</span><br />		<span class="token keyword">return</span> options<span class="token punctuation">.</span>existingRenderer<span class="token punctuation">.</span><span class="token function">render</span><span class="token punctuation">(</span>inputContent<span class="token punctuation">,</span> data<span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token punctuation">}</span><span class="token punctuation">;</span><br />	<span class="token keyword">const</span> <span class="token function-variable function">compiler</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">inputContent<span class="token punctuation">,</span> inputPath</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />		<span class="token keyword">let</span> remark <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">;</span><br />		<span class="token keyword">if</span> <span class="token punctuation">(</span><br />			inputContent <span class="token operator">&amp;&amp;</span><br />			inputPath <span class="token operator">&amp;&amp;</span><br />			inputPath<span class="token punctuation">.</span><span class="token function">endsWith</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">.</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>options<span class="token punctuation">.</span>extension<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><br />		<span class="token punctuation">)</span> <span class="token punctuation">{</span><br />			remark <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">;</span><br />		<span class="token punctuation">}</span><br />		<span class="token keyword">return</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">data</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />			<span class="token keyword">if</span> <span class="token punctuation">(</span>remark <span class="token operator">&amp;&amp;</span> data<span class="token punctuation">.</span>layout <span class="token operator">&amp;&amp;</span> <span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">post</span><span class="token regex-delimiter">/</span></span><span class="token punctuation">.</span><span class="token function">test</span><span class="token punctuation">(</span>data<span class="token punctuation">.</span>layout<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />				<span class="token keyword">const</span> rmResult <span class="token operator">=</span> <span class="token function">reMarkdown</span><span class="token punctuation">(</span>inputContent<span class="token punctuation">,</span> data<span class="token punctuation">)</span><span class="token punctuation">;</span><br />				<span class="token keyword">return</span> rmResult<span class="token punctuation">;</span><br />			<span class="token punctuation">}</span><br />			<span class="token comment">// You can also access the default `markdown-it` renderer here:</span><br />			<span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">defaultRenderer</span><span class="token punctuation">(</span>data<span class="token punctuation">)</span><span class="token punctuation">;</span><br />		<span class="token punctuation">}</span><span class="token punctuation">;</span><br />	<span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
<p id="code-skip-day-15-4">Ok, now to write some files!</p>
<p>Hmmm, to get the file name, I'll need to be able to get the link ID and the sanitized link before initiating the promise. I'll have to restructure the main object to return those functions.</p>
<p><a target="_blank" href="https://github.com/AramZS/contexter/commit/05865c8911487986fde6f6ccd7a58994f1b0d6e1" class="git-commit-link"><code>git commit -am &quot;Small fixes and getting link utils facing out of the module&quot;</code></a></p>
<p>Ok, now to pull the URLs in with the regex. I'm going to name the regex group and use <code>exec</code> to pull just the URL along with the full match to make it possible to replace in the text.</p>
<p>Here's the final regex:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/context-pages/day-15/#code-skip-day-15-3" id="skip-to-code-skip-day-15-3" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> urlRegex <span class="token operator">=</span><br />	<span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">^(?:[\t\- ]*)(?&lt;main>(\b((?:[a-z][\w-]+:(?:\/{1,3}|[a-z0-9%])|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}\/)(?:[^\s()&lt;>]+|\(([^\s()&lt;>]+|(\([^\s()&lt;>]+\)))*\))+(?:\(([^\s()&lt;>]+|(\([^\s()&lt;>]+\)))*\)|[^\s`!()\[\]{};:'".,&lt;>?«»“”‘’]))(?=\n|\r)$)+)</span><span class="token regex-delimiter">/</span><span class="token regex-flags">gim</span></span><span class="token punctuation">;</span></code></pre>
<hr />
<p id="code-skip-day-15-3">EDIT (3/14/2023): <em>Don't use the above Regex</em>. It turns out to have a <a href="https://www.regular-expressions.info/catastrophic.html" target="_blank">catastrophic</a> <a href="https://javascript.info/regexp-catastrophic-backtracking" target="_blank">backtracking</a> problem caused when the line ends on a space. Here is the Regex I quickly switched to, though I am still testing:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/context-pages/day-15/#code-skip-day-15-2" id="skip-to-code-skip-day-15-2" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> urlRegex <span class="token operator">=</span><br />	<span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">^([\t\- ]*)*(?&lt;main>(\b((?:[a-z][\w-]+:(?:\/{1,3}|[a-z0-9%])|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}\/)(?:[^\s()&lt;>]+|\(([^\s()&lt;>]+|(\([^\s()&lt;>]+\)))*\))+(?:\(([^\s()&lt;>]+|(\([^\s()&lt;>]+\)))*\)|[^\s`!()\[\]{};:'".,&lt;>?«»“”‘’])))+)</span><span class="token regex-delimiter">/</span><span class="token regex-flags">gim</span></span><span class="token punctuation">;</span></code></pre>
<hr />
<p id="code-skip-day-15-2">Here's how I handled the walkthrough of the regex results:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/context-pages/day-15/#code-skip-day-15-1" id="skip-to-code-skip-day-15-1" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript">		<span class="token keyword">let</span> matchArray <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span><br />		<span class="token keyword">let</span> urlsArray <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span><br />		<span class="token keyword">let</span> counter <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span><br />		<span class="token keyword">while</span> <span class="token punctuation">(</span><span class="token punctuation">(</span>matchArray <span class="token operator">=</span> urlRegex<span class="token punctuation">.</span><span class="token function">exec</span><span class="token punctuation">(</span>inputContent<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />			<span class="token keyword">if</span> <span class="token punctuation">(</span>urls<span class="token punctuation">)</span> <span class="token punctuation">{</span><br />				console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><br />					<span class="token string">"Found URLs"</span><span class="token punctuation">,</span><br />					matchArray<span class="token punctuation">.</span>groups<span class="token punctuation">.</span>main<span class="token punctuation">,</span><br />					matchArray<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><br />				<span class="token punctuation">)</span><span class="token punctuation">;</span><br />				urlsArray<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span><span class="token punctuation">{</span><br />					<span class="token literal-property property">url</span><span class="token operator">:</span> matchArray<span class="token punctuation">.</span>groups<span class="token punctuation">.</span>main<span class="token punctuation">,</span><br />					<span class="token literal-property property">replace</span><span class="token operator">:</span> matchArray<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br />				<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />				counter<span class="token operator">++</span><span class="token punctuation">;</span><br />			<span class="token punctuation">}</span><br />		<span class="token punctuation">}</span><br />		<span class="token keyword">if</span> <span class="token punctuation">(</span>urlsArray<span class="token punctuation">.</span>length<span class="token punctuation">)</span> <span class="token punctuation">{</span><br />			urlsArray<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">urlObj</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />				<span class="token keyword">const</span> link <span class="token operator">=</span> urlObj<span class="token punctuation">.</span>url<span class="token punctuation">;</span><br />				console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">"inputContent Process"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />				<span class="token comment">// console.log("inputContent treated", inputContent);</span><br />				<span class="token keyword">const</span> <span class="token punctuation">{</span> cacheFolder<span class="token punctuation">,</span> cacheFile <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token function">cacheFilePath</span><span class="token punctuation">(</span><br />					<span class="token string">""</span><span class="token punctuation">,</span><br />					contexter<span class="token punctuation">.</span><span class="token function">uidLink</span><span class="token punctuation">(</span>contexter<span class="token punctuation">.</span><span class="token function">sanitizeLink</span><span class="token punctuation">(</span>link<span class="token punctuation">)</span><span class="token punctuation">)</span><br />				<span class="token punctuation">)</span><span class="token punctuation">;</span><br />				<span class="token keyword">try</span> <span class="token punctuation">{</span><br />					fs<span class="token punctuation">.</span><span class="token function">accessSync</span><span class="token punctuation">(</span>cacheFile<span class="token punctuation">,</span> fs<span class="token punctuation">.</span>constants<span class="token punctuation">.</span><span class="token constant">F_OK</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />					<span class="token keyword">const</span> contextString <span class="token operator">=</span> fs<span class="token punctuation">.</span><span class="token function">readFileSync</span><span class="token punctuation">(</span>cacheFile<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toString</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />					<span class="token keyword">const</span> contextData <span class="token operator">=</span> <span class="token constant">JSON</span><span class="token punctuation">.</span><span class="token function">parse</span><span class="token punctuation">(</span>contextString<span class="token punctuation">)</span><span class="token punctuation">;</span><br />					<span class="token comment">// console.log("contextData", contextData);</span><br />					<span class="token comment">// const contextData = JSON.parse(contextString);</span><br />					inputContent <span class="token operator">=</span> inputContent<span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span><br />						urlObj<span class="token punctuation">.</span>replace<span class="token punctuation">,</span><br />						contextData<span class="token punctuation">.</span>htmlEmbed<br />					<span class="token punctuation">)</span><span class="token punctuation">;</span><br />				<span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span>e<span class="token punctuation">)</span> <span class="token punctuation">{</span><br />					<span class="token keyword">let</span> pContext <span class="token operator">=</span> contexter<span class="token punctuation">.</span><span class="token function">context</span><span class="token punctuation">(</span>link<span class="token punctuation">)</span><span class="token punctuation">;</span><br />					<span class="token comment">// No file yet</span><br />					console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><br />						<span class="token string">"Cached link "</span> <span class="token operator">+</span> cacheFile <span class="token operator">+</span> <span class="token string">" to repo not ready"</span><br />					<span class="token punctuation">)</span><span class="token punctuation">;</span><br />					pContext<span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">r</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />						console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">"Context ready"</span><span class="token punctuation">,</span> r<span class="token punctuation">.</span>linkId<span class="token punctuation">)</span><span class="token punctuation">;</span><br />						<span class="token comment">// No file yet</span><br />						console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><br />							<span class="token string">"Cached link for "</span> <span class="token operator">+</span> cacheFile <span class="token operator">+</span> <span class="token string">" ready to write."</span><br />						<span class="token punctuation">)</span><span class="token punctuation">;</span><br />						<span class="token keyword">try</span> <span class="token punctuation">{</span><br />							fs<span class="token punctuation">.</span><span class="token function">mkdirSync</span><span class="token punctuation">(</span>cacheFolder<span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">recursive</span><span class="token operator">:</span> <span class="token boolean">true</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />							<span class="token comment">// console.log('write data to file', cacheFile)</span><br />							fs<span class="token punctuation">.</span><span class="token function">writeFileSync</span><span class="token punctuation">(</span>cacheFile<span class="token punctuation">,</span> <span class="token constant">JSON</span><span class="token punctuation">.</span><span class="token function">stringify</span><span class="token punctuation">(</span>r<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />						<span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span>e<span class="token punctuation">)</span> <span class="token punctuation">{</span><br />							console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">"writing to cache failed:"</span><span class="token punctuation">,</span> e<span class="token punctuation">)</span><span class="token punctuation">;</span><br />						<span class="token punctuation">}</span><br />					<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />				<span class="token punctuation">}</span><br />			<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />		<span class="token punctuation">}</span></code></pre>
<p id="code-skip-day-15-1">Ok, my treatment here <a href="https://github.com/AramZS/devblog/commit/b76853b38f74735fc7a1783ee176ce65b9bbdf84" target="_blank">looks good</a>! Only, the embeds don't look so good. Ok, looks like we have some work to do in terms of how the HTML can work, but the basic concept is very sound.</p>
<p>The last difficulty is setting up some archive pages that I can generate out of the JSON I cache local to the site on the basis of links. It isn't perfect, but a simple run at this makes sense first, I can have more complex archive pages, or WARCs or both later. This <a href="https://github.com/AramZS/devblog/commit/8a58ec6a9255301dd095694870d37939b2aa1d75" target="_blank">also turns out to be more complicated than I expected</a>. There's some weirdness here. For some reason <code>eleventyComputed</code> doesn't take every property I set up in it, but I can use the object itself. I took a first run at a Twitter object, but <a href="https://github.com/AramZS/devblog/commit/8a58ec6a9255301dd095694870d37939b2aa1d75#diff-2921b80376a7612f0dc51a098f3d81ad1f5d8a94c9955b6e1795313c3f0ca960R108" target="_blank">it doesn't work like I'd hoped</a>.</p>
<p>I am going to need richer user data. Let's give it a try.</p>
<p><a target="_blank" href="https://github.com/AramZS/contexter/commit/a67ff2f63b26e7ae63904ffb2f1f3ee113f1ef08" class="git-commit-link"><code>git commit -am &quot;Just use the data property, like everywhere else, on the main tweet and add in user data&quot;</code></a></p>
]]></content:encoded>
	</item>
	
	<item>
		<title>Day 14: Testing the Contexter in action</title>
		<link>https://fightwithtools.dev/posts/projects/context-pages/day-14/?source=rss</link>
		<pubDate>Fri, 11 Feb 2022 02:59:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/projects/context-pages/day-14/</guid>
		<description>I want to get the data set up in an HTML block a user can style</description>
		<content:encoded><![CDATA[<h2 id="project-scope-and-todos" tabindex="-1">Project Scope and ToDos</h2>
<ol>
<li>Take a link and turn it into an oEmbed/Open Graph style share card</li>
<li>Take a link and archive it in the most reliable way</li>
<li>When the link is a tweet, display the tweet but also the whole tweet thread.</li>
<li>When the link is a tweet, archive the tweets, and display them if the live ones are not available.</li>
<li>Capture any embedded retweets in the thread. Capture their thread if one exists</li>
<li>Capture any links in the Tweet</li>
<li>Create the process as an abstract function that returns the data in a savable way</li>
</ol>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Archive links on <a href="http://archive.org/" target="_blank">Archive.org</a> and save the resulting archival links</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Create link IDs that can be used to cache related content</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Integrate it into the site to be able to make context pages here.</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Check if a link is still available at build time and rebuild the block with links to an archived link</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Use v1 Twitter API to get Gifs and videos</li>
</ul>
<h2 id="day-14" tabindex="-1">Day 14</h2>
<p>Ok, let's make sure that the finalized meta object is as filled out as possible.</p>
<p><a target="_blank" href="https://github.com/AramZS/contexter/commit/4077e3b3d043421250039dbb4aa95f418eb77e99" class="git-commit-link"><code>git commit -am &quot;Fill out finalizedMeta object&quot;</code></a></p>
<p>Let's try to embed a tweet and a link in this post! What would this look like for Eleventy? We can't just pull the module in, we'll need to build something to process it.</p>
<p>So first a Tweet in a thread:</p>
<p><a href="https://twitter.com/Chronotope/status/1402628536121319424" target="_blank">https://twitter.com/Chronotope/status/1402628536121319424</a></p>
<p>A single tweet:</p>
<ul>
<li><a href="https://twitter.com/Chronotope/status/1485620069229027329" target="_blank">https://twitter.com/Chronotope/status/1485620069229027329</a></li>
</ul>
<p>A link:</p>
<p><a href="https://aramzs.github.io/jekyll/schema-dot-org/2018/04/27/how-to-make-your-jekyll-site-structured.html" target="_blank">https://aramzs.github.io/jekyll/schema-dot-org/2018/04/27/how-to-make-your-jekyll-site-structured.html</a></p>
<p>A tabbed link:</p>
<p><a href="https://www.regular-expressions.info/lookaround.html" target="_blank">https://www.regular-expressions.info/lookaround.html</a></p>
<p>Now, let's try building out the Eleventy plugin we need.</p>
<p>The core will be detection, so we want the right regex for it.</p>
<p>There's a <a href="https://stackoverflow.com/questions/6927719/url-regex-does-not-work-in-javascript" target="_blank">good preexisting safe URL regex</a> I can use. But I want to also make sure it's on its own line along with supporting <code>-</code>, <code>- </code> and a version that opens with a tab.</p>
<p>So we can play around a little bit to capture the opening and make sure that the URL is the end of the line as well:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/context-pages/day-14/#code-skip-day-14-1" id="skip-to-code-skip-day-14-1" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> urlRegex <span class="token operator">=</span><br />	<span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">^((\t?| )?\- )?(\b((?:[a-z][\w-]+:(?:\/{1,3}|[a-z0-9%])|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}\/)(?:[^\s()&lt;>]+|\(([^\s()&lt;>]+|(\([^\s()&lt;>]+\)))*\))+(?:\(([^\s()&lt;>]+|(\([^\s()&lt;>]+\)))*\)|[^\s`!()\[\]{};:'".,&lt;>?«»“”‘’]))(?=\n|\r)$)+</span><span class="token regex-delimiter">/</span><span class="token regex-flags">gim</span></span><span class="token punctuation">;</span></code></pre>
<p id="code-skip-day-14-1">Good stuff!</p>
<p>But how to apply it? I've tried doing it inside Markdown before but it requires a double-run. I wonder if I can try another approach?</p>
<p data-wordfix="true">What about <a href="https://www.11ty.dev/docs/config/#transforms" target="_blank">Eleventy transforms</a>? They look <a href="https://github.com/vimtor/eleventy-plugin-external-links/blob/main/index.js" target="_blank">pretty straightforward to implement</a>.</p>
<p>Oop ended up going out instead of finishing this. Whelp, on to the next day!</p>
]]></content:encoded>
	</item>
	
	<item>
		<title>Day 13: Getting Twitter Threads Working</title>
		<link>https://fightwithtools.dev/posts/projects/context-pages/day-13/?source=rss</link>
		<pubDate>Mon, 07 Feb 2022 02:59:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/projects/context-pages/day-13/</guid>
		<description>I want to get the data set up in an HTML block a user can style</description>
		<content:encoded><![CDATA[<h2 id="project-scope-and-todos" tabindex="-1">Project Scope and ToDos</h2>
<ol>
<li>Take a link and turn it into an oEmbed/Open Graph style share card</li>
<li>Take a link and archive it in the most reliable way</li>
<li>When the link is a tweet, display the tweet but also the whole tweet thread.</li>
<li>When the link is a tweet, archive the tweets, and display them if the live ones are not available.</li>
<li>Capture any embedded retweets in the thread. Capture their thread if one exists</li>
<li>Capture any links in the Tweet</li>
<li>Create the process as an abstract function that returns the data in a savable way</li>
</ol>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Archive links on <a href="http://archive.org/" target="_blank">Archive.org</a> and save the resulting archival links</li>
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Create link IDs that can be used to cache related content</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Integrate it into the site to be able to make context pages here.</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Check if a link is still available at build time and rebuild the block with links to an archived link</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Use v1 Twitter API to get Gifs and videos</li>
</ul>
<h2 id="day-13" tabindex="-1">Day 13</h2>
<p>Ok, forgot to do one thing, hook in the Twitter work. The one big issue is that I want to tie a bunch of oembeds together but the query doesn't seem to actually return a Twitter URL, just the ID. Is there a way to link to a Tweet without having to query up the user?</p>
<p>Looks like there is a way to construct this by putting the UID for the tweet on to the end of <code>https://twitter.com/i/web/status/</code>. Can I use this structure to get an oembed?</p>
<p>Nope.</p>
<p>Ok, it looks like even though this link doesn't work on the web and it isn't documented, you <a href="https://stackoverflow.com/questions/64917470/which-url-are-you-supposed-to-use-for-the-twitter-oembed-api" target="_blank">can take the ID and pass it into the oembed endpoint</a> in the format of <code>twitter.com/twitter/status/{id}</code>. This is a very irritating hack, but hey, it works. I can get real complicated here, but I think it would be good to get to actually integrating this into a blog setup to get a better handle on how it works.</p>
<p>It looks like my oEmbed tool doesn't work with Twitter, but I can make a custom fetch to that process. It will get me back an object with an <code>html</code> property. I can then use <code>reduce</code> to pull all those oembeds together into a single string. Each comes with a script tag, so I'll just remove that. The final version that gets stitched together can have the tag added to the end.</p>
<p><a target="_blank" href="https://github.com/AramZS/contexter/commit/aab665170673b07325726506e05b03cfae5bc15a" class="git-commit-link"><code>git commit -am &quot;Combine blockquotes, remove scripts and set up twitter thread oembeds.&quot;</code></a></p>
<p>Oh wait, I need to fix the finalized meta date object not filling properly!</p>
]]></content:encoded>
	</item>
	
	<item>
		<title>Day 12: Building a block to show link data</title>
		<link>https://fightwithtools.dev/posts/projects/context-pages/day-12/?source=rss</link>
		<pubDate>Sun, 06 Feb 2022 02:59:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/projects/context-pages/day-12/</guid>
		<description>I want to get the data set up in an HTML block a user can style</description>
		<content:encoded><![CDATA[<h2 id="project-scope-and-todos" tabindex="-1">Project Scope and ToDos</h2>
<ol>
<li>Take a link and turn it into an oEmbed/Open Graph style share card</li>
<li>Take a link and archive it in the most reliable way</li>
<li>When the link is a tweet, display the tweet but also the whole tweet thread.</li>
<li>When the link is a tweet, archive the tweets, and display them if the live ones are not available.</li>
<li>Capture any embedded retweets in the thread. Capture their thread if one exists</li>
<li>Capture any links in the Tweet</li>
<li>Create the process as an abstract function that returns the data in a savable way</li>
</ol>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Archive links on <a href="http://archive.org/" target="_blank">Archive.org</a> and save the resulting archival links</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Create link IDs that can be used to cache related content</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Integrate it into the site to be able to make context pages here.</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Check if a link is still available at build time and rebuild the block with links to an archived link</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Use v1 Twitter API to get Gifs and videos</li>
</ul>
<h2 id="day-12" tabindex="-1">Day 12</h2>
<p>Ok, I want to make it easy to set archives for queries by any user. So that means a predictable ID based on the link text. Could we handle that with a one way hash? We'll leverage the built-in node cryptographic library and <a href="https://medium.com/@chris_72272/what-is-the-fastest-node-js-hashing-algorithm-c15c1a0e164e" target="_blank">use the most performant approach</a>. If we were handling passwords we wouldn't use <code>sha1</code> but to create a predictable ID it should be just fine.</p>
<p>I can't use base64 encoding, because that would generate a string with slashes in it, so I'll need to use the <code>hex</code> digest. That can give me a nice safe-for-filename structure like <code>943fae25db612f29a54dc9851ae87f46de959cad</code>. I can also cover it with tests to make sure the functionality works the way I expect.</p>
<p><a target="_blank" href="https://github.com/AramZS/contexter/commit/07f46a92a6adfce51ecfebfd68c8e0a3afd34c30" class="git-commit-link"><code>git commit -am &quot;Create unique link IDs&quot;</code>'</a></p>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Create link IDs that can be used to cache related content</li>
</ul>
<p>Ok, let's create a basic template for link listings. We can mark it up with useful metadata as well, starting with <a href="https://microformats.org/wiki/h-entry" target="_blank">h-entry</a> and <a href="https://schema.org/CreativeWork" target="_blank">including Schema.org</a>. I'll start by building a basic version of the HTML I want to generate with all the markdown working correctly.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/context-pages/day-12/#code-skip-day-12-1" id="skip-to-code-skip-day-12-1" class="skip-link">Skip code block ▼</a></p>
<pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>article</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>link-card h-entry hentry<span class="token punctuation">"</span></span> <span class="token attr-name">itemscope</span> <span class="token attr-name">itemtype</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>https://schema.org/CreativeWork<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><br />  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>thumbnail<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><br />    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>img</span> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span><span class="token punctuation">"</span></span> <span class="token attr-name">alt</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span><span class="token punctuation">"</span></span> <span class="token attr-name">itemprop</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>image<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span><br />  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span><br />  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span><span class="token punctuation">></span></span><br />    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>header</span><span class="token punctuation">></span></span><br />      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>p-name entry-title<span class="token punctuation">"</span></span> <span class="token attr-name">itemprop</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>headline<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><br />        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span><span class="token punctuation">"</span></span> <span class="token attr-name">itemprop</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>url<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>A Tale Of Two Tags<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>a</span><span class="token punctuation">></span></span><br />      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">></span></span><br />    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>header</span><span class="token punctuation">></span></span><br />    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>p-author author<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><br />      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>p-name<span class="token punctuation">"</span></span> <span class="token attr-name">rel</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>author<span class="token punctuation">"</span></span> <span class="token attr-name">itemprop</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>author<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Chandra<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">></span></span><br />    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span><br />    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>time</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>dt-published published<span class="token punctuation">"</span></span> <span class="token attr-name">itemprop</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>datePublished<span class="token punctuation">"</span></span> <span class="token attr-name">datetime</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>2012-06-20T08:34:46-07:00<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>June 20, 2012<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>time</span><span class="token punctuation">></span></span><br />    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>summary</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>p-summary entry-summary<span class="token punctuation">"</span></span> <span class="token attr-name">itemprop</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>abstract<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><br />      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">></span></span>It was the best of visible tags, it was the alternative invisible tags.<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">></span></span><br />      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">></span></span>The a tag is perhaps the best of HTML, yet its corresponding invisible link tag has uses too.<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">></span></span><br />    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>summary</span><span class="token punctuation">></span></span><br />    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">itemprop</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>keywords<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><br />      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">rel</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>category tag<span class="token punctuation">"</span></span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>p-category<span class="token punctuation">"</span></span> <span class="token attr-name">itemprop</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>keywords<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>General<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">></span></span><br />    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span><br />    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span><span class="token punctuation">></span></span><br />      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span><span class="token punctuation">"</span></span> <span class="token attr-name">itemprop</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>archivedAt<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Archived<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>a</span><span class="token punctuation">></span></span><br />      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span><span class="token punctuation">"</span></span> <span class="token attr-name">itemprop</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>isBasedOn<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Read<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>a</span><span class="token punctuation">></span></span><br />    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span><br />  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span><br /><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>article</span><span class="token punctuation">></span></span></code></pre>
<p id="code-skip-day-12-1">Now let's break it down into components that are generated based on what data we get and then I can build them into the template.</p>
<p>At the point of the link-request module I'll want to get some backup values for image and description if I can. So I'll add some DOM walking properties to the object. I want to get the first Image SRC and that's easy enough to get, but notable that <code>jsdom</code> doesn't support <code>innerText</code> so I'll use <code>textContent</code> instead.</p>
<p>There are likely some other things that I could add to that <code>finalizedMeta</code> object to make it simpler to build the HTML I want.</p>
<p><a target="_blank" href="https://github.com/AramZS/contexter/commit/d037bbc6d5395b8f4454a3fccc479e94309c4825" class="git-commit-link"><code>git commit -am &quot;Add more data to finalized meta object&quot;</code></a></p>
<p>Ok, once I have everything passed into the template I want to test it using jsDom to make sure it has all the right stuff passed in.</p>
<p><a target="_blank" href="https://github.com/AramZS/contexter/commit/9b5d9b9ffb916dc9f13fca457b5d4f6f97e77944" class="git-commit-link"><code>git commit -am &quot;Set up creation of link block&quot;</code></a></p>
<p>I'm pretty much ready. I think it's good to take a look at the archive link which isn't really hooked in yet. I can check the request and...</p>
<p>Yup the GET request to the web archive returns the link that gets created by the request. Ok, I can include that in the object and yeah! This looks like it's good to go! Next step is to try integrating it into something.</p>
<p><a target="_blank" href="https://github.com/AramZS/contexter/commit/94a3e25ffb05013a2d8543148b4a4956053f0001" class="git-commit-link"><code>git commit -am &quot;Hook in archive url.&quot;</code></a></p>
]]></content:encoded>
	</item>
	
	<item>
		<title>Day 11: Getting Twitter Media and Links</title>
		<link>https://fightwithtools.dev/posts/projects/context-pages/day-11/?source=rss</link>
		<pubDate>Mon, 31 Jan 2022 02:59:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/projects/context-pages/day-11/</guid>
		<description>I want to get the full tweet and thread and the media inside those tweets. </description>
		<content:encoded><![CDATA[<h2 id="project-scope-and-todos" tabindex="-1">Project Scope and ToDos</h2>
<ol>
<li>Take a link and turn it into an oEmbed/Open Graph style share card</li>
<li>Take a link and archive it in the most reliable way</li>
<li>When the link is a tweet, display the tweet but also the whole tweet thread.</li>
<li>When the link is a tweet, archive the tweets, and display them if the live ones are not available.</li>
<li>Capture any embedded retweets in the thread. Capture their thread if one exists</li>
<li>Capture any links in the Tweet</li>
<li>Create the process as an abstract function that returns the data in a savable way</li>
</ol>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Archive links on <a href="http://archive.org/" target="_blank">Archive.org</a> and save the resulting archival links</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Create link IDs that can be used to cache related content</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Integrate it into the site to be able to make context pages here.</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Check if a link is still available at build time and rebuild the block with links to an archived link</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Use v1 Twitter API to get Gifs and videos</li>
</ul>
<h2 id="day-11" tabindex="-1">Day 11</h2>
<p>Ok, let's set up the last supporting function of the Twitter archiving process.</p>
<p>Ok, so what is the data structure involved here? I'm going to set up a test to log out the single tweet versions of this in order to understand what the data is and where it lives.</p>
<p>Here's how we figure out what we're looking at via tests.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/context-pages/day-11/#code-skip-day-11-2" id="skip-to-code-skip-day-11-2" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript"><span class="token function">describe</span><span class="token punctuation">(</span><span class="token string">"Capture twitter media"</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />	<span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">timeout</span><span class="token punctuation">(</span><span class="token number">60000</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token function">it</span><span class="token punctuation">(</span><span class="token string">"should capture a basic tweet with an image link"</span><span class="token punctuation">,</span> <span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />		<span class="token keyword">const</span> getUser <span class="token operator">=</span> <span class="token keyword">await</span> linkModule<br />			<span class="token punctuation">.</span><span class="token function">getTwitterClient</span><span class="token punctuation">(</span><span class="token punctuation">)</span><br />			<span class="token punctuation">.</span><span class="token function">singleTweet</span><span class="token punctuation">(</span><span class="token string">"1487451928309207047"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />		<span class="token function">expect</span><span class="token punctuation">(</span>getUser<span class="token punctuation">.</span>data<span class="token punctuation">.</span>text<span class="token punctuation">)</span><span class="token punctuation">.</span>to<span class="token punctuation">.</span><span class="token function">equal</span><span class="token punctuation">(</span><br />			<span class="token string">"Hmmm not sure I would want a mortgage from a company also encouraging me to gamble. https://t.co/S9tVJpjeZo"</span><br />		<span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />	it<span class="token punctuation">.</span><span class="token function">only</span><span class="token punctuation">(</span><span class="token string">"should get image media from a Tweet"</span><span class="token punctuation">,</span> <span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />		<span class="token keyword">const</span> gotTweet <span class="token operator">=</span> <span class="token keyword">await</span> linkModule<span class="token punctuation">.</span><span class="token function">getTweetByUrl</span><span class="token punctuation">(</span><br />			<span class="token string">"https://twitter.com/Chronotope/status/1487451928309207047"</span><br />		<span class="token punctuation">)</span><span class="token punctuation">;</span><br />		console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">"gotTweet"</span><span class="token punctuation">,</span> gotTweet<span class="token punctuation">)</span><span class="token punctuation">;</span><br />		console<span class="token punctuation">.</span><span class="token function">dir</span><span class="token punctuation">(</span>gotTweet<span class="token punctuation">.</span>data<span class="token punctuation">.</span>attachments<span class="token punctuation">)</span><span class="token punctuation">;</span><br />		console<span class="token punctuation">.</span><span class="token function">dir</span><span class="token punctuation">(</span>gotTweet<span class="token punctuation">.</span>data<span class="token punctuation">.</span>entities<span class="token punctuation">)</span><span class="token punctuation">;</span><br />		<span class="token function">expect</span><span class="token punctuation">(</span>gotTweet<span class="token punctuation">.</span>data<span class="token punctuation">.</span>attachments<span class="token punctuation">)</span><span class="token punctuation">.</span>to<span class="token punctuation">.</span>deep<span class="token punctuation">.</span><span class="token function">include</span><span class="token punctuation">(</span><span class="token punctuation">{</span><br />			<span class="token literal-property property">media_keys</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">"3_1487451926233030667"</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br />		<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />		<span class="token keyword">const</span> quotedId <span class="token operator">=</span> <span class="token keyword">await</span> linkModule<span class="token punctuation">.</span><span class="token function">getQuotedTweetId</span><span class="token punctuation">(</span>gotTweet<span class="token punctuation">.</span>data<span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p id="code-skip-day-11-2">So now we know that a tweet might have a <code>media_keys</code> property inside its <code>attachments</code> property and that it will give us a media key.</p>
<p>Looking at the list of endpoints... is there a way to query for the media by key? It doesn't look like it, i<a href="https://developer.twitter.com/en/docs/twitter-api/data-dictionary/object-model/media" target="_blank">t looks like it is just handled on the <code>includes</code> property of the query response object</a>. Easy enough to see by altering this test slightly for a single Tweet query. What about the search? I don't see media links, even though I can add them to the query according to the documentation. The library <a href="https://github.com/plhery/node-twitter-api-v2/blob/HEAD/doc/v2.md#search-tweets-recent" target="_blank">explains</a> that <a href="https://github.com/PLhery/node-twitter-api-v2/blob/master/doc/paginators.md" target="_blank">it has an access property on searches</a>.</p>
<p>But using that seems to do no more than accessing the tweet directly from the query object. The tweets themselves are surprisingly bare of metadata, regardless of what arguments I pass in. Ah, I can't just pass <code>media.fields</code> I also need to pass <code>expansions: [&quot;attachments.media_keys&quot;]</code>. But what happens when there is more than one result? I need a search that gets me multiple media tweets. Ok, so it is just a list, with keys alongside a list of tweets.</p>
<p>Instead I can combine the two, folding the <code>includes</code> data into the <code>attachments</code> key.</p>
<p>Ok, that works!</p>
<p><a target="_blank" href="https://github.com/AramZS/contexter/commit/3f30ebe3069c433b1516752ed2b4496e4a57da76" class="git-commit-link"><code>git commit -am &quot;Get image media from Tweet&quot;</code></a></p>
<p>Seems like I can't get gif media or videos from a Tweet. So those are out for now unless I want to activate v1. I'll put that on a future feature list nice-to-have. The last piece I want now is to extract links from Tweets.</p>
<p>Ok, for this I'll have to build a function that looks in the tweet data for the <code>entities</code> property and in the <code>entities</code> property for the <code>urls</code> property. If I find that, then I'll want to week out any <code>pic.twitter</code> URLs or <code>twitter.com</code> URLs in order to avoid double handling Twitter-based media I've already dealt with at some other part of the process. That should make sure that I don't have a situation where I'm trying to capture Twitter-based media as if it was a link off Twitter.</p>
<p><a target="_blank" href="https://github.com/AramZS/contexter/commit/d235cf475543ba90eec7f3a3144509fc38c6a2d5" class="git-commit-link"><code>git commit -am &quot;Pull links from tweets.&quot;</code></a></p>
<p>It's worth noting the expanded URL object can be pretty extensive. Here's an example of a full one:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/context-pages/day-11/#code-skip-day-11-1" id="skip-to-code-skip-day-11-1" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript"><span class="token punctuation">[</span><br />    <span class="token punctuation">{</span><br />      <span class="token literal-property property">start</span><span class="token operator">:</span> <span class="token number">224</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">end</span><span class="token operator">:</span> <span class="token number">247</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">url</span><span class="token operator">:</span> <span class="token string">'https://t.co/csLhSgsVy4'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">expanded_url</span><span class="token operator">:</span> <span class="token string">'https://www.thegamer.com/facebooks-horizon-worlds-broken-metaverse-unimaginative-games/'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">display_url</span><span class="token operator">:</span> <span class="token string">'thegamer.com/facebooks-hori…'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">images</span><span class="token operator">:</span> <span class="token punctuation">[</span>Array<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">status</span><span class="token operator">:</span> <span class="token number">200</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">title</span><span class="token operator">:</span> <span class="token string">'Facebook’s Horizon Worlds Is A Broken Metaverse Filled With Unimaginative Games'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">description</span><span class="token operator">:</span> <span class="token string">"For now, Mark Zuckerberg's virtual paradise looks like an underbaked digital space instead of Ready Player One"</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">unwound_url</span><span class="token operator">:</span> <span class="token string">'https://www.thegamer.com/facebooks-horizon-worlds-broken-metaverse-unimaginative-games/'</span><br />    <span class="token punctuation">}</span><br /><span class="token punctuation">]</span></code></pre>
<p id="code-skip-day-11-1">I'll build a simple function to dig those out.</p>
<p>Last piece before I integrate this chunk in with the rest of the library is a function to wind all this together.</p>
<p>I'll need to compile the data together into a single object and then run tests to cover single tweets, quoted tweets, tweet threads, and tweet threads with quote tweets.</p>
<p><a target="_blank" href="https://github.com/AramZS/contexter/commit/1ef63d08eeefaaab855887bf59efdd8cb70897b8" class="git-commit-link"><code>git commit -am &quot;Setup getTweets by URL for further use, with full data&quot;</code></a></p>
]]></content:encoded>
	</item>
	
	<item>
		<title>Day 10: Getting Quoted Tweets</title>
		<link>https://fightwithtools.dev/posts/projects/context-pages/day-10/?source=rss</link>
		<pubDate>Sun, 30 Jan 2022 02:59:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/projects/context-pages/day-10/</guid>
		<description>I want to get the full tweet and thread when a Tweet quotes another tweet. </description>
		<content:encoded><![CDATA[<h2 id="project-scope-and-todos" tabindex="-1">Project Scope and ToDos</h2>
<ol>
<li>Take a link and turn it into an oEmbed/Open Graph style share card</li>
<li>Take a link and archive it in the most reliable way</li>
<li>When the link is a tweet, display the tweet but also the whole tweet thread.</li>
<li>When the link is a tweet, archive the tweets, and display them if the live ones are not available.</li>
<li>Capture any embedded retweets in the thread. Capture their thread if one exists</li>
<li>Capture any links in the Tweet</li>
<li>Create the process as an abstract function that returns the data in a savable way</li>
</ol>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Archive links on <a href="http://archive.org/" target="_blank">Archive.org</a> and save the resulting archival links</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Create link IDs that can be used to cache related content</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Integrate it into the site to be able to make context pages here.</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Check if a link is still available at build time and rebuild the block with links to an archived link</li>
</ul>
<h2 id="day-10" tabindex="-1">Day 10</h2>
<p>Ok, I got my stuff pretty well working yesterday, but I want to check to see if it works with a thread that's not just me.</p>
<p>It isn't quite working though. It looks like I can't depend on the replied_to tweet data to be in the first position consistently. I'll use a <code>find</code> instead of making that assumption.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/context-pages/day-10/#code-skip-day-10-1" id="skip-to-code-skip-day-10-1" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> <span class="token function-variable function">getRepliedTo</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">tweetData</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />	<span class="token keyword">if</span> <span class="token punctuation">(</span>tweetData<span class="token punctuation">.</span>referenced_tweets <span class="token operator">&amp;&amp;</span> tweetData<span class="token punctuation">.</span>referenced_tweets<span class="token punctuation">.</span>length<span class="token punctuation">)</span> <span class="token punctuation">{</span><br />		<span class="token keyword">const</span> repliedTo <span class="token operator">=</span> tweetData<span class="token punctuation">.</span>referenced_tweets<span class="token punctuation">.</span><span class="token function">find</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">tweet</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />			<span class="token keyword">if</span> <span class="token punctuation">(</span>tweet<span class="token punctuation">.</span>type <span class="token operator">==</span> <span class="token string">"replied_to"</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />				<span class="token keyword">return</span> <span class="token boolean">true</span><span class="token punctuation">;</span><br />			<span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span><br />				<span class="token keyword">return</span> <span class="token boolean">false</span><span class="token punctuation">;</span><br />			<span class="token punctuation">}</span><br />		<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />		<span class="token keyword">if</span> <span class="token punctuation">(</span>repliedTo<span class="token punctuation">)</span> <span class="token punctuation">{</span><br />			console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">"referenced_tweet 0"</span><span class="token punctuation">,</span> repliedTo<span class="token punctuation">.</span>id<span class="token punctuation">)</span><span class="token punctuation">;</span><br />			<span class="token keyword">return</span> repliedTo<span class="token punctuation">.</span>id<span class="token punctuation">;</span><br />		<span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span><br />			<span class="token keyword">return</span> <span class="token boolean">false</span><span class="token punctuation">;</span><br />		<span class="token punctuation">}</span><br />	<span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span><br />		<span class="token keyword">return</span> <span class="token boolean">false</span><span class="token punctuation">;</span><br />	<span class="token punctuation">}</span><br /><span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
<p id="code-skip-day-10-1">Ok, now when I want to get a quoted tweet, I can build a similar function to extract the ID as a first step. Then I can get the full Tweet. I can try pulling that Tweet's thread... But what if that tweet is the middle of a thread? I should likely check that as well. Do I need to do that in every case, or just this case? I think it would be unwise to assume I want to do it in every case, so let's just do it in this case. Get the assumed Thread AND the conversation thread?</p>
<p>I guess it is a little more complicated and requires a little more complex of a return than a simple array to handle all the cases. Ok, time to refactor it.</p>
<p>Oh, ok, you don't get a <code>data</code> object with every tweet. It's only per query (though not the search query I guess?). Let's refactor some more to remove it from the equation and make my functions generally usable.</p>
<p><a target="_blank" href="https://github.com/AramZS/contexter/commit/7f2d16b0fa351c597fd17dac9da3bebd90a8616a" class="git-commit-link"><code>git commit -am &quot;Fix incorrect use of Twitter Query data object and make the thread finder more versatile.&quot;</code></a></p>
<p>Ok, so now let's set up a situation where we need this new feature to work! I've found a good Tweet, so now I'll give it a try.</p>
<p>Hmmmm</p>
<p>And for some reason my conversation_id based query isn't working. The query is going through, but it isn't getting results. Even though checking the search it should be.</p>
<p>Oh, I see, <a href="https://developer.twitter.com/en/docs/twitter-api/tweets/search/introduction" target="_blank">the search endpoint only goes back 7 days</a>. Annoying.</p>
<p><a target="_blank" href="https://github.com/AramZS/contexter/commit/47d8051fe7aef67d2f0a892d4d35f30c8b25b987" class="git-commit-link"><code>git commit -am &quot;Tweet archiver test if tweets were more recent this would work&quot;</code></a></p>
<p>Ok, I'm getting my quoted tweets and tweet threads!</p>
<p>Last step is a function for grabbing the media from tweets to archive and then I can build a function that takes tweet objects and turns them into something useful and embedable, and easy to archive.</p>
]]></content:encoded>
	</item>
	
	<item>
		<title>Day 9: Handle a Twitter Thread</title>
		<link>https://fightwithtools.dev/posts/projects/context-pages/day-9/?source=rss</link>
		<pubDate>Fri, 28 Jan 2022 02:59:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/projects/context-pages/day-9/</guid>
		<description>I want to get a Twitter thread when I link to a single Tweet that is part of a thread</description>
		<content:encoded><![CDATA[<h2 id="project-scope-and-todos" tabindex="-1">Project Scope and ToDos</h2>
<ol>
<li>Take a link and turn it into an oEmbed/Open Graph style share card</li>
<li>Take a link and archive it in the most reliable way</li>
<li>When the link is a tweet, display the tweet but also the whole tweet thread.</li>
<li>When the link is a tweet, archive the tweets, and display them if the live ones are not available.</li>
<li>Capture any embedded retweets in the thread. Capture their thread if one exists</li>
<li>Capture any links in the Tweet</li>
<li>Create the process as an abstract function that returns the data in a savable way</li>
</ol>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Archive links on <a href="http://archive.org/" target="_blank">Archive.org</a> and save the resulting archival links</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Create link IDs that can be used to cache related content</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Integrate it into the site to be able to make context pages here.</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Check if a link is still available at build time and rebuild the block with links to an archived link</li>
</ul>
<h2 id="day-9" tabindex="-1">Day 9</h2>
<p>Ok, so last time we were here it wasn't looping properly with the While and I assumed it had something to do with the Promises. I'm not so sure now. I forgot that I added the first tweet into the array which means it never even loops once. So this means the loop isn't advancing, but it's unclear why. My conditions seem to be correct.</p>
<p>After adding a little logging, it seems like it doesn't even finish that first loop.</p>
<p>Oops, looks like I captured the wrong Tweet to test with. Well, that's a good reason why.</p>
<p>Ok, code works, it's a little messy but it works!</p>
<p>Cleaned it up, refined the test. Here's the final function to walk a Tweet thread:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/context-pages/day-9/#code-skip-day-9-1" id="skip-to-code-skip-day-9-1" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript"><br /><span class="token keyword">const</span> <span class="token function-variable function">getTweetThread</span> <span class="token operator">=</span> <span class="token keyword">async</span> <span class="token punctuation">(</span><span class="token parameter">tweetObj <span class="token operator">=</span> defaultTweetObj</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />	<span class="token keyword">let</span> threadCheck <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">;</span><br />	<span class="token keyword">let</span> threadFirstCheck <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">;</span><br />	<span class="token keyword">let</span> conversation <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">;</span><br />	<span class="token comment">// const promises = [];</span><br />	<span class="token keyword">const</span> tweetData <span class="token operator">=</span> tweetObj<span class="token punctuation">.</span>data<span class="token punctuation">;</span><br />	<span class="token keyword">const</span> tweetIncludes <span class="token operator">=</span> tweetObj<span class="token punctuation">.</span>includes<span class="token punctuation">;</span><br />	<span class="token keyword">if</span> <span class="token punctuation">(</span>tweetData<span class="token punctuation">.</span>in_reply_to_user_id<span class="token punctuation">)</span> <span class="token punctuation">{</span><br />		threadFirstCheck <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">;</span><br />	<span class="token punctuation">}</span><br />	<span class="token keyword">if</span> <span class="token punctuation">(</span><br />		Array<span class="token punctuation">.</span><span class="token function">isArray</span><span class="token punctuation">(</span>tweetIncludes<span class="token punctuation">.</span>users<span class="token punctuation">)</span> <span class="token operator">&amp;&amp;</span><br />		tweetIncludes<span class="token punctuation">.</span>users<span class="token punctuation">.</span>length <span class="token operator">></span> <span class="token number">0</span> <span class="token operator">&amp;&amp;</span><br />		tweetIncludes<span class="token punctuation">.</span>users<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">.</span>users <span class="token operator">&amp;&amp;</span><br />		tweetData<span class="token punctuation">.</span>in_reply_to_user_id <span class="token operator">&amp;&amp;</span><br />		tweetData<span class="token punctuation">.</span>conversation_id <span class="token operator">!=</span> tweetData<span class="token punctuation">.</span>id<br />	<span class="token punctuation">)</span> <span class="token punctuation">{</span><br />		threadFirstCheck <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">;</span><br />	<span class="token punctuation">}</span><br />	<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>threadFirstCheck<span class="token punctuation">)</span> <span class="token punctuation">{</span><br />		conversation <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token function">getTwitterClient</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">search</span><span class="token punctuation">(</span><br />			<span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">conversation_id:</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>tweetData<span class="token punctuation">.</span>conversation_id<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> to:</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>tweetIncludes<span class="token punctuation">.</span>users<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">.</span>username<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> from:</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>tweetIncludes<span class="token punctuation">.</span>users<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">.</span>username<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span><br />			tweetFields<br />		<span class="token punctuation">)</span><span class="token punctuation">;</span><br />		<span class="token keyword">const</span> fullConversation <span class="token operator">=</span> conversation<span class="token punctuation">.</span>_realData<span class="token punctuation">.</span>data<span class="token punctuation">;</span><br />		<span class="token keyword">if</span> <span class="token punctuation">(</span>conversation<span class="token punctuation">.</span>_realData<span class="token punctuation">.</span>data<span class="token punctuation">.</span>length <span class="token operator">&lt;</span> <span class="token number">1</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />			<span class="token keyword">return</span> <span class="token boolean">false</span><span class="token punctuation">;</span><br />		<span class="token punctuation">}</span><br />		fullConversation<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span>tweetObj<span class="token punctuation">)</span><span class="token punctuation">;</span><br />		console<span class="token punctuation">.</span><span class="token function">dir</span><span class="token punctuation">(</span>fullConversation<span class="token punctuation">)</span><span class="token punctuation">;</span><br />		<span class="token keyword">return</span> fullConversation<span class="token punctuation">.</span><span class="token function">reverse</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span><br />		console<span class="token punctuation">.</span><span class="token function">dir</span><span class="token punctuation">(</span>tweetData<span class="token punctuation">)</span><span class="token punctuation">;</span><br />		conversation <span class="token operator">=</span> <span class="token punctuation">[</span>tweetObj<span class="token punctuation">]</span><span class="token punctuation">;</span><br />		<span class="token keyword">let</span> nextTweet <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">;</span><br />		<span class="token keyword">while</span> <span class="token punctuation">(</span>nextTweet <span class="token operator">!=</span> <span class="token boolean">false</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />			console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">"nextTweet"</span><span class="token punctuation">,</span> nextTweet<span class="token punctuation">)</span><span class="token punctuation">;</span><br />			<span class="token keyword">if</span> <span class="token punctuation">(</span>nextTweet <span class="token operator">===</span> <span class="token boolean">true</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />				nextTweet <span class="token operator">=</span> <span class="token function">getRepliedTo</span><span class="token punctuation">(</span>tweetData<span class="token punctuation">)</span><span class="token punctuation">;</span><br />				console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">"nextTweet true"</span><span class="token punctuation">,</span> nextTweet<span class="token punctuation">)</span><span class="token punctuation">;</span><br />			<span class="token punctuation">}</span><br />			<span class="token keyword">var</span> tweet <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token function">getTwitterClient</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">singleTweet</span><span class="token punctuation">(</span><br />				<span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>nextTweet<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span><br />				tweetFields<br />			<span class="token punctuation">)</span><span class="token punctuation">;</span><br />			<span class="token comment">// promises.push(tweet);</span><br />			console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">"tweet true"</span><span class="token punctuation">,</span> tweet<span class="token punctuation">)</span><span class="token punctuation">;</span><br />			conversation<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span>tweet<span class="token punctuation">)</span><span class="token punctuation">;</span><br />			nextTweet <span class="token operator">=</span> <span class="token function">getRepliedTo</span><span class="token punctuation">(</span>tweet<span class="token punctuation">.</span>data<span class="token punctuation">)</span><span class="token punctuation">;</span><br />		<span class="token punctuation">}</span><br />		<span class="token comment">// await Promise.all(promises);</span><br />		<span class="token keyword">return</span> conversation<span class="token punctuation">.</span><span class="token function">reverse</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token punctuation">}</span><br /><span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
<p id="code-skip-day-9-1">Cool stuff. I can now capture a twitter thread either bottom up or top down. Next step here is to capture any quote tweets and their threads. Luckily this thread provides an example quote tweet, I'll have to find another thread to give me a quoted thread.</p>
<p><a target="_blank" href="https://github.com/AramZS/contexter/commit/a3e1e68c05093ee6c6eb47102e47c8b16b442462" class="git-commit-link"><code>git commit -am &quot;Capture a Twitter thread&quot;</code></a></p>
]]></content:encoded>
	</item>
	
	<item>
		<title>Day 8: Getting a Twitter Thread</title>
		<link>https://fightwithtools.dev/posts/projects/context-pages/day-8/?source=rss</link>
		<pubDate>Wed, 26 Jan 2022 02:59:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/projects/context-pages/day-8/</guid>
		<description>I want to get a Twitter thread when I link to a single Tweet that is part of a thread</description>
		<content:encoded><![CDATA[<h2 id="project-scope-and-todos" tabindex="-1">Project Scope and ToDos</h2>
<ol>
<li>Take a link and turn it into an oEmbed/Open Graph style share card</li>
<li>Take a link and archive it in the most reliable way</li>
<li>When the link is a tweet, display the tweet but also the whole tweet thread.</li>
<li>When the link is a tweet, archive the tweets, and display them if the live ones are not available.</li>
<li>Capture any embedded retweets in the thread. Capture their thread if one exists</li>
<li>Capture any links in the Tweet</li>
<li>Create the process as an abstract function that returns the data in a savable way</li>
</ol>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Archive links on <a href="http://archive.org/" target="_blank">Archive.org</a> and save the resulting archival links</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Create link IDs that can be used to cache related content</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Integrate it into the site to be able to make context pages here.</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Check if a link is still available at build time and rebuild the block with links to an archived link</li>
</ul>
<h2 id="day-8" tabindex="-1">Day 8</h2>
<p>Last time I worked on this project I got a basic Twitter tweet object worked out. It looked like this:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/context-pages/day-8/#code-skip-day-8-4" id="skip-to-code-skip-day-8-4" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript"><span class="token punctuation">{</span><br />	<span class="token literal-property property">data</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />		<span class="token literal-property property">text</span><span class="token operator">:</span> <span class="token string">"@swodinsky Everything connected to the internet eventually becomes ads :/"</span><span class="token punctuation">,</span><br />		<span class="token literal-property property">referenced_tweets</span><span class="token operator">:</span> <span class="token punctuation">[</span><br />			<span class="token punctuation">{</span> <span class="token literal-property property">type</span><span class="token operator">:</span> <span class="token string">"replied_to"</span><span class="token punctuation">,</span> <span class="token literal-property property">id</span><span class="token operator">:</span> <span class="token string">"1275920325000278020"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span><br />		<span class="token punctuation">]</span><span class="token punctuation">,</span><br />		<span class="token literal-property property">author_id</span><span class="token operator">:</span> <span class="token string">"15099054"</span><span class="token punctuation">,</span><br />		<span class="token literal-property property">in_reply_to_user_id</span><span class="token operator">:</span> <span class="token string">"15099054"</span><span class="token punctuation">,</span><br />		<span class="token literal-property property">id</span><span class="token operator">:</span> <span class="token string">"1275920609097199628"</span><span class="token punctuation">,</span><br />		<span class="token literal-property property">entities</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />			<span class="token literal-property property">mentions</span><span class="token operator">:</span> <span class="token punctuation">[</span><br />				<span class="token punctuation">{</span><br />					<span class="token literal-property property">start</span><span class="token operator">:</span> <span class="token number">0</span><span class="token punctuation">,</span><br />					<span class="token literal-property property">end</span><span class="token operator">:</span> <span class="token number">10</span><span class="token punctuation">,</span><br />					<span class="token literal-property property">username</span><span class="token operator">:</span> <span class="token string">"swodinsky"</span><span class="token punctuation">,</span><br />					<span class="token literal-property property">id</span><span class="token operator">:</span> <span class="token string">"2908572178"</span><span class="token punctuation">,</span><br />				<span class="token punctuation">}</span><span class="token punctuation">,</span><br />			<span class="token punctuation">]</span><span class="token punctuation">,</span><br />		<span class="token punctuation">}</span><span class="token punctuation">,</span><br />		<span class="token literal-property property">possibly_sensitive</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span><br />		<span class="token literal-property property">conversation_id</span><span class="token operator">:</span> <span class="token string">"1275917959618232320"</span><span class="token punctuation">,</span><br />		<span class="token literal-property property">reply_settings</span><span class="token operator">:</span> <span class="token string">"everyone"</span><span class="token punctuation">,</span><br />		<span class="token literal-property property">created_at</span><span class="token operator">:</span> <span class="token string">"2020-06-24T22:35:53.000Z"</span><span class="token punctuation">,</span><br />		<span class="token literal-property property">source</span><span class="token operator">:</span> <span class="token string">"Twitter Web App"</span><span class="token punctuation">,</span><br />	<span class="token punctuation">}</span><span class="token punctuation">,</span><br />	<span class="token literal-property property">includes</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />		<span class="token literal-property property">users</span><span class="token operator">:</span> <span class="token punctuation">[</span><br />			<span class="token punctuation">{</span><br />				<span class="token literal-property property">username</span><span class="token operator">:</span> <span class="token string">"Chronotope"</span><span class="token punctuation">,</span><br />				<span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">"Aram Zucker-Scharff"</span><span class="token punctuation">,</span><br />				<span class="token literal-property property">id</span><span class="token operator">:</span> <span class="token string">"15099054"</span><span class="token punctuation">,</span><br />				<span class="token literal-property property">url</span><span class="token operator">:</span> <span class="token string">"https://t.co/2rHFiUBQX1"</span><span class="token punctuation">,</span><br />			<span class="token punctuation">}</span><span class="token punctuation">,</span><br />			<span class="token punctuation">{</span><br />				<span class="token literal-property property">username</span><span class="token operator">:</span> <span class="token string">"swodinsky"</span><span class="token punctuation">,</span><br />				<span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">"shoshana wodinsky (she/her)"</span><span class="token punctuation">,</span><br />				<span class="token literal-property property">id</span><span class="token operator">:</span> <span class="token string">"2908572178"</span><span class="token punctuation">,</span><br />				<span class="token literal-property property">url</span><span class="token operator">:</span> <span class="token string">"https://t.co/MYBP7NgPOL"</span><span class="token punctuation">,</span><br />			<span class="token punctuation">}</span><span class="token punctuation">,</span><br />		<span class="token punctuation">]</span><span class="token punctuation">,</span><br />		<span class="token literal-property property">tweets</span><span class="token operator">:</span> <span class="token punctuation">[</span><br />			<span class="token punctuation">{</span><br />				<span class="token literal-property property">possibly_sensitive</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span><br />				<span class="token literal-property property">text</span><span class="token operator">:</span> <span class="token string">"@swodinsky I think that, unless something changes pretty radically at the regulatory level, that is a fair assumption.  https://t.co/aDY7rAbJYd"</span><span class="token punctuation">,</span><br />				<span class="token literal-property property">id</span><span class="token operator">:</span> <span class="token string">"1275920325000278020"</span><span class="token punctuation">,</span><br />				<span class="token literal-property property">source</span><span class="token operator">:</span> <span class="token string">"Twitter Web App"</span><span class="token punctuation">,</span><br />				<span class="token literal-property property">author_id</span><span class="token operator">:</span> <span class="token string">"15099054"</span><span class="token punctuation">,</span><br />				<span class="token literal-property property">in_reply_to_user_id</span><span class="token operator">:</span> <span class="token string">"2908572178"</span><span class="token punctuation">,</span><br />				<span class="token literal-property property">reply_settings</span><span class="token operator">:</span> <span class="token string">"everyone"</span><span class="token punctuation">,</span><br />				<span class="token literal-property property">created_at</span><span class="token operator">:</span> <span class="token string">"2020-06-24T22:34:45.000Z"</span><span class="token punctuation">,</span><br />				<span class="token literal-property property">entities</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />					<span class="token literal-property property">urls</span><span class="token operator">:</span> <span class="token punctuation">[</span><br />						<span class="token punctuation">{</span><br />							<span class="token literal-property property">start</span><span class="token operator">:</span> <span class="token number">120</span><span class="token punctuation">,</span><br />							<span class="token literal-property property">end</span><span class="token operator">:</span> <span class="token number">143</span><span class="token punctuation">,</span><br />							<span class="token literal-property property">url</span><span class="token operator">:</span> <span class="token string">"https://t.co/aDY7rAbJYd"</span><span class="token punctuation">,</span><br />							<span class="token literal-property property">expanded_url</span><span class="token operator">:</span><br />								<span class="token string">"https://twitter.com/Chronotope/status/1134464455872524288"</span><span class="token punctuation">,</span><br />							<span class="token literal-property property">display_url</span><span class="token operator">:</span><br />								<span class="token string">"twitter.com/Chronotope/sta…"</span><span class="token punctuation">,</span><br />						<span class="token punctuation">}</span><span class="token punctuation">,</span><br />					<span class="token punctuation">]</span><span class="token punctuation">,</span><br />					<span class="token literal-property property">mentions</span><span class="token operator">:</span> <span class="token punctuation">[</span><br />						<span class="token punctuation">{</span><br />							<span class="token literal-property property">start</span><span class="token operator">:</span> <span class="token number">0</span><span class="token punctuation">,</span><br />							<span class="token literal-property property">end</span><span class="token operator">:</span> <span class="token number">10</span><span class="token punctuation">,</span><br />							<span class="token literal-property property">username</span><span class="token operator">:</span> <span class="token string">"swodinsky"</span><span class="token punctuation">,</span><br />							<span class="token literal-property property">id</span><span class="token operator">:</span> <span class="token string">"2908572178"</span><span class="token punctuation">,</span><br />						<span class="token punctuation">}</span><span class="token punctuation">,</span><br />					<span class="token punctuation">]</span><span class="token punctuation">,</span><br />				<span class="token punctuation">}</span><span class="token punctuation">,</span><br />				<span class="token literal-property property">referenced_tweets</span><span class="token operator">:</span> <span class="token punctuation">[</span><br />					<span class="token punctuation">{</span> <span class="token literal-property property">type</span><span class="token operator">:</span> <span class="token string">"quoted"</span><span class="token punctuation">,</span> <span class="token literal-property property">id</span><span class="token operator">:</span> <span class="token string">"1134464455872524288"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span><br />					<span class="token punctuation">{</span><br />						<span class="token literal-property property">type</span><span class="token operator">:</span> <span class="token string">"replied_to"</span><span class="token punctuation">,</span><br />						<span class="token literal-property property">id</span><span class="token operator">:</span> <span class="token string">"1275919838607794181"</span><span class="token punctuation">,</span><br />					<span class="token punctuation">}</span><span class="token punctuation">,</span><br />				<span class="token punctuation">]</span><span class="token punctuation">,</span><br />				<span class="token literal-property property">conversation_id</span><span class="token operator">:</span> <span class="token string">"1275917959618232320"</span><span class="token punctuation">,</span><br />			<span class="token punctuation">}</span><span class="token punctuation">,</span><br />		<span class="token punctuation">]</span><span class="token punctuation">,</span><br />	<span class="token punctuation">}</span><span class="token punctuation">,</span><br /><span class="token punctuation">}</span></code></pre>
<p id="code-skip-day-8-4">This time I want to be able to capture a Twitter thread. I <a href="https://twitter.com/Chronotope/status/1485621494365528072" target="_blank">have a short one</a> starting with a retweet at the top that will be perfect for this. So how do I test for this to be a thread?</p>
<p>I think there are a few early checks that can narrow it down:</p>
<ul>
<li>If the ID of the tweet doesn't match the conversation_id of the tweet.</li>
<li>If the <code>in_reply_to_user_id</code> field matches the <code>author_id</code></li>
</ul>
<p>This doesn't cover conversations that start at the beginning of the tweet though. For that I want to search by <code>conversation_id</code> and <code>author_id</code> to see if there are replies.</p>
<p>I'm able to search by conversation_id:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/context-pages/day-8/#code-skip-day-8-3" id="skip-to-code-skip-day-8-3" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript">	<span class="token keyword">const</span> conversation <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token function">getTwitterClient</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">search</span><span class="token punctuation">(</span><br />		<span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">conversation_id:</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>tweetData<span class="token punctuation">.</span>conversation_id<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><br />	<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p id="code-skip-day-8-3">but <code>+</code> or <code> </code> or <code>&amp;</code> as a join with <code>author_id</code> doesn't work.</p>
<p>Let me try it with just the <code>author_id</code> field.</p>
<p>Ok, well, that field isn't valid to query by itself either.</p>
<p><a href="https://developer.twitter.com/en/docs/twitter-api/tweets/search/integrate/build-a-query#build" target="_blank">Looks like only some fields are valid to query with</a>.</p>
<p>Ok! This works!</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/context-pages/day-8/#code-skip-day-8-2" id="skip-to-code-skip-day-8-2" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> conversation <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token function">getTwitterClient</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">search</span><span class="token punctuation">(</span><br />	<span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">conversation_id:</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>tweetData<span class="token punctuation">.</span>conversation_id<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> to:</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>tweetIncludes<span class="token punctuation">.</span>users<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">.</span>username<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> from:</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>tweetIncludes<span class="token punctuation">.</span>users<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">.</span>username<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span><br />	tweetFields<br /><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p id="code-skip-day-8-2">I can then take the array of tweets at <code>conversation._realData.data</code>, push the passed-in Tweet Object to the array of tweets, and then <code>reverse()</code> it.</p>
<p>Ok, that verifies if the tweet is at the top of the thread. I can check to make sure the query returns more than one object, so I know it is a thread.</p>
<p>The next type of Twitter link is the one that is at the bottom of the thread.</p>
<p>Hmmm, I can break out the function to get the replied to ID to it's own function so I can reuse it, but that doesn't solve the problem that walking up the Twitter thread is going to have a series of <code>async</code>s that need to be awaited. Perhaps <a href="https://stackoverflow.com/questions/17217736/while-loop-with-promises" target="_blank">this way</a>?</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/context-pages/day-8/#code-skip-day-8-1" id="skip-to-code-skip-day-8-1" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript"><span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span><br />	console<span class="token punctuation">.</span><span class="token function">dir</span><span class="token punctuation">(</span>tweetData<span class="token punctuation">)</span><span class="token punctuation">;</span><br />	conversation <span class="token operator">=</span> <span class="token punctuation">[</span>tweetObj<span class="token punctuation">]</span><span class="token punctuation">;</span><br /><br />	<span class="token keyword">let</span> nextTweet <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">;</span><br />	<span class="token keyword">while</span> <span class="token punctuation">(</span>nextTweet<span class="token punctuation">)</span> <span class="token punctuation">{</span><br />		<span class="token keyword">if</span> <span class="token punctuation">(</span>nextTweet <span class="token operator">===</span> <span class="token boolean">true</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />			nextTweet <span class="token operator">=</span> <span class="token function">getRepliedTo</span><span class="token punctuation">(</span>tweetData<span class="token punctuation">)</span><span class="token punctuation">;</span><br />		<span class="token punctuation">}</span><br />		<span class="token keyword">var</span> tweet <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token function">getTwitterClient</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">singleTweet</span><span class="token punctuation">(</span><br />			<span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>nextTweet<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span><br />			tweetFields<br />		<span class="token punctuation">)</span><span class="token punctuation">;</span><br />		conversation<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span>tweet<span class="token punctuation">)</span><span class="token punctuation">;</span><br />		nextTweet <span class="token operator">=</span> <span class="token function">getRepliedTo</span><span class="token punctuation">(</span>tweet<span class="token punctuation">.</span>data<span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token punctuation">}</span><br /><span class="token punctuation">}</span></code></pre>
<p id="code-skip-day-8-1">Hmmm... I'm not getting the right array length. Seems like it isn't waiting to resolve things wrong enough or my loop is wrong. Something to check tomorrow!</p>
<p><a target="_blank" href="https://github.com/AramZS/contexter/commit/0441d5328b40dbc441dec11aabbdd02662e56b29" class="git-commit-link"><code>git commit -am &quot;Building out thread archiver&quot;</code></a></p>
]]></content:encoded>
	</item>
	
	<item>
		<title>Day 7: Connecting to Twitter</title>
		<link>https://fightwithtools.dev/posts/projects/context-pages/day-7/?source=rss</link>
		<pubDate>Tue, 18 Jan 2022 02:59:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/projects/context-pages/day-7/</guid>
		<description>I want to get my Tweets archived when I link to them</description>
		<content:encoded><![CDATA[<h2 id="project-scope-and-todos" tabindex="-1">Project Scope and ToDos</h2>
<ol>
<li>Take a link and turn it into an oEmbed/Open Graph style share card</li>
<li>Take a link and archive it in the most reliable way</li>
<li>When the link is a tweet, display the tweet but also the whole tweet thread.</li>
<li>When the link is a tweet, archive the tweets, and display them if the live ones are not available.</li>
<li>Capture any embedded retweets in the thread. Capture their thread if one exists</li>
<li>Capture any links in the Tweet</li>
<li>Create the process as an abstract function that returns the data in a savable way</li>
</ol>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Archive links on <a href="http://archive.org/" target="_blank">Archive.org</a> and save the resulting archival links</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Create link IDs that can be used to cache related content</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Integrate it into the site to be able to make context pages here.</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Check if a link is still available at build time and rebuild the block with links to an archived link</li>
</ul>
<h2 id="day-7" tabindex="-1">Day 7</h2>
<p>I want to have a good archive of tweets, with the capability to capture the tweet, even if it is deleted. I also want to be able to capture a whole thread from the starting tweet.</p>
<p>One step at a time, let's capture tweets, create a specific-to-tweet archive mode, and then move on to the thread mode.</p>
<p>I could make a direct communication to the Twitter API, or do some more straightforward API requests, but it looks like there <a href="https://github.com/PLhery/node-twitter-api-v2" target="_blank">is a publicly maintained Node package with frequent activity and good contribution</a>. Let's start there.</p>
<p>I'll need to manage Twitter keys, so I need to use <code>dotenv</code> for local development.</p>
<p>Ok, documentation on this package isn't great, so let's start playing with it. First I'll set up a client and set that up with a unit test. Ok, well it looks like that isn't working. Something is wrong with how I'm setting up the client apparently. The most basic version isn't giving me back results.</p>
<p>Ok, I got to keep trying. I think I need to use the app flow here?</p>
<p>The <a href="https://github.com/plhery/node-twitter-api-v2/blob/HEAD/doc/basics.md" target="_blank">tutorial</a> they provide is annoyingly not very useful.</p>
<p>Ok, I tested out a few different takes on the authentication flow and got one working on Glitch. It looks like the way to build the client, since I already have the token, is with:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/context-pages/day-7/#code-skip-day-7-4" id="skip-to-code-skip-day-7-4" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript">	<span class="token keyword">const</span> appOnlyClient <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">TwitterApi</span><span class="token punctuation">(</span>process<span class="token punctuation">.</span>env<span class="token punctuation">.</span><span class="token constant">TWITTER_BEARER</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token comment">// const roC = appOnlyClient.readOnly;</span><br />	<span class="token keyword">const</span> v2Client <span class="token operator">=</span> appOnlyClient<span class="token punctuation">.</span>v2<span class="token punctuation">;</span><br />	<span class="token keyword">return</span> v2Client<span class="token punctuation">;</span></code></pre>
<p id="code-skip-day-7-4">Ok, to check this is working I need to check deep equality with the expected object. Not sure how to do that with mocha and chai. It <a href="https://medium.com/building-ibotta/testing-arrays-and-objects-with-chai-js-4b372310fe6d" target="_blank">looks</a> like I can do that with <code>expect(object).to.deep.include</code>?</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/context-pages/day-7/#code-skip-day-7-3" id="skip-to-code-skip-day-7-3" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">var</span> chai <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">"chai"</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br />	expect <span class="token operator">=</span> chai<span class="token punctuation">.</span>expect<span class="token punctuation">,</span><br />	assert <span class="token operator">=</span> chai<span class="token punctuation">.</span>assert<span class="token punctuation">,</span><br />	should <span class="token operator">=</span> chai<span class="token punctuation">.</span><span class="token function">should</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br /><span class="token keyword">const</span> linkModule <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">"../src/tweet-archiver"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token function">describe</span><span class="token punctuation">(</span><span class="token string">"The Twitter Archive Module"</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />	<span class="token comment">// Basic, let's make sure everything is working</span><br />	<span class="token comment">// Some adapted from https://github.com/braintree/sanitize-url/blob/main/src/__tests__/test.ts</span><br />	<span class="token function">describe</span><span class="token punctuation">(</span><span class="token string">"Capture a single tweet"</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />		<span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">timeout</span><span class="token punctuation">(</span><span class="token number">60000</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />		<span class="token function">it</span><span class="token punctuation">(</span><span class="token string">"should capture a basic tweet"</span><span class="token punctuation">,</span> <span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />			<span class="token keyword">const</span> getUser <span class="token operator">=</span> <span class="token keyword">await</span> linkModule<br />				<span class="token punctuation">.</span><span class="token function">getTwitterClient</span><span class="token punctuation">(</span><span class="token punctuation">)</span><br />				<span class="token punctuation">.</span><span class="token function">userByUsername</span><span class="token punctuation">(</span><span class="token string">"chronotope"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />			<span class="token function">expect</span><span class="token punctuation">(</span>getUser<span class="token punctuation">)</span><span class="token punctuation">.</span>to<span class="token punctuation">.</span>deep<span class="token punctuation">.</span><span class="token function">include</span><span class="token punctuation">(</span><span class="token punctuation">{</span><br />				<span class="token literal-property property">data</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />					<span class="token literal-property property">id</span><span class="token operator">:</span> <span class="token string">"15099054"</span><span class="token punctuation">,</span><br /><br />					<span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">"Aram Zucker-Scharff"</span><span class="token punctuation">,</span><br /><br />					<span class="token literal-property property">username</span><span class="token operator">:</span> <span class="token string">"Chronotope"</span><span class="token punctuation">,</span><br />				<span class="token punctuation">}</span><span class="token punctuation">,</span><br />			<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />		<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p id="code-skip-day-7-3">Yup, that works!</p>
<p>Ok, I've got a basic connection to twitter up and running!</p>
<p>Ok, so now I want to be able to get a Tweet's data from it's URL.</p>
<p>I want to start by <a href="https://github.com/PLhery/node-twitter-api-v2/blob/f4bea02d21b70faabb80973d34dc4ee545da9bf1/doc/v2.md#lookup-for-tweets" target="_blank">finding an individual tweet</a>. I need to regex the number out of the URL and then I can query up the tweet data.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/context-pages/day-7/#code-skip-day-7-2" id="skip-to-code-skip-day-7-2" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> <span class="token function-variable function">getTweetByUrl</span> <span class="token operator">=</span> <span class="token keyword">async</span> <span class="token punctuation">(</span><span class="token parameter">url</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />	<span class="token keyword">var</span> tweetID <span class="token operator">=</span> url<span class="token punctuation">.</span><span class="token function">match</span><span class="token punctuation">(</span><span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">(?&lt;=status\/).*(?=\/|)</span><span class="token regex-delimiter">/</span><span class="token regex-flags">i</span></span><span class="token punctuation">)</span><span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">;</span><br />	console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>tweetID<span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token keyword">var</span> tweet <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token function">getTwitterClient</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">tweets</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>tweetID<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token keyword">return</span> tweet<span class="token punctuation">;</span><br /><span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
<p id="code-skip-day-7-2">and in the test:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/context-pages/day-7/#code-skip-day-7-1" id="skip-to-code-skip-day-7-1" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript"><span class="token function">it</span><span class="token punctuation">(</span><span class="token string">"should capture a single tweet"</span><span class="token punctuation">,</span> <span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />	<span class="token keyword">const</span> getTweet <span class="token operator">=</span> <span class="token keyword">await</span> linkModule<span class="token punctuation">.</span><span class="token function">getTweetByUrl</span><span class="token punctuation">(</span><br />		<span class="token string">"https://twitter.com/Chronotope/status/1275920609097199628"</span><br />	<span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token function">expect</span><span class="token punctuation">(</span>getTweet<span class="token punctuation">)</span><span class="token punctuation">.</span>to<span class="token punctuation">.</span>deep<span class="token punctuation">.</span><span class="token function">include</span><span class="token punctuation">(</span><span class="token punctuation">{</span><br />		<span class="token literal-property property">data</span><span class="token operator">:</span> <span class="token punctuation">[</span><br />			<span class="token punctuation">{</span><br />				<span class="token literal-property property">id</span><span class="token operator">:</span> <span class="token string">"1275920609097199628"</span><span class="token punctuation">,</span><br />				<span class="token literal-property property">text</span><span class="token operator">:</span><br />					<span class="token string">"@swodinsky Everything connected to "</span> <span class="token operator">+</span><br />					<span class="token string">"the internet eventually becomes ads "</span> <span class="token operator">+</span><br />					<span class="token string">":/"</span><span class="token punctuation">,</span><br />			<span class="token punctuation">}</span><span class="token punctuation">,</span><br />		<span class="token punctuation">]</span><span class="token punctuation">,</span><br />	<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p id="code-skip-day-7-1">That works!</p>
<p><a target="_blank" href="https://github.com/AramZS/contexter/commit/8af474a386bf4da264158aaa8e5446fcd1cc4b00" class="git-commit-link"><code>git commit -am &quot;Basic Twitter query functionality&quot;</code></a></p>
<p>This is a little troubling though. There's no information about the tweet as a thread. That information is in a standard response from the Twitter API. Do I need to access the API directly or do I need to change my function call here?</p>
<p>Ok, it looks like <a href="https://developer.twitter.com/en/docs/twitter-api/tweets/lookup/api-reference/get-tweets" target="_blank">I have to use expansions and optional fields</a> to get the info I want. I can look in the defined types file for this module to understand a little more about how these get passed (easy enough to pull up with the Peak feature in VS Code).</p>
<p>Using that, I can get a much more complex object back!</p>
<p>Now I can have the whole tweet object I'm generating in the test, useful for reference.</p>
<p><a target="_blank" href="https://github.com/AramZS/contexter/commit/dd99a91697218b85f99ff9992fe993808fb96712" class="git-commit-link"><code>git commit -am &quot;Get and test a more complex single tweet&quot;</code></a></p>
]]></content:encoded>
	</item>
	
	<item>
		<title>Day 6: Looking into Memento and Readability processing</title>
		<link>https://fightwithtools.dev/posts/projects/context-pages/day-6/?source=rss</link>
		<pubDate>Mon, 17 Jan 2022 02:59:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/projects/context-pages/day-6/</guid>
		<description>I want to share lists of links, but make them readable and archived</description>
		<content:encoded><![CDATA[<h2 id="project-scope-and-todos" tabindex="-1">Project Scope and ToDos</h2>
<ol>
<li>Take a link and turn it into an oEmbed/Open Graph style share card</li>
<li>Take a link and archive it in the most reliable way</li>
<li>When the link is a tweet, display the tweet but also the whole tweet thread.</li>
<li>When the link is a tweet, archive the tweets, and display them if the live ones are not available.</li>
<li>Capture any embedded retweets in the thread. Capture their thread if one exists</li>
<li>Capture any links in the Tweet</li>
<li>Create the process as an abstract function that returns the data in a savable way</li>
</ol>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Archive links on <a href="http://archive.org/" target="_blank">Archive.org</a> and save the resulting archival links</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Create link IDs that can be used to cache related content</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Integrate it into the site to be able to make context pages here.</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Check if a link is still available at build time and rebuild the block with links to an archived link</li>
</ul>
<h2 id="day-6" tabindex="-1">Day 6</h2>
<p>It looks like if I want to get any more complicated than the basics of the Wayback Machine's <code>/save/</code> URL, I'll likely need to explore the Memento API structure. So, we'll <a href="http://mementoweb.org/guide/quick-intro/" target="_blank">start with the Memento intro</a>.</p>
<h3 id="examining-memento" tabindex="-1">Examining Memento</h3>
<p>Ok the main points here are that there are three Memento entities joined over a link-based time map:</p>
<ul>
<li>TimeGate</li>
<li>TimeMap</li>
<li>Memento</li>
</ul>
<p>It seems that whoever builds the site would be responsible for the first two entities, so I want to really (at least for now) drill down into the Mementos. There is <a href="http://mementoweb.org/guide/rfc/#overview" target="_blank">a spec for Mementos</a> as well and <a href="https://www.slideshare.net/hvdsomp/memento-101" target="_blank">a useful slideshow</a>. But most of this is looking at the access protocol, not the actual process of creating the archive.</p>
<p>Let's look for some guidance from the Archive Team projects. There are a few places that might be useful starts. There's <a href="https://github.com/ArchiveTeam/grab-site" target="_blank">grab-site</a> and <a href="https://github.com/ArchiveTeam/wpull" target="_blank">wpull</a>.</p>
<p>I think the place to start is running a little test of <code>grab-site</code> locally. Let's try it out.</p>
<h3 id="adding-readability-to-the-link-object" tabindex="-1">Adding Readability to the Link Object</h3>
<p>I also wonder if it makes sense to have a less complex archive shipped in this initial package, like taking the already downloaded HTML document and processing it <a href="https://github.com/mozilla/readability" target="_blank">with Readability</a>.</p>
<p>I'll start with <code>npm install @mozilla/readability</code> and incorporate it into building my link object.</p>
<p>Like I did with the other sources of metadata, I'll add it to the core object so people can do what they wish with it when they pull in this package. Let's make sure that this new property is properly covered with unit tests.</p>
<p><a target="_blank" href="https://github.com/AramZS/contexter/commit/7571ed989d9a6287894b2254bac14dfa990d9915" class="git-commit-link"><code>git commit -am &quot;Add readability object to output&quot;</code></a></p>
<p>Ok. I got that working!</p>
<h3 id="trying-out-grab-site" tabindex="-1">Trying out grab-site</h3>
<p>I want to switch back--now that I've installed it--to <code>grab-site</code> and see how it works.</p>
<p>Hmmm, it does not. It appears I have some missing libraries here. I'll <a href="https://stackoverflow.com/questions/63972113/big-sur-clang-invalid-version-error-due-to-macosx-deployment-target" target="_blank">have to run some system level updates</a>. Let's see if that works.</p>
<p>It looks like the key was running <code>softwareupdate --all --install --force</code> and then <code>sudo xcode-select --switch /Applications/Xcode.app/</code> on my OSX machine. Yup, that got it working!</p>
<p>Wow, when I archive a page with no additional actions it crawls way deep into every related page and link huh? I was thinking it might be possible to run this <a href="https://github.com/actions/virtual-environments" target="_blank">in a Github Action virtual machine</a>. But if I even want to try that I'll have to think about <a href="https://github.com/ArchiveTeam/grab-site#grab-site-options-ordered-by-importance" target="_blank">ways to limit it</a>. And on top of everything else, <code>grab-site</code> at least creates WARC files, which aren't ready to deploy to a static site that can then be browsed in a normal browser the way I would want to have this work. I'd either have to find different tools or some way to transform the WARC file into a browser accessible website. I'm sure there's a way, perhaps <a href="https://replayweb.page/docs/embedding" target="_blank">this ReplayWeb package</a> or some <a href="https://github.com/webrecorder/wabac.js" target="_blank">other</a> method, but I'll have to dig into it.</p>
<p>As I'm starting to examine <code>grab-site</code> and <code>wpull</code> and I'm wondering if building a Memento of a site is something that is going to be easy to do in Node. There are some utilities that it looks like have been adapted from Python into node that I can explore: <a href="https://github.com/webrecorder/warcio.js" target="_blank">warcio.js</a> and <a href="https://github.com/N0taN3rd/node-warc" target="_blank">node-warc</a>. At least if I do go down that route it will be a major project. It looks like I can also <a href="https://archiveweb.page/guide" target="_blank">look at ArchiveWeb as a possible tool to emulate</a> or <a href="https://webrecorder.net/tools" target="_blank">some related tools</a>? It might make more sense to handle it in another way. It's still worth digging into, but I'm wondering if I need to put a more complex archiving process aside to work on some other components. Let's put a pin in it for now.</p>
<p>Ok, I think it's a good place to stop for tonight!</p>
]]></content:encoded>
	</item>
	
	<item>
		<title>Play to Find Out: On Showing Your (Code) Work</title>
		<link>https://fightwithtools.dev/posts/writing/play-to-find-out-on-showing-your-code/?source=rss</link>
		<pubDate>Sun, 16 Jan 2022 20:30:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/writing/play-to-find-out-on-showing-your-code/</guid>
		<description>You can't learn without exploring. Working in the open, while scary, makes for easy collaboration, better results.</description>
		<content:encoded><![CDATA[<h2 id="how-do-you-solve-a-problem-of-unseen-code" tabindex="-1">How do you solve a problem of unseen-code?</h2>
<p>I've <a href="https://twitter.com/Chronotope/status/1390700217838841860" target="_blank">been thinking a lot about how to get better at code when it's in my own side projects</a>. I do these side projects pretty much in isolation. Maybe sometimes I get a comment or, if I tweet about it enough and it's relevant, it might get rolled into some blog post. When that happens it's great! But it doesn't really give me feedback on my work or the quality of it. Without feedback it's hard to improve.</p>
<p>Don't get me wrong, I do these projects for myself. I do them because I want to find something out and I need a tool to do it. I do them to learn new things because learning is fun. I do them because I want to create something cool that lets me play in code. These are all core to why I even bother with side projects.</p>
<p>I don't want to stagnate in these side projects. I want them to get better, I want them to make me better, I want to make <em>the projects</em> better, and I want to advance my skills while working on them.</p>
<p>At work, when I'm putting code together, I get opportunities to talk over ideas, plan architecture, and then, of course, I get feedback on my approach and technique in pull requests. PRs can be frustrating, revelatory, or any feeling in between, but I always learn something, even if it is just another way to approach how to write code.</p>
<p>This process makes better coders. It makes me a better coder. Exponentially so. I badly miss it when it comes to side projects, but there doesn't really seem to be any formal structures around how to make getting feedback part of casual coding projects. So, I thought about this for a while.</p>
<p>Then three things happened.</p>
<h3 id="play-to-find-out" tabindex="-1">Play To Find Out</h3>
<p>One: I started to play more Powered by the Apocalypse (PbtA) tabletop games. Then I started to write Powered by the Apocalypse games. Then I started to write rulesets for Powered by the Apocalypse games. This meant reading a lot of other people's PbtA games. I saw and came to appreciate one of the core rules for all Powered by the Apocalypse games, which is &quot;<a href="https://twitter.com/lumpleygames/status/1152247889885876224" target="_blank">Play to Find Out</a>&quot;.</p>
<p>Play to Find Out is deceptively simple; it means that you don't pre-decide the outcomes. It means that games don't go off the rails because they don't have the rails. You have a general endpoint in mind... maybe... but the more important thing is to not be a game &quot;master&quot; in the way D&amp;D games are run, but to be a facilitator. It's to let go of the style of absolute control and realize that sometimes decisions come from outside and are driven by accident and play as much as they are by starting intention.</p>
<p>This was the first idea to build on. I started thinking about these side projects less as end goals that leveraged things I knew and more as opportunities to explore the ecosystems and communities of the libraries and code samples I built on top of and potentially contribute back to them. I wasn't just going to go with my favorite tool, or what I wanted to learn, I was also going to go with the flow to some extent, <a href="https://fightwithtools.dev/posts/projects/devblog/retro-markdown-it/" target="_blank">even if it meant trying a library I neither needed to learn or would get any particular job-relevant knowledge from</a>.</p>
<p>I know it seems strange to say this, but this sort of thinking led me towards moving more with the flow of the work. I began treating side projects less as an outcome or desired product and more of an exploration. This has led me down some weird roads, but I think has made the process more sustainable and fun and will continue to do so!</p>
<h3 id="math-and-showing-your-work" tabindex="-1">Math and Showing Your Work</h3>
<p>Two: I started to get more into math. I know people generally expect those who work with code are &quot;math-y&quot; (for lack of a better term). But that was never my path. I wasn't particularly engaged (and, therefore, not particularly good) with math in high school or college. I never enjoyed it, nor could I focus on it. However, I've been encountering more complex math and math concepts through my work with the W3C.</p>
<p>I discovered that math was fun to read about and, more importantly, fun to play with conceptually. This is something I've been doing more. I think there's an image painted in most people's minds that an outcome of learning math in-depth is becoming the Math Expert, standing at a chalkboard working through equations. But I'm starting to think that's not the outcome, but the path.</p>
<p>To learn and refine our practice as coders we play towards an outcome with sketching system architecture, or pseudo code, both at a whiteboard.</p>
<p>Learning math isn't about getting to the point where you can stand at a whiteboard and do equations, it's about the process of learning through playing at the whiteboard.</p>
<p>The problems of my math education came out of a solutionism approach. So many of the problems that I've had trying to figure stuff out with code stem from the same frustrations I had as a kid with math: that there is only one methodology, only one solution, only one way, and I just have to find it like I'm digging up an artifact.</p>
<p>Solutionism isn't just a problem in how I learned math, <a href="https://www.macmillandictionary.com/us/buzzword/entries/solutionism.html" target="_blank">solutionism is a fundamental tech issue</a>. Approaching these projects as if they had ready-made solutions walls me off from collaboration in work. If I assume the solution is already there, ready formed in the metaphorical block of marble, I block out other viewpoints unlike mine and I remove the fun from the process of building, the exact opposite of what I want to do.</p>
<p>When I learned math, we always had to &quot;show our work&quot;. But showing our work wasn't really the point of my math education. &quot;Showing your work&quot; was code for &quot;prove you didn't cheat,&quot; and it wasn't about exploring the problem... it was about showing you could recite back rote methodology. It was an approach that enforced the opposite of what showing your work should be about. It was trying to enforce the concept that there was only <em>one</em> solution to any math problem. Math became something to be whipped into you.</p>
<p>No wonder Americans resisted so hard when math educators proclaimed that there might be more than one way to Do Math and that they were going to teach a different way to do so with Common Core. The math education I, and I suspect most others, received was designed to enforce that--not only was there a single solution--there was only one way to get to it. Learning some other approach to math hit a wall of dogma that the education system had handed down in math classrooms for decades.</p>
<p>So, from this realization that my math education was injured by a lack of play, I realized that what I needed for my side projects was to spend significantly more time showing my work than showing the resulting product. If I was going to be able to keep track of projects and enjoy my time on them, they had to be a vehicle for play, and the way you play with code is by working through it, sometimes down the wrong path, sometimes down an unexpected one.</p>
<h3 id="streaming-code" tabindex="-1">Streaming Code</h3>
<p>Three: Then I saw someone who had really encoded the first two realizations I had into their programming process and turned it into not just a way to work but a <strong>resource</strong>. I'm talking about <a href="https://twitter.com/pfrazee/status/1371174362531962880" target="_blank">this very cool thing that Paul Frazee is doing with his work</a> where he livestreams himself coding, working on his project. He talks through what he's doing and the decisions he's making, and opens himself up to feedback from a live and later reviewing audience. This is very much like the writing-circle-style coding approach that I want to create.</p>
<p>Even better, his code livestream becomes a permanent resource about his work that others can look to through his <a href="https://ctzn.network/dev-vlog" target="_blank">dev-vlog</a>, which links commits he's made during livestreams to the actual video where he's making those commits.</p>
<p>I think that, in some regards, streaming oneself doing code is terrifying. It means admitting that you have to look things up, that you don't know everything, and that maybe your code isn't always the best. It also means opening yourself up to a community of feedback, for better or worse.</p>
<p>I think my main hesitation with opening up my workflow like this is I worried that process is less interesting, even when I'm just thinking through an approach. I was disabused of this notion <a href="https://twitter.com/helenhousandi/status/1306277814551928832" target="_blank">when I watched Helen 侯-Sandí do her bug scrub livestream as part of the WordPress development workflow</a>. Watching people at work is interesting, regardless of the work.</p>
<h2 id="principles-of-the-dev-blog" tabindex="-1">Principles of the Dev Blog</h2>
<p>So, taking these inspirations, I decided that what I really needed was a dev blog... heavy on the <strong>log</strong> part.</p>
<p>I could have done a video stream, like a number of other people do. Clearly, there <a href="https://www.youtube.com/channel/UCSkcL4my2wgDRFvjQOJzrlg" target="_blank">are</a> <a href="https://www.twitch.tv/williamchyr" target="_blank">some</a> <a href="https://www.twitch.tv/mvandevander" target="_blank">great</a> <a href="https://www.twitch.tv/devwars/videos" target="_blank">examples</a> out there. But I don't think that model fits for me. I don't code regularly. This is a fun thing to do in my free time and I don't want to make a schedule for it in the way that livestreaming seems to require. Also, sometimes I think up something at lunch and jot a note about it and some code down. Or, I do very little one day. Or, I spread it out over small sessions. My approach for the projects I want to document just doesn't seem to be the right one for livestreaming.</p>
<p>It's less of a resource that way too, at least when it isn't attached to a specific project. I want this to be as much of a reference as a log. Part of the goal here is to create stuff that is useful to people. Even if maybe I need to de-index things via robots.txt with some regularity.</p>
<p>So, instead, I decided to create a written blog, which lets me exercise my writing too. This is another practice I enjoy but don't spend enough time doing.</p>
<p>On top of everything else, this will help me solve a problem where I often like to put projects down for a while, or switch projects, and then when I come back to it I can't remember what I was doing. With an active log, it'll be easier to pick up and put down projects, which will be more fun.</p>
<p>I decided it needs principles</p>
<ul>
<li>Commit often: better to save a reasonable mistake than forget it and repeat it.</li>
<li>Work in the open: with errors and frustration on display.</li>
<li>Play to learn: work through the problems instead of around them, even if it means sticking with a library that might frustrate me.</li>
<li>Document the mistakes.</li>
<li>Always take the opportunity to contribute: so that means building plugins, making PRs, leaving Issues and taking feedback in my own issues or PRs. Engage in the communities around the code I use, even if it means slowing down and breaking from working on a project.</li>
<li>Work towards readability: The goal should always be to make my work readable in both log and code formats and to be clearer through things like leaving in scrap print statements and comments so others can reuse my shown work as much as the end product.</li>
<li>Write messy, clean another day: Logs should be raw first and then edited and cleaned up on a later date.</li>
<li>Define scope, but don't make it the absolute limit.</li>
</ul>
<p>And I decided I needed to make <a href="https://fightwithtools.dev/projects/devblog/" target="_blank">the first project this blog documented the making of the blog itself</a>.</p>
<p>So, that's what this is about, trying to code but without a solutionism bent, instead with a mind to show my work, to show that this is a process, and not always an easy one. That this type of work is better done with a community, open to input, and out in the open. That I might <strong>fight with my tools,</strong> but that's part of the process. Hopefully, by opening up that process, I can help others.</p>
<p>Also, I'm just a big <a href="https://open.spotify.com/album/2mSCSmEjNdJUic3fcqse57?si=8GiAlR9XT2aD1mK54NLQ3Q" target="_blank">Flobots fan</a>.</p>
]]></content:encoded>
	</item>
	
	<item>
		<title>Extract Sass into an Eleventy Plugin</title>
		<link>https://fightwithtools.dev/posts/projects/devblog/upgrade-to-eleventy-1/?source=rss</link>
		<pubDate>Sun, 16 Jan 2022 02:59:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/projects/devblog/upgrade-to-eleventy-1/</guid>
		<description>More devblog</description>
		<content:encoded><![CDATA[<h2 id="project-scope-and-todos" tabindex="-1">Project Scope and ToDos</h2>
<ol>
<li>Static Site Generator that can build the blog and let me host it on Github Pages</li>
<li>I want to write posts in Markdown because I'm lazy, it's easy, and it is how I take notes now.</li>
<li>I don't want to spend a ton of time doing design work. I'm doing complicated designs for other projects, so I want to pull a theme I like that I can rely on someone else to keep up.</li>
<li>Once it gets going, I want template changes to be easy.</li>
<li>It should be as easy as Jekyll, so I need to be able to build it using GitHub Actions, where I can just commit a template change or Markdown file and away it goes. If I can't figure this out than fk it, just use Jekyll.</li>
<li>I require it to be used by a significant percent of my professional peers so I can get easy answers when something goes wrong.</li>
<li>I want source maps. This is a dev log site which means whatever I do with it should be easy for other developers to read.</li>
</ol>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Also <a href="https://www.npmjs.com/package/@quasibit/eleventy-plugin-sitemap" target="_blank">the sitemap plugin</a> looks cool. Should grab that later.</li>
</ul>
<s>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> So does the <a href="https://www.npmjs.com/package/eleventy-plugin-reading-time" target="_blank">reading time one</a>.</li>
</ul>
</s>
<ul class="task-list">
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Also <a href="https://github.com/jdsteinbach/eleventy-plugin-toc/" target="_blank">this TOC plugin</a> mby?</p>
</li>
<li class="task-list-item">
<p data-wordfix="true"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Use <a href="https://www.11ty.dev/docs/data-deep-merge/" target="_blank">Data Deep Merge</a> in this blog.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Decide if I want to render the CSS fancier than just a base file and do per-template splitting.</p>
</li>
</ul>
<s>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Can I use the template inside of dinky that already exists instead of copy/pasting it?</li>
</ul>
</s>
<s>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Is there a way to have permalinks to posts contain metadata without organizing them into subfolders?</li>
</ul>
</s>
<ul class="task-list">
<li class="task-list-item">
<p data-wordfix="true"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> How do I cachebreak files on the basis of new build events? Datetime? <code>site.github.build_revision</code> is <a href="https://github.com/jekyll/github-metadata/blob/master/docs/site.github.md" target="_blank">how Jekyll accomplishes this</a>, but is there a way to push <a href="https://docs.github.com/en/actions/reference/context-and-expression-syntax-for-github-actions#github-context" target="_blank">that</a> <a href="https://stackoverflow.com/questions/54310050/how-to-version-build-artifacts-using-github-actions" target="_blank">into the build process</a> for Eleventy?</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Make link text look less shitty. It looks like it is a whole, lighter, font.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Code blocks do not have good syntax highlighting. I want good syntax highlighting.</p>
</li>
<li class="task-list-item">
<p data-wordfix="true"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Build a Markdown-it plugin to take my typing shortcuts <code>[prob, b/c, ...?]</code> and expand them on build.</p>
</li>
</ul>
<s>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> See if we can start Markdown's interpretation of H tags to <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/Heading_Elements#multiple_h1" target="_blank">start at 2, since H1</a> is always pulled from the page title metadata. If it isn't easy, I just have to change my pattern of writing in the MD documents.</li>
</ul>
</s>
<ul class="task-list">
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Should I <a href="https://www.madebymike.com.au/writing/11ty-filters-data-shortcodes/" target="_blank">explore some shortcodes</a>?</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Order projects listing by last posted blog in that project</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Limit the output of home page post lists to a specific number of posts</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Show the latest post below the site intro on the homepage.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Tags pages with Pagination</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Posts should be able to support a preview header image that can also be shown on post lists.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Create a Markdown-It plugin that reads the project's repo URL off the folder data file and renders commit messages with <a href="https://stackoverflow.com/questions/15919635/on-github-api-what-is-the-best-way-to-get-the-last-commit-message-associated-w" target="_blank">links to the referenced commit</a>. (Is this even possible?) (Is there a way to do it with eleventy instead?)</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Create Next Day/Previous Day links on each post / Next/Previous post on post templates from projects</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Tags should be in the sidebar of articles and link to tag pages</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Create a skiplink for the todo section (or would this be better served with the ToC plugin?) - Yes it would be!</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Add a Things I Learned section to the project pages that are the things I learned from that specific project.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Add a technical reading log to the homepage</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/:empty" target="_blank">Hide</a> empty sections.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Add byline to post pages</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Have table of contents attach to sidebar bottom on mobile</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Support dark mode</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Social Icons</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> SEO/Social/JSON-LD HEAD data</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Create a per-project <code>/now</code> page.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Create a whole-site aggregated <code>/now</code> page.</p>
</li>
</ul>
<h2 id="day-43" tabindex="-1">Day 43</h2>
<p>Ok, so I want to update Eleventy to v1. In part, because I want to try some features. So let's give it a go!</p>
<p>I installed <a href="https://github.com/11ty/eleventy-upgrade-help" target="_blank">11ty's upgrade helper</a>, and it passes me. It helps that apparently most of the changes were to Liquid stuff which I don't use.</p>
<p>Ok, things look good. I'll have to check what, if anything, changes. I got a warning about my sitemap plugin from NPM, but <code>http://localhost:8080/sitemap.xml</code> on my local build looks fine. So... looking good?</p>
]]></content:encoded>
	</item>
	
	<item>
		<title>Day 5: Simple Wayback Machine Archiving</title>
		<link>https://fightwithtools.dev/posts/projects/context-pages/day-5/?source=rss</link>
		<pubDate>Sun, 16 Jan 2022 02:59:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/projects/context-pages/day-5/</guid>
		<description>I want to share lists of links, but make them readable and archived</description>
		<content:encoded><![CDATA[<h2 id="project-scope-and-todos" tabindex="-1">Project Scope and ToDos</h2>
<ol>
<li>Take a link and turn it into an oEmbed/Open Graph style share card</li>
<li>Take a link and archive it in the most reliable way</li>
<li>When the link is a tweet, display the tweet but also the whole tweet thread.</li>
<li>When the link is a tweet, archive the tweets, and display them if the live ones are not available.</li>
<li>Capture any embedded retweets in the thread. Capture their thread if one exists</li>
<li>Capture any links in the Tweet</li>
<li>Create the process as an abstract function that returns the data in a savable way</li>
</ol>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Archive links on <a href="http://archive.org/" target="_blank">Archive.org</a> and save the resulting archival links</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Create link IDs that can be used to cache related content</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Integrate it into the site to be able to make context pages here.</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Check if a link is still available at build time and rebuild the block with links to an archived link</li>
</ul>
<h2 id="day-5" tabindex="-1">Day 5</h2>
<p>Ok, the <a href="http://archive.is/" target="_blank">Archive.is</a> stuff isn't working for no clear reason. Let's step back and try <a href="http://archive.org/" target="_blank">Archive.org</a>. I want to first standardize to a single set of finalized meta values. I built a function to find the right values moving down priorities from <code>metadata</code> to OpenGraph to JSON-LD, with JSON-LD (where there) being the most likely to have accurate metadata.</p>
<p>Ok, let's look at Web Archive documentation</p>
<ul>
<li><a href="https://blog.archive.org/2017/01/25/see-something-save-something/" target="_blank">https://blog.archive.org/2017/01/25/see-something-save-something/</a></li>
<li><a href="https://github.com/ArchiveTeam" target="_blank">https://github.com/ArchiveTeam</a></li>
<li><a href="https://wiki.archiveteam.org/index.php/Dev/Source_Code" target="_blank">https://wiki.archiveteam.org/index.php/Dev/Source_Code</a></li>
<li><a href="https://github.com/ArchiveTeam/seesaw-kit" target="_blank">https://github.com/ArchiveTeam/seesaw-kit</a></li>
<li><a href="https://github.com/ArchiveTeam/grab-site" target="_blank">https://github.com/ArchiveTeam/grab-site</a></li>
<li><a href="https://help.archive.org/how-to-upload-files-to-create-a-new-item-page/" target="_blank">https://help.archive.org/how-to-upload-files-to-create-a-new-item-page/</a></li>
<li><a href="https://help.archive.org/example-of-good-metadata-for-items/" target="_blank">https://help.archive.org/example-of-good-metadata-for-items/</a></li>
<li><a href="https://en.wikipedia.org/wiki/Help:Using_the_Wayback_Machine" target="_blank">https://en.wikipedia.org/wiki/Help:Using_the_Wayback_Machine</a></li>
</ul>
<p>It can definitely get complicated depending on how complex we want our archiving process to be. But let's start with <a href="https://en.wikipedia.org/wiki/Help:Using_the_Wayback_Machine#To_save_a_live_page" target="_blank">a very basic version</a>. It looks like I should just be able to send a request and start the archiving process off? Let's try setting up a basic fetch.</p>
<p>Hmm there's a bunch of repeated code I'll need to implement for fetch. Let's pull it out into its own file. Now I can basically use it in place and also reuse it for my link archiver functions:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/context-pages/day-5/#code-skip-day-5-1" id="skip-to-code-skip-day-5-1" class="skip-link">Skip code block ▼</a></p>
<pre class="language-js"><code class="language-js"><span class="token comment">// Using suggestion from the docs - https://www.npmjs.com/package/node-fetch#loading-and-configuring-the-module</span><br /><br /><span class="token keyword">const</span> <span class="token function-variable function">fetch</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter"><span class="token operator">...</span>args</span><span class="token punctuation">)</span> <span class="token operator">=></span><br />	<span class="token keyword">import</span><span class="token punctuation">(</span><span class="token string">"node-fetch"</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> <span class="token keyword">default</span><span class="token operator">:</span> fetch <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token function">fetch</span><span class="token punctuation">(</span><span class="token operator">...</span>args<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br /><span class="token keyword">const</span> ua <span class="token operator">=</span><br />	<span class="token string">"facebookexternalhit/1.1 (+http://www.facebook.com/externalhit_uatext.php)"</span><span class="token punctuation">;</span><br /><br /><span class="token keyword">const</span> <span class="token function-variable function">getRequestHeaders</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />	<span class="token keyword">return</span> <span class="token punctuation">{</span><br />		<span class="token literal-property property">cookie</span><span class="token operator">:</span> <span class="token string">""</span><span class="token punctuation">,</span><br />		<span class="token string-property property">"Accept-Language"</span><span class="token operator">:</span> <span class="token string">"en-US,en;q=0.8"</span><span class="token punctuation">,</span><br />		<span class="token string-property property">"User-Agent"</span><span class="token operator">:</span> ua<span class="token punctuation">,</span><br />	<span class="token punctuation">}</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span><span class="token punctuation">;</span><br /><br /><span class="token keyword">class</span> <span class="token class-name">HTTPResponseError</span> <span class="token keyword">extends</span> <span class="token class-name">Error</span> <span class="token punctuation">{</span><br />	<span class="token function">constructor</span><span class="token punctuation">(</span><span class="token parameter">response<span class="token punctuation">,</span> <span class="token operator">...</span>args</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />		<span class="token keyword">super</span><span class="token punctuation">(</span><br />			<span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">HTTP Error Response: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>response<span class="token punctuation">.</span>status<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>response<span class="token punctuation">.</span>statusText<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span><br />			<span class="token operator">...</span>args<br />		<span class="token punctuation">)</span><span class="token punctuation">;</span><br />		<span class="token keyword">this</span><span class="token punctuation">.</span>response <span class="token operator">=</span> response<span class="token punctuation">;</span><br />	<span class="token punctuation">}</span><br /><span class="token punctuation">}</span><br /><br /><span class="token keyword">const</span> <span class="token function-variable function">checkStatus</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">response</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />	<span class="token keyword">if</span> <span class="token punctuation">(</span>response<span class="token punctuation">.</span>ok<span class="token punctuation">)</span> <span class="token punctuation">{</span><br />		<span class="token comment">// response.status >= 200 &amp;&amp; response.status &lt; 300</span><br />		<span class="token keyword">return</span> response<span class="token punctuation">;</span><br />	<span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span><br />		<span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">HTTPResponseError</span><span class="token punctuation">(</span>response<span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token punctuation">}</span><br /><span class="token punctuation">}</span><span class="token punctuation">;</span><br /><br /><span class="token keyword">const</span> <span class="token function-variable function">fetchUrl</span> <span class="token operator">=</span> <span class="token keyword">async</span> <span class="token punctuation">(</span><span class="token parameter">url<span class="token punctuation">,</span> options <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">,</span> ua <span class="token operator">=</span> <span class="token boolean">true</span></span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />	<span class="token keyword">let</span> response <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">;</span><br />	<span class="token keyword">let</span> finalOptions <span class="token operator">=</span> options<br />		<span class="token operator">?</span> options<br />		<span class="token operator">:</span> <span class="token punctuation">{</span><br />				<span class="token literal-property property">method</span><span class="token operator">:</span> <span class="token string">"get"</span><span class="token punctuation">,</span><br />		  <span class="token punctuation">}</span><span class="token punctuation">;</span><br />	<span class="token keyword">if</span> <span class="token punctuation">(</span>ua<span class="token punctuation">)</span> <span class="token punctuation">{</span><br />		finalOptions<span class="token punctuation">.</span>header <span class="token operator">=</span> ua <span class="token operator">===</span> <span class="token boolean">true</span> <span class="token operator">?</span> ua <span class="token operator">:</span> <span class="token function">getRequestHeaders</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token punctuation">}</span><br />	<span class="token keyword">try</span> <span class="token punctuation">{</span><br />		response <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token function">fetch</span><span class="token punctuation">(</span>url<span class="token punctuation">,</span> finalOptions<span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span>e<span class="token punctuation">)</span> <span class="token punctuation">{</span><br />		<span class="token keyword">if</span> <span class="token punctuation">(</span>e<span class="token punctuation">.</span><span class="token function">hasOwnProperty</span><span class="token punctuation">(</span><span class="token string">"response"</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />			console<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span><span class="token string">"Fetch Error in response"</span><span class="token punctuation">,</span> e<span class="token punctuation">.</span>response<span class="token punctuation">.</span><span class="token function">text</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />		<span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>e<span class="token punctuation">.</span>code <span class="token operator">==</span> <span class="token string">"ENOTFOUND"</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />			console<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span><span class="token string">"URL Does Not Exist"</span><span class="token punctuation">,</span> e<span class="token punctuation">)</span><span class="token punctuation">;</span><br />		<span class="token punctuation">}</span><br />		<span class="token keyword">return</span> <span class="token boolean">false</span><span class="token punctuation">;</span><br />	<span class="token punctuation">}</span><br />	response <span class="token operator">=</span> <span class="token function">checkStatus</span><span class="token punctuation">(</span>response<span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token keyword">return</span> response<span class="token punctuation">;</span><br /><span class="token punctuation">}</span><span class="token punctuation">;</span><br /><br />module<span class="token punctuation">.</span>exports <span class="token operator">=</span> fetchUrl<span class="token punctuation">;</span></code></pre>
<p id="code-skip-day-5-1">Ok, that works! I am getting a 200 back, implying that it is being archived. Yeah, <a href="https://web.archive.org/web/*/http://blog.aramzs.me/" target="_blank">when I check the archive page for me test link it is working</a>!</p>
<p><a target="_blank" href="https://github.com/AramZS/contexter/commit/640f178f20e3bd2bb420ea97a0096bed933bd49d" class="git-commit-link"><code>git commit -am &quot;Set up for further archiving and abstract fetch tools. Send links to Wayback Machine&quot;</code></a></p>
]]></content:encoded>
	</item>
	
	<item>
		<title>Day 4: Getting links archived - research spike</title>
		<link>https://fightwithtools.dev/posts/projects/context-pages/day-4-running-archives/?source=rss</link>
		<pubDate>Wed, 12 Jan 2022 02:59:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/projects/context-pages/day-4-running-archives/</guid>
		<description>I want to share lists of links, but make them readable and archived</description>
		<content:encoded><![CDATA[<h2 id="project-scope-and-todos" tabindex="-1">Project Scope and ToDos</h2>
<ol>
<li>Take a link and turn it into an oEmbed/Open Graph style share card</li>
<li>Take a link and archive it in the most reliable way</li>
<li>When the link is a tweet, display the tweet but also the whole tweet thread.</li>
<li>When the link is a tweet, archive the tweets, and display them if the live ones are not available.</li>
<li>Capture any embedded retweets in the thread. Capture their thread if one exists</li>
<li>Capture any links in the Tweet</li>
<li>Create the process as an abstract function that returns the data in a savable way</li>
</ol>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Archive links on <a href="http://archive.org/" target="_blank">Archive.org</a> and save the resulting archival links</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Create link IDs that can be used to cache related content</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Integrate it into the site to be able to make context pages here.</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Check if a link is still available at build time and rebuild the block with links to an archived link</li>
</ul>
<h2 id="day-4" tabindex="-1">Day 4</h2>
<p>Ok, now that I have a sane link and metadata, I want to archive the links in a useful way and take that archive link and make it available. I <a href="https://github.com/epaulson/liquid_link_archiver" target="_blank">thought a little more about this in public and got an example approach in Python</a>.</p>
<p><a href="https://github.com/california-civic-data-coalition/django-internetarchive-storage/blob/master/ia_storage/storage.py" target="_blank">Looking at other work in the space</a> I'll need to walk my generated metadata object and get specific metadata values to set as the main version of those values for the archive. If I want to set this up so it can be locally archived by users It'll also be useful to look at <a href="https://pastpages.org/" target="_blank">current work on this process</a> in <a href="https://django-memento-framework.readthedocs.io/en/latest/" target="_blank">Python</a> and <a href="https://wordpress-memento-plugin.readthedocs.io/en/latest/" target="_blank">PHP</a>. It looks like there are <a href="https://github.com/machawk1/awesome-memento" target="_blank">some existing tools that also</a> <a href="http://www.mementoweb.org/tools/" target="_blank">might be useful to reference</a>. There's even <a href="https://github.com/qvint/archive.is" target="_blank">a rather old but still useful archive.is package</a>. Some people have <a href="https://twitter.com/Yahel/status/1481087744780738562" target="_blank">even talked about</a> taking <a href="https://splinter.readthedocs.io/en/latest/screenshot.html" target="_blank">screenshots</a>.</p>
<p>Let's start with <a href="http://archive.is/" target="_blank">Archive.is</a>. Trying the preexisting package seems easiest and the code within seems pretty straightforward, very similar to the Python API I was looking at.</p>
<p>We'll find out if the package still works, very simple if so, though I'm adapting it to use async/await. We'll see how that goes:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/context-pages/day-4-running-archives/#code-skip-day-4-running-archives-2" id="skip-to-code-skip-day-4-running-archives-2" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> <span class="token function-variable function">pushToArchiveIs</span> <span class="token operator">=</span> <span class="token keyword">async</span> <span class="token punctuation">(</span><span class="token parameter">url</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />	<span class="token comment">// Based on https://github.com/palewire/archiveis/blob/master/archiveis/api.py</span><br />	<span class="token keyword">const</span> archiveTool <span class="token operator">=</span> <span class="token string">"https://archive.is"</span><span class="token punctuation">;</span><br />	<span class="token keyword">const</span> archivingPath <span class="token operator">=</span> <span class="token string">"/submit/"</span><span class="token punctuation">;</span><br />	<span class="token keyword">const</span> saveUrl <span class="token operator">=</span> archiveTool <span class="token operator">+</span> archivingPath<span class="token punctuation">;</span><br /><br />	<span class="token keyword">let</span> result <span class="token operator">=</span> <span class="token keyword">await</span> archiveIs<span class="token punctuation">.</span><span class="token function">save</span><span class="token punctuation">(</span>url<span class="token punctuation">)</span><span class="token punctuation">;</span><br />	console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>result<span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token keyword">return</span> result<span class="token punctuation">;</span><br /><span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
<p id="code-skip-day-4-running-archives-2">Well, wrote a test and it doesn't seem to work.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/context-pages/day-4-running-archives/#code-skip-day-4-running-archives-1" id="skip-to-code-skip-day-4-running-archives-1" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript"><span class="token function">it</span><span class="token punctuation">(</span><span class="token string">"should send a URL to archive.is"</span><span class="token punctuation">,</span> <span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />			<span class="token keyword">const</span> result <span class="token operator">=</span> <span class="token keyword">await</span> linkModule<span class="token punctuation">.</span><span class="token function">pushToArchiveIs</span><span class="token punctuation">(</span><br />				<span class="token string">"https://blog.aramzs.me"</span><br />			<span class="token punctuation">)</span><span class="token punctuation">;</span><br />			result<span class="token punctuation">.</span>shortUrl<span class="token punctuation">.</span>should<span class="token punctuation">.</span><span class="token function">equal</span><span class="token punctuation">(</span><span class="token string">""</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />		<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p id="code-skip-day-4-running-archives-1">Results in <code>TooManyRequestsError: Too Many Requests</code> no matter what URL I put in. So I guess the module doesn't work.</p>
<p>Ok, now I know. I wonder if I can fix it? I guess that's for the next day I work on this. Today was mostly about research and reading.</p>
<p><a target="_blank" href="https://github.com/AramZS/contexter/commit/348e79abd173766d7cab72eec585c567bf30d0fc" class="git-commit-link"><code>git commit -am &quot;Set up archiver and test archive.is module (it failed)&quot;</code></a></p>
]]></content:encoded>
	</item>
	
	<item>
		<title>Day 3: Wrestling with OEmbed and Metadata</title>
		<link>https://fightwithtools.dev/posts/projects/context-pages/day-3-wrestling-oembed-link-metadata/?source=rss</link>
		<pubDate>Mon, 10 Jan 2022 02:59:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/projects/context-pages/day-3-wrestling-oembed-link-metadata/</guid>
		<description>I want to share lists of links, but make them readable and archived</description>
		<content:encoded><![CDATA[<h2 id="project-scope-and-todos" tabindex="-1">Project Scope and ToDos</h2>
<ol>
<li>Take a link and turn it into an oEmbed/Open Graph style share card</li>
<li>Take a link and archive it in the most reliable way</li>
<li>When the link is a tweet, display the tweet but also the whole tweet thread.</li>
<li>When the link is a tweet, archive the tweets, and display them if the live ones are not available.</li>
<li>Capture any embedded retweets in the thread. Capture their thread if one exists</li>
<li>Capture any links in the Tweet</li>
<li>Create the process as an abstract function that returns the data in a savable way</li>
</ol>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Archive links on <a href="http://archive.org/" target="_blank">Archive.org</a> and save the resulting archival links</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Create link IDs that can be used to cache related content</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Integrate it into the site to be able to make context pages here.</li>
</ul>
<h2 id="day-3" tabindex="-1">Day 3</h2>
<p>Ok, yesterday I was trying to knock down the oEmbed process from Facebook and getting nothing. Let's take this back to base principles and see if I can make a request outside of Node that gets what I need</p>
<p>Ok, it looks like I don't have the right permissions for my Facebook app? Sort of taking the o out of oEmbed if I need an app, permissions and a key isn't it Facebook?</p>
<p>Ok, to get the oEmbed process working I need to have my App verified on Facebook... which means uploading a photo of my government provided ID? Nope, fk that. Ok, just no Facebook oembeds in this process then.</p>
<p>Ok, let's grab the page data that tells us about a post now. To do that, I'm going to use a classic package I've done some work in before: JSDOM.</p>
<p>JSDOM can do its own requests, but I would prefer to handle that as a separate step.</p>
<p>First I'm going to build a basic object that can contain data about the page that should be useful. I want to predefine a few namespaces I would use. Let's pull <a href="https://aramzs.github.io/jekyll/social-media/2015/11/11/be-social-with-jekyll.html" target="_blank">the standard stuff from the meta tags</a> and <a href="https://aramzs.github.io/jekyll/schema-dot-org/2018/04/27/how-to-make-your-jekyll-site-structured.html" target="_blank">JSON-LD</a>. I can also use <a href="https://en.wikipedia.org/wiki/Dublin_Core#Levels_of_the_standard" target="_blank">Dublin Core potentially</a>. I <a href="https://microformats.org/wiki/h-card" target="_blank">can also use h-card</a> <a href="https://indieweb.org/h-card" target="_blank">perhaps</a> or <a href="https://indieweb.org/authorship" target="_blank">h-entry</a>? We can try that out at some later point.</p>
<p>Ok, so once I have the DOM set up how can I grab the data I need?</p>
<p>On the DOM object I can execute <code>window.document.getElementsByTagName(&quot;meta&quot;);</code> and get a list back. Interestingly tags using the <code>name</code> property are accessible on the resulting object by name. For OpenGraph we can use <a href="https://stackoverflow.com/questions/8714090/queryselector-wildcard-element-match" target="_blank">a wildcard search</a> of <code>querySelectorAll</code>.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/context-pages/day-3-wrestling-oembed-link-metadata/#code-skip-day-3-wrestling-oembed-link-metadata-6" id="skip-to-code-skip-day-3-wrestling-oembed-link-metadata-6" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> openGraphNodes <span class="token operator">=</span> window<span class="token punctuation">.</span>document<span class="token punctuation">.</span><span class="token function">querySelectorAll</span><span class="token punctuation">(</span><br />	<span class="token string">"meta[property^='og:']"</span><br /><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p id="code-skip-day-3-wrestling-oembed-link-metadata-6">Ok, so I need to set up some tests to make sure it is working as expected.</p>
<p>Can I use <code>to.equal</code> in mocha?</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/context-pages/day-3-wrestling-oembed-link-metadata/#code-skip-day-3-wrestling-oembed-link-metadata-5" id="skip-to-code-skip-day-3-wrestling-oembed-link-metadata-5" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript">result<span class="token punctuation">.</span>metadata<span class="token punctuation">.</span>keyvalues<span class="token punctuation">.</span><span class="token function">equal</span><span class="token punctuation">(</span><span class="token punctuation">[</span><br />	<span class="token string">"jekyll"</span><span class="token punctuation">,</span><br />	<span class="token string">"social-media"</span><span class="token punctuation">,</span><br /><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p id="code-skip-day-3-wrestling-oembed-link-metadata-5">Apparently not.</p>
<p>Ok, did some searching around and <a href="https://stackoverflow.com/questions/41726208/chai-testing-for-values-in-array-of-objects" target="_blank">it looks like the right way to handle this</a>:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/context-pages/day-3-wrestling-oembed-link-metadata/#code-skip-day-3-wrestling-oembed-link-metadata-4" id="skip-to-code-skip-day-3-wrestling-oembed-link-metadata-4" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript"><span class="token function">expect</span><span class="token punctuation">(</span>result<span class="token punctuation">.</span>metadata<span class="token punctuation">.</span>keyvalues<span class="token punctuation">)</span><span class="token punctuation">.</span>to<span class="token punctuation">.</span>have<span class="token punctuation">.</span><span class="token function">members</span><span class="token punctuation">(</span><span class="token punctuation">[</span><br />	<span class="token string">"jekyll"</span><span class="token punctuation">,</span><br />	<span class="token string">"social-media"</span><span class="token punctuation">,</span><br /><span class="token punctuation">]</span><span class="token punctuation">)</span></code></pre>
<p id="code-skip-day-3-wrestling-oembed-link-metadata-4">Ok, things are working. But I think I can make this better code by simplifying and abstracting the functions around the <code>querySelector</code>. There OpenGraph and Twitter based meta values are all based on RDF and we can analyze them in a similar way.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/context-pages/day-3-wrestling-oembed-link-metadata/#code-skip-day-3-wrestling-oembed-link-metadata-3" id="skip-to-code-skip-day-3-wrestling-oembed-link-metadata-3" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> <span class="token function-variable function">pullMetadataFromRDFProperty</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">documentObj<span class="token punctuation">,</span> topNode</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />	<span class="token keyword">const</span> graphNodes <span class="token operator">=</span> documentObj<span class="token punctuation">.</span><span class="token function">querySelectorAll</span><span class="token punctuation">(</span><br />		<span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">meta[property^='</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>topNode<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">:']</span><span class="token template-punctuation string">`</span></span><br />	<span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token keyword">const</span> openGraphObject <span class="token operator">=</span> Array<span class="token punctuation">.</span><span class="token function">from</span><span class="token punctuation">(</span>graphNodes<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">reduce</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">prev<span class="token punctuation">,</span> curr</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />		<span class="token keyword">const</span> keyValue <span class="token operator">=</span> curr<span class="token punctuation">.</span>attributes<br />			<span class="token punctuation">.</span><span class="token function">item</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span><br />			<span class="token punctuation">.</span>nodeValue<span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>topNode<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">:</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span> <span class="token string">""</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />		<span class="token keyword">if</span> <span class="token punctuation">(</span>prev<span class="token punctuation">.</span><span class="token function">hasOwnProperty</span><span class="token punctuation">(</span>keyValue<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />			<span class="token keyword">const</span> lastValue <span class="token operator">=</span> prev<span class="token punctuation">[</span>keyValue<span class="token punctuation">]</span><span class="token punctuation">;</span><br />			<span class="token keyword">if</span> <span class="token punctuation">(</span>Array<span class="token punctuation">.</span><span class="token function">isArray</span><span class="token punctuation">(</span>lastValue<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />				prev<span class="token punctuation">[</span>keyValue<span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span>curr<span class="token punctuation">.</span>content<span class="token punctuation">)</span><span class="token punctuation">;</span><br />			<span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span><br />				prev<span class="token punctuation">[</span>keyValue<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token punctuation">[</span>lastValue<span class="token punctuation">,</span> curr<span class="token punctuation">.</span>content<span class="token punctuation">]</span><span class="token punctuation">;</span><br />			<span class="token punctuation">}</span><br />		<span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span><br />			prev<span class="token punctuation">[</span>keyValue<span class="token punctuation">]</span> <span class="token operator">=</span> curr<span class="token punctuation">.</span>content<span class="token punctuation">;</span><br />		<span class="token punctuation">}</span><br />		<span class="token keyword">return</span> prev<span class="token punctuation">;</span><br />	<span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token comment">// console.log("openGraphObject", openGraphObject);</span><br />	<span class="token keyword">return</span> openGraphObject<span class="token punctuation">;</span><br /><span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
<p id="code-skip-day-3-wrestling-oembed-link-metadata-3"><a target="_blank" href="https://github.com/AramZS/contexter/commit/86f38d2528212411a27644c1e0ff4423d0c846fd" class="git-commit-link"><code>git commit -am &quot;Setting up scrape of OpenGraph data and supporting unit tests&quot;</code></a></p>
<p>Now I can use this function to capture the Twitter metadata as well!</p>
<p><a target="_blank" href="https://github.com/AramZS/contexter/commit/12b3775646157162049a771a46a8843169d909bc" class="git-commit-link"><code>git commit -am &quot;Setting up scrape of twitter data&quot;</code></a></p>
<p>Oh wait, I need to account for the fact that some tags are using <code>name</code> and some are using <code>property</code>.</p>
<p><a target="_blank" href="https://github.com/AramZS/contexter/commit/b5ed2079a6b000bb32067748735824bf6a60571a" class="git-commit-link"><code>git commit -am &quot;Fix pullMetadataFromRDFProperty to have a prop type&quot;</code></a></p>
<p>A few more modifications and I can get it to capture DublinCore if available as well.</p>
<p>I can even build some tests to prove some negative cases. That should be useful for more comprehensive testing.</p>
<p>Basically this should allow me to compose a bunch of different tests with different HTML.</p>
<p><a target="_blank" href="https://github.com/AramZS/contexter/commit/42fb1e5e426286c8536d5f285042074de4f1e141" class="git-commit-link"><code>git commit -am &quot;More extensive test coverage&quot;</code></a></p>
<p>Looking good. Now I want to test it end to end.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/context-pages/day-3-wrestling-oembed-link-metadata/#code-skip-day-3-wrestling-oembed-link-metadata-2" id="skip-to-code-skip-day-3-wrestling-oembed-link-metadata-2" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript">	<span class="token function">describe</span><span class="token punctuation">(</span><span class="token string">"should create link objects from a domain requests"</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />		<span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">timeout</span><span class="token punctuation">(</span><span class="token number">5000</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />		<span class="token function">it</span><span class="token punctuation">(</span><span class="token string">"should resolve a basic URL"</span><span class="token punctuation">,</span> <span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />			<span class="token keyword">const</span> result <span class="token operator">=</span> <span class="token keyword">await</span> linkModule<span class="token punctuation">.</span><span class="token function">getLinkData</span><span class="token punctuation">(</span><span class="token punctuation">{</span><br />				<span class="token literal-property property">sanitizedLink</span><span class="token operator">:</span><br />					<span class="token string">"http://aramzs.github.io/jekyll/social-media/2015/11/11/be-social-with-jekyll.html"</span><span class="token punctuation">,</span><br />				<span class="token literal-property property">link</span><span class="token operator">:</span> <span class="token string">"http://aramzs.github.io/jekyll/social-media/2015/11/11/be-social-with-jekyll.html"</span><span class="token punctuation">,</span><br />			<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />			result<span class="token punctuation">.</span>status<span class="token punctuation">.</span>should<span class="token punctuation">.</span><span class="token function">equal</span><span class="token punctuation">(</span><span class="token number">200</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />			result<span class="token punctuation">.</span>metadata<span class="token punctuation">.</span>title<span class="token punctuation">.</span>should<span class="token punctuation">.</span><span class="token function">equal</span><span class="token punctuation">(</span><br />				<span class="token string">"How to make your Jekyll site show up on social"</span><br />			<span class="token punctuation">)</span><span class="token punctuation">;</span><br />			result<span class="token punctuation">.</span>metadata<span class="token punctuation">.</span>author<span class="token punctuation">.</span>should<span class="token punctuation">.</span><span class="token function">equal</span><span class="token punctuation">(</span><span class="token string">"Aram Zucker-Scharff"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />			result<span class="token punctuation">.</span>metadata<span class="token punctuation">.</span>description<span class="token punctuation">.</span>should<span class="token punctuation">.</span><span class="token function">equal</span><span class="token punctuation">(</span><br />				<span class="token string">"Here's how to make Jekyll posts easier for others to see and share on social networks."</span><br />			<span class="token punctuation">)</span><span class="token punctuation">;</span><br />			result<span class="token punctuation">.</span>metadata<span class="token punctuation">.</span>canonical<span class="token punctuation">.</span>should<span class="token punctuation">.</span><span class="token function">equal</span><span class="token punctuation">(</span><br />				<span class="token string">"http://aramzs.github.io/jekyll/social-media/2015/11/11/be-social-with-jekyll.html"</span><br />			<span class="token punctuation">)</span><span class="token punctuation">;</span><br />			<span class="token function">expect</span><span class="token punctuation">(</span>result<span class="token punctuation">.</span>metadata<span class="token punctuation">.</span>keywords<span class="token punctuation">)</span><span class="token punctuation">.</span>to<span class="token punctuation">.</span>have<span class="token punctuation">.</span><span class="token function">members</span><span class="token punctuation">(</span><span class="token punctuation">[</span><br />				<span class="token string">"jekyll"</span><span class="token punctuation">,</span><br />				<span class="token string">"social-media"</span><span class="token punctuation">,</span><br />			<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />			result<span class="token punctuation">.</span>opengraph<span class="token punctuation">.</span>title<span class="token punctuation">.</span>should<span class="token punctuation">.</span><span class="token function">equal</span><span class="token punctuation">(</span><br />				<span class="token string">"How to make your Jekyll site show up on social"</span><br />			<span class="token punctuation">)</span><span class="token punctuation">;</span><br />			result<span class="token punctuation">.</span>opengraph<span class="token punctuation">.</span>locale<span class="token punctuation">.</span>should<span class="token punctuation">.</span><span class="token function">equal</span><span class="token punctuation">(</span><span class="token string">"en_US"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />			result<span class="token punctuation">.</span>opengraph<span class="token punctuation">.</span>description<span class="token punctuation">.</span>should<span class="token punctuation">.</span><span class="token function">equal</span><span class="token punctuation">(</span><br />				<span class="token string">"Here's how to make Jekyll posts easier for others to see and share on social networks."</span><br />			<span class="token punctuation">)</span><span class="token punctuation">;</span><br />			result<span class="token punctuation">.</span>opengraph<span class="token punctuation">.</span>url<span class="token punctuation">.</span>should<span class="token punctuation">.</span><span class="token function">equal</span><span class="token punctuation">(</span><br />				<span class="token string">"http://aramzs.github.io/jekyll/social-media/2015/11/11/be-social-with-jekyll.html"</span><br />			<span class="token punctuation">)</span><span class="token punctuation">;</span><br />			result<span class="token punctuation">.</span>twitter<span class="token punctuation">.</span>card<span class="token punctuation">.</span>should<span class="token punctuation">.</span><span class="token function">equal</span><span class="token punctuation">(</span><span class="token string">"summary_large_image"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />			result<span class="token punctuation">.</span>twitter<span class="token punctuation">.</span>creator<span class="token punctuation">.</span>should<span class="token punctuation">.</span><span class="token function">equal</span><span class="token punctuation">(</span><span class="token string">"@chronotope"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />			result<span class="token punctuation">.</span>twitter<span class="token punctuation">.</span>title<span class="token punctuation">.</span>should<span class="token punctuation">.</span><span class="token function">equal</span><span class="token punctuation">(</span><br />				<span class="token string">"How to make your Jekyll site show up on social"</span><br />			<span class="token punctuation">)</span><span class="token punctuation">;</span><br />			result<span class="token punctuation">.</span>twitter<span class="token punctuation">.</span>image<span class="token punctuation">.</span>should<span class="token punctuation">.</span><span class="token function">equal</span><span class="token punctuation">(</span><br />				<span class="token string">"https://raw.githubusercontent.com/AramZS/aramzs.github.io/master/_includes/tumblr_nwncf1T2ht1rl195mo1_1280.jpg"</span><br />			<span class="token punctuation">)</span><span class="token punctuation">;</span><br />			result<span class="token punctuation">.</span>dublinCore<span class="token punctuation">.</span>Format<span class="token punctuation">.</span>should<span class="token punctuation">.</span><span class="token function">equal</span><span class="token punctuation">(</span><span class="token string">"video/mpeg; 10 minutes"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />			result<span class="token punctuation">.</span>dublinCore<span class="token punctuation">.</span>Language<span class="token punctuation">.</span>should<span class="token punctuation">.</span><span class="token function">equal</span><span class="token punctuation">(</span><span class="token string">"en"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />			result<span class="token punctuation">.</span>dublinCore<span class="token punctuation">.</span>Publisher<span class="token punctuation">.</span>should<span class="token punctuation">.</span><span class="token function">equal</span><span class="token punctuation">(</span><span class="token string">"publisher-name"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />			result<span class="token punctuation">.</span>dublinCore<span class="token punctuation">.</span>Title<span class="token punctuation">.</span>should<span class="token punctuation">.</span><span class="token function">equal</span><span class="token punctuation">(</span><span class="token string">"HYP"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />			result<span class="token punctuation">.</span>jsonLd<span class="token punctuation">[</span><span class="token string">"@type"</span><span class="token punctuation">]</span><span class="token punctuation">.</span>should<span class="token punctuation">.</span><span class="token function">equal</span><span class="token punctuation">(</span><span class="token string">"BlogPosting"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />			result<span class="token punctuation">.</span>jsonLd<span class="token punctuation">.</span>headline<span class="token punctuation">.</span>should<span class="token punctuation">.</span><span class="token function">equal</span><span class="token punctuation">(</span><br />				<span class="token string">"How to make your Jekyll site show up on social"</span><br />			<span class="token punctuation">)</span><span class="token punctuation">;</span><br />			result<span class="token punctuation">.</span>jsonLd<span class="token punctuation">.</span>description<span class="token punctuation">.</span>should<span class="token punctuation">.</span><span class="token function">equal</span><span class="token punctuation">(</span><br />				<span class="token string">"Here's how to make Jekyll posts easier for others to see and share on social networks."</span><br />			<span class="token punctuation">)</span><span class="token punctuation">;</span><br />			<span class="token function">expect</span><span class="token punctuation">(</span>result<span class="token punctuation">.</span>jsonLd<span class="token punctuation">.</span>image<span class="token punctuation">)</span><span class="token punctuation">.</span>to<span class="token punctuation">.</span>have<span class="token punctuation">.</span><span class="token function">members</span><span class="token punctuation">(</span><span class="token punctuation">[</span><br />				<span class="token string">"https://raw.githubusercontent.com/AramZS/aramzs.github.io/master/_includes/tumblr_nwncf1T2ht1rl195mo1_1280.jpg"</span><span class="token punctuation">,</span><br />			<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />		<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p id="code-skip-day-3-wrestling-oembed-link-metadata-2">Oh, I forgot, I need to await <code>response.text()</code>!</p>
<p>Ok, a few more tweaks and a reminder that I don't have Dublin Core on my actual site and it should be good to go.</p>
<p><a target="_blank" href="https://github.com/AramZS/contexter/commit/152cecd946499b8375e00e37ab09fcfffb0de1e1" class="git-commit-link"><code>git commit -am &quot;End to end unit test for building a link object&quot; </code></a></p>
<p>Now I have a good looking data object I can use to build context cards:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/context-pages/day-3-wrestling-oembed-link-metadata/#code-skip-day-3-wrestling-oembed-link-metadata-1" id="skip-to-code-skip-day-3-wrestling-oembed-link-metadata-1" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript"><span class="token punctuation">{</span><br />  <span class="token literal-property property">originalLink</span><span class="token operator">:</span> <span class="token string">'http://aramzs.github.io/jekyll/social-media/2015/11/11/be-social-with-jekyll.html'</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">sanitizedLink</span><span class="token operator">:</span> <span class="token string">'http://aramzs.github.io/jekyll/social-media/2015/11/11/be-social-with-jekyll.html'</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">oembed</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">jsonLd</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />    <span class="token string-property property">'@type'</span><span class="token operator">:</span> <span class="token string">'BlogPosting'</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">headline</span><span class="token operator">:</span> <span class="token string">'How to make your Jekyll site show up on social'</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">description</span><span class="token operator">:</span> <span class="token string">"Here's how to make Jekyll posts easier for others to see and share on social networks."</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">image</span><span class="token operator">:</span> <span class="token punctuation">[</span><br />      <span class="token string">'https://raw.githubusercontent.com/AramZS/aramzs.github.io/master/_includes/tumblr_nwncf1T2ht1rl195mo1_1280.jpg'</span><br />    <span class="token punctuation">]</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">mainEntityOfPage</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />      <span class="token string-property property">'@type'</span><span class="token operator">:</span> <span class="token string">'WebPage'</span><span class="token punctuation">,</span><br />      <span class="token string-property property">'@id'</span><span class="token operator">:</span> <span class="token string">'http://aramzs.github.io/jekyll/social-media/2015/11/11/be-social-with-jekyll.html'</span><br />    <span class="token punctuation">}</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">datePublished</span><span class="token operator">:</span> <span class="token string">'2015-11-11 10:34:51 -0500'</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">dateModified</span><span class="token operator">:</span> <span class="token string">'2015-11-11 10:34:51 -0500'</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">isAccessibleForFree</span><span class="token operator">:</span> <span class="token string">'True'</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">isPartOf</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />      <span class="token string-property property">'@type'</span><span class="token operator">:</span> <span class="token punctuation">[</span> <span class="token string">'CreativeWork'</span><span class="token punctuation">,</span> <span class="token string">'Product'</span><span class="token punctuation">,</span> <span class="token string">'Blog'</span> <span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'Fight With Tools'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">productID</span><span class="token operator">:</span> <span class="token string">'aramzs.github.io'</span><br />    <span class="token punctuation">}</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">discussionUrl</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">license</span><span class="token operator">:</span> <span class="token string">'http://creativecommons.org/licenses/by-sa/4.0/'</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">author</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />      <span class="token string-property property">'@type'</span><span class="token operator">:</span> <span class="token string">'Person'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'Aram Zucker-Scharff'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">description</span><span class="token operator">:</span> <span class="token string">'Aram Zucker-Scharff is Director for Ad Engineering at Washington Post, lead dev for PressForward and a consultant. Tech solutions for journo problems.'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">sameAs</span><span class="token operator">:</span> <span class="token string">'http://aramzs.github.io/aramzs/'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">image</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />        <span class="token string-property property">'@type'</span><span class="token operator">:</span> <span class="token string">'ImageObject'</span><span class="token punctuation">,</span><br />        <span class="token literal-property property">url</span><span class="token operator">:</span> <span class="token string">'https://raw.githubusercontent.com/AramZS/aramzs.github.io/master/_includes/Aram-Zucker-Scharff-square.jpg'</span><br />      <span class="token punctuation">}</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">givenName</span><span class="token operator">:</span> <span class="token string">'Aram'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">familyName</span><span class="token operator">:</span> <span class="token string">'Zucker-Scharff'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">alternateName</span><span class="token operator">:</span> <span class="token string">'AramZS'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">publishingPrinciples</span><span class="token operator">:</span> <span class="token string">'http://aramzs.github.io/about/'</span><br />    <span class="token punctuation">}</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">publisher</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />      <span class="token string-property property">'@type'</span><span class="token operator">:</span> <span class="token string">'Organization'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'Fight With Tools'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">description</span><span class="token operator">:</span> <span class="token string">"A site discussing how to imagine, build, analyze and use cool code and web tools. Better websites, better stories, better developers. Technology won't save the world, but you can."</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">sameAs</span><span class="token operator">:</span> <span class="token string">'http://aramzs.github.io'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">logo</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />        <span class="token string-property property">'@type'</span><span class="token operator">:</span> <span class="token string">'ImageObject'</span><span class="token punctuation">,</span><br />        <span class="token literal-property property">url</span><span class="token operator">:</span> <span class="token string">'https://41.media.tumblr.com/709bb3c371b9924add351bfe3386e946/tumblr_nxdq8uFdx81qzocgko1_1280.jpg'</span><br />      <span class="token punctuation">}</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">publishingPrinciples</span><span class="token operator">:</span> <span class="token string">'http://aramzs.github.io/about/'</span><br />    <span class="token punctuation">}</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">editor</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />      <span class="token string-property property">'@type'</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">description</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">sameAs</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">image</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token string-property property">'@type'</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span> <span class="token literal-property property">url</span><span class="token operator">:</span> <span class="token boolean">false</span> <span class="token punctuation">}</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">givenName</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">familyName</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">alternateName</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">publishingPrinciples</span><span class="token operator">:</span> <span class="token boolean">false</span><br />    <span class="token punctuation">}</span><span class="token punctuation">,</span><br />    <span class="token string-property property">'@context'</span><span class="token operator">:</span> <span class="token string">'http://schema.org'</span><br />  <span class="token punctuation">}</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">status</span><span class="token operator">:</span> <span class="token number">200</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">metadata</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />    <span class="token literal-property property">author</span><span class="token operator">:</span> <span class="token string">'Aram Zucker-Scharff'</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">title</span><span class="token operator">:</span> <span class="token string">'How to make your Jekyll site show up on social'</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">description</span><span class="token operator">:</span> <span class="token string">"Here's how to make Jekyll posts easier for others to see and share on social networks."</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">canonical</span><span class="token operator">:</span> <span class="token string">'http://aramzs.github.io/jekyll/social-media/2015/11/11/be-social-with-jekyll.html'</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">keywords</span><span class="token operator">:</span> <span class="token punctuation">[</span> <span class="token string">'jekyll'</span><span class="token punctuation">,</span> <span class="token string">'social-media'</span> <span class="token punctuation">]</span><br />  <span class="token punctuation">}</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">dublinCore</span><span class="token operator">:</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">opengraph</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />    <span class="token literal-property property">title</span><span class="token operator">:</span> <span class="token string">'How to make your Jekyll site show up on social'</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">description</span><span class="token operator">:</span> <span class="token string">"Here's how to make Jekyll posts easier for others to see and share on social networks."</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">url</span><span class="token operator">:</span> <span class="token string">'http://aramzs.github.io/jekyll/social-media/2015/11/11/be-social-with-jekyll.html'</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">site_name</span><span class="token operator">:</span> <span class="token string">'Fight With Tools by AramZS'</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">locale</span><span class="token operator">:</span> <span class="token string">'en_US'</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">type</span><span class="token operator">:</span> <span class="token string">'article'</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">typeObject</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />      <span class="token literal-property property">published_time</span><span class="token operator">:</span> <span class="token string">'2015-11-11 10:34:51 -0500'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">modified_time</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">author</span><span class="token operator">:</span> <span class="token string">'http://facebook.com/aramzs'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">publisher</span><span class="token operator">:</span> <span class="token string">'https://www.facebook.com/aramzs'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">section</span><span class="token operator">:</span> <span class="token string">'Code'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">tag</span><span class="token operator">:</span> <span class="token punctuation">[</span> <span class="token string">'jekyll'</span><span class="token punctuation">,</span> <span class="token string">'social-media'</span> <span class="token punctuation">]</span><br />    <span class="token punctuation">}</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">image</span><span class="token operator">:</span> <span class="token string">'https://raw.githubusercontent.com/AramZS/aramzs.github.io/master/_includes/tumblr_nwncf1T2ht1rl195mo1_1280.jpg'</span><br />  <span class="token punctuation">}</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">twitter</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />    <span class="token literal-property property">site</span><span class="token operator">:</span> <span class="token string">'@chronotope'</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">description</span><span class="token operator">:</span> <span class="token string">"Here's how to make Jekyll posts easier for others to see and share on social networks."</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">card</span><span class="token operator">:</span> <span class="token string">'summary_large_image'</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">creator</span><span class="token operator">:</span> <span class="token string">'@chronotope'</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">title</span><span class="token operator">:</span> <span class="token string">'How to make your Jekyll site show up on social'</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">image</span><span class="token operator">:</span> <span class="token string">'https://raw.githubusercontent.com/AramZS/aramzs.github.io/master/_includes/tumblr_nwncf1T2ht1rl195mo1_1280.jpg'</span><br />  <span class="token punctuation">}</span><br /><span class="token punctuation">}</span></code></pre>
]]></content:encoded>
	</item>
	
	<item>
		<title>Day 2: Building a tool to generate context pages</title>
		<link>https://fightwithtools.dev/posts/projects/context-pages/day-2/?source=rss</link>
		<pubDate>Sun, 09 Jan 2022 02:59:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/projects/context-pages/day-2/</guid>
		<description>I want to share lists of links, but make them readable and archived</description>
		<content:encoded><![CDATA[<h2 id="project-scope-and-todos" tabindex="-1">Project Scope and ToDos</h2>
<ol>
<li>Take a link and turn it into an oEmbed/Open Graph style share card</li>
<li>Take a link and archive it in the most reliable way</li>
<li>When the link is a tweet, display the tweet but also the whole tweet thread.</li>
<li>When the link is a tweet, archive the tweets, and display them if the live ones are not available.</li>
<li>Capture any embedded retweets in the thread. Capture their thread if one exists</li>
<li>Capture any links in the Tweet</li>
<li>Create the process as an abstract function that returns the data in a savable way</li>
</ol>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Archive links on <a href="http://archive.org/" target="_blank">Archive.org</a> and save the resulting archival links</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Create link IDs that can be used to cache related content</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Integrate it into the site to be able to make context pages here.</li>
</ul>
<h2 id="day-2" tabindex="-1">Day 2</h2>
<p>Ok, let's set up the request process. I want to retrieve the page so let's move forward on that as the next step.</p>
<p>Fetch is increasingly the way to handle HTTP requests in the browser, so it would be a good library to play with. Luckily there is a <a href="https://www.npmjs.com/package/node-fetch" target="_blank">Node Fetch library</a> I can leverage.</p>
<p>If I want to use fetch v3 it looks like this is how I have to go</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/context-pages/day-2/#code-skip-day-2-5" id="skip-to-code-skip-day-2-5" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> <span class="token function-variable function">fetch</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter"><span class="token operator">...</span>args</span><span class="token punctuation">)</span> <span class="token operator">=></span><br />	<span class="token keyword">import</span><span class="token punctuation">(</span><span class="token string">"node-fetch"</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> <span class="token keyword">default</span><span class="token operator">:</span> fetch <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token function">fetch</span><span class="token punctuation">(</span><span class="token operator">...</span>args<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>`</code></pre>
<p id="code-skip-day-2-5">The other thing I know from working on PressForward is that requests will often get blocked if they look too much like a bot, so it is helpful to purposefully identify yourself as a trusted bot. There's <a href="https://user-agents.net/lookup" target="_blank">a list of UAs that I could search</a>, but I know from experiance that the most successful User Agent is Facebook's, especially when I'm trying to retrieve page metadata. So let's start there.</p>
<p>I also want to check for errors.</p>
<p>Let's use the advised pattern on the module page to start with. The logic here is that a response can still be &quot;successful&quot; even if it comes back with an error code. Their pattern should be able to catch that.</p>
<p>Ok, here's my code now:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/context-pages/day-2/#code-skip-day-2-4" id="skip-to-code-skip-day-2-4" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript"><br /><span class="token keyword">const</span> <span class="token function-variable function">fetch</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter"><span class="token operator">...</span>args</span><span class="token punctuation">)</span> <span class="token operator">=></span><br />	<span class="token keyword">import</span><span class="token punctuation">(</span><span class="token string">"node-fetch"</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> <span class="token keyword">default</span><span class="token operator">:</span> fetch <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token function">fetch</span><span class="token punctuation">(</span><span class="token operator">...</span>args<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br /><span class="token keyword">const</span> ua <span class="token operator">=</span><br />	<span class="token string">"facebookexternalhit/1.1 (+http://www.facebook.com/externalhit_uatext.php)"</span><span class="token punctuation">;</span><br /><br /><span class="token keyword">const</span> <span class="token function-variable function">getRequestHeaders</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />	<span class="token keyword">return</span> <span class="token punctuation">{</span><br />		<span class="token literal-property property">cookie</span><span class="token operator">:</span> <span class="token string">""</span><span class="token punctuation">,</span><br />		<span class="token string-property property">"Accept-Language"</span><span class="token operator">:</span> <span class="token string">"en-US,en;q=0.8"</span><span class="token punctuation">,</span><br />		<span class="token string-property property">"User-Agent"</span><span class="token operator">:</span> ua<span class="token punctuation">,</span><br />	<span class="token punctuation">}</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span><span class="token punctuation">;</span><br /><br /><span class="token keyword">class</span> <span class="token class-name">HTTPResponseError</span> <span class="token keyword">extends</span> <span class="token class-name">Error</span> <span class="token punctuation">{</span><br />	<span class="token function">constructor</span><span class="token punctuation">(</span><span class="token parameter">response<span class="token punctuation">,</span> <span class="token operator">...</span>args</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />		<span class="token keyword">super</span><span class="token punctuation">(</span><br />			<span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">HTTP Error Response: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>response<span class="token punctuation">.</span>status<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>response<span class="token punctuation">.</span>statusText<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span><br />			<span class="token operator">...</span>args<br />		<span class="token punctuation">)</span><span class="token punctuation">;</span><br />		<span class="token keyword">this</span><span class="token punctuation">.</span>response <span class="token operator">=</span> response<span class="token punctuation">;</span><br />	<span class="token punctuation">}</span><br /><span class="token punctuation">}</span><br /><br /><span class="token keyword">const</span> <span class="token function-variable function">checkStatus</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">response</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />	<span class="token keyword">if</span> <span class="token punctuation">(</span>response<span class="token punctuation">.</span>ok<span class="token punctuation">)</span> <span class="token punctuation">{</span><br />		<span class="token comment">// response.status >= 200 &amp;&amp; response.status &lt; 300</span><br />		<span class="token keyword">return</span> response<span class="token punctuation">;</span><br />	<span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span><br />		<span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">HTTPResponseError</span><span class="token punctuation">(</span>response<span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token punctuation">}</span><br /><span class="token punctuation">}</span><span class="token punctuation">;</span><br /><br /><span class="token keyword">const</span> <span class="token function-variable function">fetchUrl</span> <span class="token operator">=</span> <span class="token keyword">async</span> <span class="token punctuation">(</span><span class="token parameter">url</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />	<span class="token keyword">try</span> <span class="token punctuation">{</span><br />		<span class="token keyword">const</span> response <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token function">fetch</span><span class="token punctuation">(</span>url<span class="token punctuation">,</span> <span class="token punctuation">{</span><br />			<span class="token literal-property property">method</span><span class="token operator">:</span> <span class="token string">"get"</span><span class="token punctuation">,</span><br />			<span class="token literal-property property">header</span><span class="token operator">:</span> <span class="token function">getRequestHeaders</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br />		<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span>e<span class="token punctuation">)</span> <span class="token punctuation">{</span><br />		console<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span><span class="token string">"Fetch Error"</span><span class="token punctuation">,</span> e<span class="token punctuation">.</span>response<span class="token punctuation">.</span><span class="token function">text</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token punctuation">}</span><br />	<span class="token function">checkStatus</span><span class="token punctuation">(</span>response<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
<p id="code-skip-day-2-4">Let's add this to the module export and see if some basic requests work. Let's make a basic request that we know will respond to the GitHub API. Getting the head of this project's main commit tree should work just fine. Let's request <code>https://api.github.com/repos/AramZS/devblog/git/refs/heads/main</code>.</p>
<p>Ok, so what does a fetch returned object look like?</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/context-pages/day-2/#code-skip-day-2-3" id="skip-to-code-skip-day-2-3" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript"><span class="token punctuation">{</span> <span class="token literal-property property">size</span><span class="token operator">:</span> <span class="token number">0</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">type</span><span class="token operator">:</span> <span class="token string">'default'</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">url</span><span class="token operator">:</span> <span class="token string">'https://api.github.com/repos/AramZS/devblog/git/refs/heads/main'</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">status</span><span class="token operator">:</span> <span class="token number">200</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">ok</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">redirected</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">statusText</span><span class="token operator">:</span> <span class="token string">'OK'</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">headers</span><span class="token operator">:</span><br />   <span class="token punctuation">{</span> <span class="token literal-property property">get</span><span class="token operator">:</span> <span class="token punctuation">[</span>Function<span class="token operator">:</span> get<span class="token punctuation">]</span><span class="token punctuation">,</span><br />     <span class="token literal-property property">forEach</span><span class="token operator">:</span> <span class="token punctuation">[</span>Function<span class="token operator">:</span> forEach<span class="token punctuation">]</span><span class="token punctuation">,</span><br />     <span class="token literal-property property">values</span><span class="token operator">:</span> <span class="token punctuation">[</span>Function<span class="token operator">:</span> values<span class="token punctuation">]</span><span class="token punctuation">,</span><br />     <span class="token literal-property property">entries</span><span class="token operator">:</span> <span class="token punctuation">[</span>Function<span class="token operator">:</span> entries<span class="token punctuation">]</span><span class="token punctuation">,</span><br />     <span class="token literal-property property">append</span><span class="token operator">:</span> <span class="token punctuation">[</span>Function<span class="token punctuation">]</span><span class="token punctuation">,</span><br />     <span class="token keyword">delete</span><span class="token operator">:</span> <span class="token punctuation">[</span>Function<span class="token punctuation">]</span><span class="token punctuation">,</span><br />     <span class="token literal-property property">getAll</span><span class="token operator">:</span> <span class="token punctuation">[</span>Function<span class="token punctuation">]</span><span class="token punctuation">,</span><br />     <span class="token literal-property property">has</span><span class="token operator">:</span> <span class="token punctuation">[</span>Function<span class="token punctuation">]</span><span class="token punctuation">,</span><br />     <span class="token literal-property property">set</span><span class="token operator">:</span> <span class="token punctuation">[</span>Function<span class="token punctuation">]</span><span class="token punctuation">,</span><br />     <span class="token literal-property property">sort</span><span class="token operator">:</span> <span class="token punctuation">[</span>Function<span class="token operator">:</span> sort<span class="token punctuation">]</span><span class="token punctuation">,</span><br />     <span class="token literal-property property">keys</span><span class="token operator">:</span> <span class="token punctuation">[</span>Function<span class="token punctuation">]</span> <span class="token punctuation">}</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">clone</span><span class="token operator">:</span> <span class="token punctuation">[</span>Function<span class="token operator">:</span> clone<span class="token punctuation">]</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">body</span><span class="token operator">:</span><br />   <span class="token punctuation">{</span> <span class="token literal-property property">_writeState</span><span class="token operator">:</span> <span class="token punctuation">[</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0</span> <span class="token punctuation">]</span><span class="token punctuation">,</span><br />     <span class="token literal-property property">_readableState</span><span class="token operator">:</span><br />      <span class="token punctuation">{</span> <span class="token literal-property property">objectMode</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span><br />        <span class="token literal-property property">highWaterMark</span><span class="token operator">:</span> <span class="token number">16384</span><span class="token punctuation">,</span><br />        <span class="token literal-property property">buffer</span><span class="token operator">:</span> <span class="token punctuation">[</span>Object<span class="token punctuation">]</span><span class="token punctuation">,</span><br />        <span class="token literal-property property">length</span><span class="token operator">:</span> <span class="token number">0</span><span class="token punctuation">,</span><br />        <span class="token literal-property property">pipes</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br />        <span class="token literal-property property">flowing</span><span class="token operator">:</span> <span class="token keyword">null</span><span class="token punctuation">,</span><br />        <span class="token literal-property property">ended</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span><br />        <span class="token literal-property property">endEmitted</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span><br />        <span class="token literal-property property">reading</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span><br />        <span class="token literal-property property">constructed</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span><br />        <span class="token literal-property property">sync</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span><br />        <span class="token literal-property property">needReadable</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span><br />        <span class="token literal-property property">emittedReadable</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span><br />        <span class="token literal-property property">readableListening</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span><br />        <span class="token literal-property property">resumeScheduled</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span><br />        <span class="token literal-property property">errorEmitted</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span><br />        <span class="token literal-property property">emitClose</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span><br />        <span class="token literal-property property">autoDestroy</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span><br />        <span class="token literal-property property">destroyed</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span><br />        <span class="token literal-property property">errored</span><span class="token operator">:</span> <span class="token keyword">null</span><span class="token punctuation">,</span><br />        <span class="token literal-property property">closed</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span><br />        <span class="token literal-property property">closeEmitted</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span><br />        <span class="token literal-property property">defaultEncoding</span><span class="token operator">:</span> <span class="token string">'utf8'</span><span class="token punctuation">,</span><br />        <span class="token literal-property property">awaitDrainWriters</span><span class="token operator">:</span> <span class="token keyword">null</span><span class="token punctuation">,</span><br />        <span class="token literal-property property">multiAwaitDrain</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span><br />        <span class="token literal-property property">readingMore</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span><br />        <span class="token literal-property property">dataEmitted</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span><br />        <span class="token literal-property property">decoder</span><span class="token operator">:</span> <span class="token keyword">null</span><span class="token punctuation">,</span><br />        <span class="token literal-property property">encoding</span><span class="token operator">:</span> <span class="token keyword">null</span> <span class="token punctuation">}</span><span class="token punctuation">,</span><br />     <span class="token literal-property property">_events</span><span class="token operator">:</span><br />      <span class="token punctuation">{</span> <span class="token literal-property property">prefinish</span><span class="token operator">:</span> <span class="token punctuation">[</span>Function<span class="token operator">:</span> prefinish<span class="token punctuation">]</span><span class="token punctuation">,</span><br />        <span class="token literal-property property">close</span><span class="token operator">:</span> <span class="token punctuation">[</span>Object<span class="token punctuation">]</span><span class="token punctuation">,</span><br />        <span class="token literal-property property">end</span><span class="token operator">:</span> <span class="token punctuation">[</span>Function<span class="token operator">:</span> onend<span class="token punctuation">]</span><span class="token punctuation">,</span><br />        <span class="token literal-property property">finish</span><span class="token operator">:</span> <span class="token punctuation">[</span>Object<span class="token punctuation">]</span><span class="token punctuation">,</span><br />        <span class="token literal-property property">error</span><span class="token operator">:</span> <span class="token punctuation">[</span>Object<span class="token punctuation">]</span><span class="token punctuation">,</span><br />        <span class="token literal-property property">unpipe</span><span class="token operator">:</span> <span class="token punctuation">[</span>Function<span class="token operator">:</span> onunpipe<span class="token punctuation">]</span> <span class="token punctuation">}</span><span class="token punctuation">,</span><br />     <span class="token literal-property property">_eventsCount</span><span class="token operator">:</span> <span class="token number">6</span><span class="token punctuation">,</span><br />     <span class="token literal-property property">_maxListeners</span><span class="token operator">:</span> <span class="token keyword">undefined</span><span class="token punctuation">,</span><br />     <span class="token literal-property property">_writableState</span><span class="token operator">:</span><br />      <span class="token punctuation">{</span> <span class="token literal-property property">objectMode</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span><br />        <span class="token literal-property property">highWaterMark</span><span class="token operator">:</span> <span class="token number">16384</span><span class="token punctuation">,</span><br />        <span class="token literal-property property">finalCalled</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span><br />        <span class="token literal-property property">needDrain</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span><br />        <span class="token literal-property property">ending</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span><br />        <span class="token literal-property property">ended</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span><br />        <span class="token literal-property property">finished</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span><br />        <span class="token literal-property property">destroyed</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span><br />        <span class="token literal-property property">decodeStrings</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span><br />        <span class="token literal-property property">defaultEncoding</span><span class="token operator">:</span> <span class="token string">'utf8'</span><span class="token punctuation">,</span><br />        <span class="token literal-property property">length</span><span class="token operator">:</span> <span class="token number">61</span><span class="token punctuation">,</span><br />        <span class="token literal-property property">writing</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span><br />        <span class="token literal-property property">corked</span><span class="token operator">:</span> <span class="token number">0</span><span class="token punctuation">,</span><br />        <span class="token literal-property property">sync</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span><br />        <span class="token literal-property property">bufferProcessing</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span><br />        <span class="token literal-property property">onwrite</span><span class="token operator">:</span> <span class="token punctuation">[</span>Function<span class="token operator">:</span> bound onwrite<span class="token punctuation">]</span><span class="token punctuation">,</span><br />        <span class="token literal-property property">writecb</span><span class="token operator">:</span> <span class="token punctuation">[</span>Function<span class="token operator">:</span> nop<span class="token punctuation">]</span><span class="token punctuation">,</span><br />        <span class="token literal-property property">writelen</span><span class="token operator">:</span> <span class="token number">61</span><span class="token punctuation">,</span><br />        <span class="token literal-property property">afterWriteTickInfo</span><span class="token operator">:</span> <span class="token keyword">null</span><span class="token punctuation">,</span><br />        <span class="token literal-property property">buffered</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br />        <span class="token literal-property property">bufferedIndex</span><span class="token operator">:</span> <span class="token number">0</span><span class="token punctuation">,</span><br />        <span class="token literal-property property">allBuffers</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span><br />        <span class="token literal-property property">allNoop</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span><br />        <span class="token literal-property property">pendingcb</span><span class="token operator">:</span> <span class="token number">1</span><span class="token punctuation">,</span><br />        <span class="token literal-property property">constructed</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span><br />        <span class="token literal-property property">prefinished</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span><br />        <span class="token literal-property property">errorEmitted</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span><br />        <span class="token literal-property property">emitClose</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span><br />        <span class="token literal-property property">autoDestroy</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span><br />        <span class="token literal-property property">errored</span><span class="token operator">:</span> <span class="token keyword">null</span><span class="token punctuation">,</span><br />        <span class="token literal-property property">closed</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span><br />        <span class="token literal-property property">closeEmitted</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span><br />        <span class="token literal-property property">getBuffer</span><span class="token operator">:</span> <span class="token punctuation">[</span>Function<span class="token operator">:</span> getBuffer<span class="token punctuation">]</span> <span class="token punctuation">}</span><span class="token punctuation">,</span><br />     <span class="token literal-property property">allowHalfOpen</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span><br />     <span class="token literal-property property">bytesWritten</span><span class="token operator">:</span> <span class="token number">0</span><span class="token punctuation">,</span><br />     <span class="token literal-property property">_handle</span><span class="token operator">:</span><br />      <span class="token punctuation">{</span> <span class="token literal-property property">onerror</span><span class="token operator">:</span> <span class="token punctuation">[</span>Function<span class="token operator">:</span> zlibOnError<span class="token punctuation">]</span><span class="token punctuation">,</span><br />        <span class="token literal-property property">buffer</span><span class="token operator">:</span> <span class="token operator">&lt;</span>Buffer 1f 8b <span class="token number">08</span> <span class="token number">00</span> <span class="token number">00</span> <span class="token number">00</span> <span class="token number">00</span> <span class="token number">00</span> <span class="token number">00</span> <span class="token number">03</span> 9d 8e 3f 6b c3 <span class="token number">30</span> <span class="token number">10</span> <span class="token number">47</span> bf 8b e6 <span class="token number">10</span> d9 8e <span class="token number">89</span> 6b <span class="token number">43</span> <span class="token number">86</span> <span class="token number">40</span> e9 9f <span class="token number">80</span> <span class="token number">92</span> a1 <span class="token number">34</span> <span class="token number">05</span> 2f e5 <span class="token number">24</span> 9d 2d <span class="token number">15</span> cb <span class="token number">12</span> <span class="token number">96</span> <span class="token number">62</span> a8 <span class="token number">43</span> be 7b <span class="token operator">...</span> <span class="token number">11</span> more bytes<span class="token operator">></span><span class="token punctuation">,</span><br />        <span class="token literal-property property">cb</span><span class="token operator">:</span> <span class="token punctuation">[</span>Function<span class="token punctuation">]</span><span class="token punctuation">,</span><br />        <span class="token literal-property property">availOutBefore</span><span class="token operator">:</span> <span class="token number">16384</span><span class="token punctuation">,</span><br />        <span class="token literal-property property">availInBefore</span><span class="token operator">:</span> <span class="token number">61</span><span class="token punctuation">,</span><br />        <span class="token literal-property property">inOff</span><span class="token operator">:</span> <span class="token number">0</span><span class="token punctuation">,</span><br />        <span class="token literal-property property">flushFlag</span><span class="token operator">:</span> <span class="token number">2</span><span class="token punctuation">,</span><br />        <span class="token literal-property property">write</span><span class="token operator">:</span> <span class="token punctuation">[</span>Function<span class="token operator">:</span> write<span class="token punctuation">]</span><span class="token punctuation">,</span><br />        <span class="token literal-property property">writeSync</span><span class="token operator">:</span> <span class="token punctuation">[</span>Function<span class="token operator">:</span> writeSync<span class="token punctuation">]</span><span class="token punctuation">,</span><br />        <span class="token literal-property property">close</span><span class="token operator">:</span> <span class="token punctuation">[</span>Function<span class="token operator">:</span> close<span class="token punctuation">]</span><span class="token punctuation">,</span><br />        <span class="token literal-property property">init</span><span class="token operator">:</span> <span class="token punctuation">[</span>Function<span class="token operator">:</span> init<span class="token punctuation">]</span><span class="token punctuation">,</span><br />        <span class="token literal-property property">params</span><span class="token operator">:</span> <span class="token punctuation">[</span>Function<span class="token operator">:</span> params<span class="token punctuation">]</span><span class="token punctuation">,</span><br />        <span class="token literal-property property">reset</span><span class="token operator">:</span> <span class="token punctuation">[</span>Function<span class="token operator">:</span> reset<span class="token punctuation">]</span><span class="token punctuation">,</span><br />        <span class="token literal-property property">getAsyncId</span><span class="token operator">:</span> <span class="token punctuation">[</span>Function<span class="token operator">:</span> getAsyncId<span class="token punctuation">]</span><span class="token punctuation">,</span><br />        <span class="token literal-property property">asyncReset</span><span class="token operator">:</span> <span class="token punctuation">[</span>Function<span class="token operator">:</span> asyncReset<span class="token punctuation">]</span><span class="token punctuation">,</span><br />        <span class="token literal-property property">getProviderType</span><span class="token operator">:</span> <span class="token punctuation">[</span>Function<span class="token operator">:</span> getProviderType<span class="token punctuation">]</span> <span class="token punctuation">}</span><span class="token punctuation">,</span><br />     <span class="token literal-property property">_outBuffer</span><span class="token operator">:</span> <span class="token operator">&lt;</span>Buffer 7b <span class="token number">55</span> <span class="token number">55</span> <span class="token number">55</span> <span class="token number">55</span> <span class="token number">55</span> <span class="token number">55</span> <span class="token number">55</span> <span class="token number">55</span> <span class="token number">55</span> <span class="token number">55</span> <span class="token number">55</span> <span class="token number">55</span> <span class="token number">55</span> <span class="token number">55</span> <span class="token number">55</span> <span class="token number">55</span> <span class="token number">00</span> <span class="token number">00</span> <span class="token number">00</span> <span class="token number">00</span> <span class="token number">00</span> <span class="token number">00</span> <span class="token number">00</span> c3 <span class="token number">00</span> <span class="token number">00</span> <span class="token number">00</span> <span class="token number">00</span> <span class="token number">00</span> <span class="token number">00</span> <span class="token number">00</span> e0 bd <span class="token number">80</span> f2 e8 7f <span class="token number">00</span> <span class="token number">00</span> <span class="token number">20</span> b8 <span class="token number">80</span> f2 e8 7f <span class="token number">00</span> <span class="token number">00</span> <span class="token number">00</span> <span class="token number">00</span> <span class="token operator">...</span> <span class="token number">16334</span> more bytes<span class="token operator">></span><span class="token punctuation">,</span><br />     <span class="token literal-property property">_outOffset</span><span class="token operator">:</span> <span class="token number">0</span><span class="token punctuation">,</span><br />     <span class="token literal-property property">_chunkSize</span><span class="token operator">:</span> <span class="token number">16384</span><span class="token punctuation">,</span><br />     <span class="token literal-property property">_defaultFlushFlag</span><span class="token operator">:</span> <span class="token number">2</span><span class="token punctuation">,</span><br />     <span class="token literal-property property">_finishFlushFlag</span><span class="token operator">:</span> <span class="token number">2</span><span class="token punctuation">,</span><br />     <span class="token literal-property property">_defaultFullFlushFlag</span><span class="token operator">:</span> <span class="token number">3</span><span class="token punctuation">,</span><br />     <span class="token literal-property property">_info</span><span class="token operator">:</span> <span class="token keyword">undefined</span><span class="token punctuation">,</span><br />     <span class="token literal-property property">_maxOutputLength</span><span class="token operator">:</span> <span class="token number">4294967296</span><span class="token punctuation">,</span><br />     <span class="token literal-property property">_level</span><span class="token operator">:</span> <span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">,</span><br />     <span class="token literal-property property">_strategy</span><span class="token operator">:</span> <span class="token number">0</span><span class="token punctuation">,</span><br />     <span class="token literal-property property">params</span><span class="token operator">:</span> <span class="token punctuation">[</span>Function<span class="token operator">:</span> params<span class="token punctuation">]</span><span class="token punctuation">,</span><br />     <span class="token literal-property property">_closed</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span><br />     <span class="token literal-property property">bytesRead</span><span class="token operator">:</span> <span class="token number">0</span><span class="token punctuation">,</span><br />     <span class="token literal-property property">reset</span><span class="token operator">:</span> <span class="token punctuation">[</span>Function<span class="token punctuation">]</span><span class="token punctuation">,</span><br />     <span class="token literal-property property">_flush</span><span class="token operator">:</span> <span class="token punctuation">[</span>Function<span class="token punctuation">]</span><span class="token punctuation">,</span><br />     <span class="token literal-property property">_final</span><span class="token operator">:</span> <span class="token punctuation">[</span>Function<span class="token punctuation">]</span><span class="token punctuation">,</span><br />     <span class="token literal-property property">flush</span><span class="token operator">:</span> <span class="token punctuation">[</span>Function<span class="token punctuation">]</span><span class="token punctuation">,</span><br />     <span class="token literal-property property">close</span><span class="token operator">:</span> <span class="token punctuation">[</span>Function<span class="token punctuation">]</span><span class="token punctuation">,</span><br />     <span class="token literal-property property">_destroy</span><span class="token operator">:</span> <span class="token punctuation">[</span>Function<span class="token punctuation">]</span><span class="token punctuation">,</span><br />     <span class="token literal-property property">_transform</span><span class="token operator">:</span> <span class="token punctuation">[</span>Function<span class="token punctuation">]</span><span class="token punctuation">,</span><br />     <span class="token literal-property property">_processChunk</span><span class="token operator">:</span> <span class="token punctuation">[</span>Function<span class="token punctuation">]</span><span class="token punctuation">,</span><br />     <span class="token literal-property property">_write</span><span class="token operator">:</span> <span class="token punctuation">[</span>Function<span class="token punctuation">]</span><span class="token punctuation">,</span><br />     <span class="token literal-property property">_read</span><span class="token operator">:</span> <span class="token punctuation">[</span>Function<span class="token punctuation">]</span><span class="token punctuation">,</span><br />     <span class="token literal-property property">write</span><span class="token operator">:</span> <span class="token punctuation">[</span>Function<span class="token punctuation">]</span><span class="token punctuation">,</span><br />     <span class="token literal-property property">cork</span><span class="token operator">:</span> <span class="token punctuation">[</span>Function<span class="token punctuation">]</span><span class="token punctuation">,</span><br />     <span class="token literal-property property">uncork</span><span class="token operator">:</span> <span class="token punctuation">[</span>Function<span class="token punctuation">]</span><span class="token punctuation">,</span><br />     <span class="token literal-property property">setDefaultEncoding</span><span class="token operator">:</span> <span class="token punctuation">[</span>Function<span class="token operator">:</span> setDefaultEncoding<span class="token punctuation">]</span><span class="token punctuation">,</span><br />     <span class="token literal-property property">_writev</span><span class="token operator">:</span> <span class="token keyword">null</span><span class="token punctuation">,</span><br />     <span class="token literal-property property">end</span><span class="token operator">:</span> <span class="token punctuation">[</span>Function<span class="token punctuation">]</span><span class="token punctuation">,</span><br />     <span class="token literal-property property">destroy</span><span class="token operator">:</span> <span class="token punctuation">[</span>Function<span class="token operator">:</span> destroy<span class="token punctuation">]</span><span class="token punctuation">,</span><br />     <span class="token literal-property property">_undestroy</span><span class="token operator">:</span> <span class="token punctuation">[</span>Function<span class="token operator">:</span> undestroy<span class="token punctuation">]</span><span class="token punctuation">,</span><br />     <span class="token literal-property property">push</span><span class="token operator">:</span> <span class="token punctuation">[</span>Function<span class="token punctuation">]</span><span class="token punctuation">,</span><br />     <span class="token literal-property property">unshift</span><span class="token operator">:</span> <span class="token punctuation">[</span>Function<span class="token punctuation">]</span><span class="token punctuation">,</span><br />     <span class="token literal-property property">isPaused</span><span class="token operator">:</span> <span class="token punctuation">[</span>Function<span class="token punctuation">]</span><span class="token punctuation">,</span><br />     <span class="token literal-property property">setEncoding</span><span class="token operator">:</span> <span class="token punctuation">[</span>Function<span class="token punctuation">]</span><span class="token punctuation">,</span><br />     <span class="token literal-property property">read</span><span class="token operator">:</span> <span class="token punctuation">[</span>Function<span class="token punctuation">]</span><span class="token punctuation">,</span><br />     <span class="token literal-property property">pipe</span><span class="token operator">:</span> <span class="token punctuation">[</span>Function<span class="token punctuation">]</span><span class="token punctuation">,</span><br />     <span class="token literal-property property">unpipe</span><span class="token operator">:</span> <span class="token punctuation">[</span>Function<span class="token punctuation">]</span><span class="token punctuation">,</span><br />     <span class="token literal-property property">on</span><span class="token operator">:</span> <span class="token punctuation">[</span>Function<span class="token punctuation">]</span><span class="token punctuation">,</span><br />     <span class="token literal-property property">addListener</span><span class="token operator">:</span> <span class="token punctuation">[</span>Function<span class="token punctuation">]</span><span class="token punctuation">,</span><br />     <span class="token literal-property property">removeListener</span><span class="token operator">:</span> <span class="token punctuation">[</span>Function<span class="token punctuation">]</span><span class="token punctuation">,</span><br />     <span class="token literal-property property">off</span><span class="token operator">:</span> <span class="token punctuation">[</span>Function<span class="token punctuation">]</span><span class="token punctuation">,</span><br />     <span class="token literal-property property">removeAllListeners</span><span class="token operator">:</span> <span class="token punctuation">[</span>Function<span class="token punctuation">]</span><span class="token punctuation">,</span><br />     <span class="token literal-property property">resume</span><span class="token operator">:</span> <span class="token punctuation">[</span>Function<span class="token punctuation">]</span><span class="token punctuation">,</span><br />     <span class="token literal-property property">pause</span><span class="token operator">:</span> <span class="token punctuation">[</span>Function<span class="token punctuation">]</span><span class="token punctuation">,</span><br />     <span class="token literal-property property">wrap</span><span class="token operator">:</span> <span class="token punctuation">[</span>Function<span class="token punctuation">]</span><span class="token punctuation">,</span><br />     <span class="token literal-property property">iterator</span><span class="token operator">:</span> <span class="token punctuation">[</span>Function<span class="token punctuation">]</span><span class="token punctuation">,</span><br />     <span class="token literal-property property">setMaxListeners</span><span class="token operator">:</span> <span class="token punctuation">[</span>Function<span class="token operator">:</span> setMaxListeners<span class="token punctuation">]</span><span class="token punctuation">,</span><br />     <span class="token literal-property property">getMaxListeners</span><span class="token operator">:</span> <span class="token punctuation">[</span>Function<span class="token operator">:</span> getMaxListeners<span class="token punctuation">]</span><span class="token punctuation">,</span><br />     <span class="token literal-property property">emit</span><span class="token operator">:</span> <span class="token punctuation">[</span>Function<span class="token operator">:</span> emit<span class="token punctuation">]</span><span class="token punctuation">,</span><br />     <span class="token literal-property property">prependListener</span><span class="token operator">:</span> <span class="token punctuation">[</span>Function<span class="token operator">:</span> prependListener<span class="token punctuation">]</span><span class="token punctuation">,</span><br />     <span class="token literal-property property">once</span><span class="token operator">:</span> <span class="token punctuation">[</span>Function<span class="token operator">:</span> once<span class="token punctuation">]</span><span class="token punctuation">,</span><br />     <span class="token literal-property property">prependOnceListener</span><span class="token operator">:</span> <span class="token punctuation">[</span>Function<span class="token operator">:</span> prependOnceListener<span class="token punctuation">]</span><span class="token punctuation">,</span><br />     <span class="token literal-property property">listeners</span><span class="token operator">:</span> <span class="token punctuation">[</span>Function<span class="token operator">:</span> listeners<span class="token punctuation">]</span><span class="token punctuation">,</span><br />     <span class="token literal-property property">rawListeners</span><span class="token operator">:</span> <span class="token punctuation">[</span>Function<span class="token operator">:</span> rawListeners<span class="token punctuation">]</span><span class="token punctuation">,</span><br />     <span class="token literal-property property">listenerCount</span><span class="token operator">:</span> <span class="token punctuation">[</span>Function<span class="token operator">:</span> listenerCount<span class="token punctuation">]</span><span class="token punctuation">,</span><br />     <span class="token literal-property property">eventNames</span><span class="token operator">:</span> <span class="token punctuation">[</span>Function<span class="token operator">:</span> eventNames<span class="token punctuation">]</span> <span class="token punctuation">}</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">bodyUsed</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">arrayBuffer</span><span class="token operator">:</span> <span class="token punctuation">[</span>Function<span class="token operator">:</span> arrayBuffer<span class="token punctuation">]</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">blob</span><span class="token operator">:</span> <span class="token punctuation">[</span>Function<span class="token operator">:</span> blob<span class="token punctuation">]</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">json</span><span class="token operator">:</span> <span class="token punctuation">[</span>Function<span class="token operator">:</span> json<span class="token punctuation">]</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">text</span><span class="token operator">:</span> <span class="token punctuation">[</span>Function<span class="token operator">:</span> text<span class="token punctuation">]</span> <span class="token punctuation">}</span></code></pre>
<p id="code-skip-day-2-3">Ok, this is pretty standard, we can get the body as JSON or as Text by using awaited functions. So I can check for a string that I expect inside that text and that will be there no matter when I make the HTTP request.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/context-pages/day-2/#code-skip-day-2-2" id="skip-to-code-skip-day-2-2" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript"><span class="token function">describe</span><span class="token punctuation">(</span><span class="token string">"handle basic requests"</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />		<span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">timeout</span><span class="token punctuation">(</span><span class="token number">5000</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />		<span class="token function">it</span><span class="token punctuation">(</span><span class="token string">"should resolve a basic URL"</span><span class="token punctuation">,</span> <span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />			<span class="token keyword">const</span> result <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token function">linkModule</span><span class="token punctuation">(</span><br />				<span class="token string">"https://api.github.com/repos/AramZS/devblog/git/refs/heads/main"</span><br />			<span class="token punctuation">)</span><span class="token punctuation">;</span><br />			result<span class="token punctuation">.</span>status<span class="token punctuation">.</span>should<span class="token punctuation">.</span><span class="token function">equal</span><span class="token punctuation">(</span><span class="token number">200</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />			<span class="token keyword">const</span> textResponse <span class="token operator">=</span> <span class="token keyword">await</span> result<span class="token punctuation">.</span><span class="token function">text</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />			console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>textResponse<span class="token punctuation">)</span><span class="token punctuation">;</span><br />			textResponse<br />				<span class="token punctuation">.</span><span class="token function">includes</span><span class="token punctuation">(</span><br />					<span class="token string">'"url":"https://api.github.com/repos/AramZS/devblog/git/refs/heads/main"'</span><br />				<span class="token punctuation">)</span><br />				<span class="token punctuation">.</span>should<span class="token punctuation">.</span><span class="token function">equal</span><span class="token punctuation">(</span><span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />		<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p id="code-skip-day-2-2">That works! This is a good test.</p>
<p>Ok, I want to look up how to create oEmbeds (where they're available). I've done a lot with scraping pages but I've never done oEmbed. How does it work? Let's look around.</p>
<p>It looks like the standard is described in a pretty basic way <a href="https://oembed.com/" target="_blank">here</a>. It looks like <a href="https://github.com/WordPress/wordpress-develop/blob/5.8.1/src/wp-includes/embed.php#L25-L28" target="_blank">the relevant code for WordPress is over here</a>. There are two popular options <a href="https://www.npmjs.com/package/oembed" target="_blank">oembed</a> and <a href="https://www.npmjs.com/package/oembed-parser" target="_blank">oembed-parser</a>.</p>
<p>This is interesting. I'd always assumed oEmbeds were based off HEAD data, but it looks like sites declare an endpoint from which to retrieve them?</p>
<p><code>oembed-parser</code> looks up to date and well maintained. I think I'll try pulling that in.</p>
<p>It looks like, should any of the links be Facebook, I'll need a Facebook API key. I want to design this to be extended to other projects, so let's set up the function that way.</p>
<p>And Now we have a pretty basic oEmbed functionality. Let's see what I get as a test result.</p>
<p>Ok, first step is to log the result. Here's what I get</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/context-pages/day-2/#code-skip-day-2-1" id="skip-to-code-skip-day-2-1" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript"><span class="token punctuation">{</span><br />  <span class="token literal-property property">type</span><span class="token operator">:</span> <span class="token string">'photo'</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">flickr_type</span><span class="token operator">:</span> <span class="token string">'photo'</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">title</span><span class="token operator">:</span> <span class="token string">'upload'</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">author_name</span><span class="token operator">:</span> <span class="token string">'AramZS'</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">author_url</span><span class="token operator">:</span> <span class="token string">'https://www.flickr.com/photos/aramzs/'</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">width</span><span class="token operator">:</span> <span class="token number">640</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">height</span><span class="token operator">:</span> <span class="token number">640</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">url</span><span class="token operator">:</span> <span class="token string">'https://live.staticflickr.com/2941/33763840540_481ce97db2_z.jpg'</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">web_page</span><span class="token operator">:</span> <span class="token string">'https://www.flickr.com/photos/aramzs/33763840540/'</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">thumbnail_url</span><span class="token operator">:</span> <span class="token string">'https://live.staticflickr.com/2941/33763840540_481ce97db2_q.jpg'</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">thumbnail_width</span><span class="token operator">:</span> <span class="token number">150</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">thumbnail_height</span><span class="token operator">:</span> <span class="token number">150</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">web_page_short_url</span><span class="token operator">:</span> <span class="token string">'https://flic.kr/p/TrAvtJ'</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">license</span><span class="token operator">:</span> <span class="token string">'Attribution License'</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">license_url</span><span class="token operator">:</span> <span class="token string">'https://creativecommons.org/licenses/by/2.0/'</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">license_id</span><span class="token operator">:</span> <span class="token string">'4'</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">html</span><span class="token operator">:</span> <span class="token string">'&lt;a data-flickr-embed="true" href="https://www.flickr.com/photos/aramzs/33763840540/" title="upload by AramZS, on Flickr">&lt;img src="https://live.staticflickr.com/2941/33763840540_481ce97db2_z.jpg" width="640" height="640" alt="upload">&lt;/a>&lt;script async src="https://embedr.flickr.com/assets/client-code.js" charset="utf-8">&lt;/script>'</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">version</span><span class="token operator">:</span> <span class="token string">'1.0'</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">cache_age</span><span class="token operator">:</span> <span class="token number">3600</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">provider_name</span><span class="token operator">:</span> <span class="token string">'Flickr'</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">provider_url</span><span class="token operator">:</span> <span class="token string">'https://www.flickr.com/'</span><br /><span class="token punctuation">}</span></code></pre>
<p id="code-skip-day-2-1">Ok, I can test for that. I should really modal the response instead of making an actual HTTP request, but for now this is a good place to be. Last thing I want to test is <a href="https://developers.facebook.com/docs/features-reference/oembed-read" target="_blank">if it can make a request to Facebook</a>.</p>
<p>Hmm, trying some URLs and all I'm getting is <code>nulls</code>. That's annoying.</p>
<p>Ok, well, I'm hungry for dinner, so let's stop here.</p>
<p><a target="_blank" href="https://github.com/AramZS/contexter/commit/c9f9149e61ecf9d17b836e81b5b7040a8804c43c" class="git-commit-link"><code>git commit -am &quot;Getting the Link Request modules requesting and testing oembed&quot;</code></a></p>
]]></content:encoded>
	</item>
	
	<item>
		<title>Day 1: Building a tool to generate context pages</title>
		<link>https://fightwithtools.dev/posts/projects/context-pages/day-1/?source=rss</link>
		<pubDate>Sun, 02 Jan 2022 02:59:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/projects/context-pages/day-1/</guid>
		<description>I want to share lists of links, but make them readable and archived</description>
		<content:encoded><![CDATA[<h2 id="project-scope-and-todos" tabindex="-1">Project Scope and ToDos</h2>
<ol>
<li>Take a link and turn it into an oEmbed/Open Graph style share card</li>
<li>Take a link and archive it in the most reliable way</li>
<li>When the link is a tweet, display the tweet but also the whole tweet thread.</li>
<li>When the link is a tweet, archive the tweets, and display them if the live ones are not available.</li>
<li>Capture any embedded retweets in the thread. Capture their thread if one exists</li>
<li>Capture any links in the Tweet</li>
<li>Create the process as an abstract function that returns the data in a savable way</li>
</ol>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Archive links on <a href="http://archive.org/" target="_blank">Archive.org</a> and save the resulting archival links</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Create link IDs that can be used to cache related content</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Integrate it into the site to be able to make context pages here.</li>
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Archive linked YouTubes</li>
</ul>
<h2 id="day-1" tabindex="-1">Day 1</h2>
<p>Ok, so this is a thing that happens a lot. I collect a bunch of links to a particular topic, and I want to share it. But it's hard to read a bunch of links, so how do I make it more readable?</p>
<p>I thought through some scope requirements and to dos and put them on the top of this page first. My first goal is to take a list of links and turn them into something more easy to read. I think the best way is by creating Open Graph style share cards for each link and replacing the link in place with those cards. So let's handle that request process.</p>
<h3 id="selecting-test-tool" tabindex="-1">Selecting test tool</h3>
<p>I think the easiest way to move forward is to build some test processes first so that I can run links through the function I'm building and test my outputs. I've now done tests with Jest and Mocha. Another popular library is <a href="https://www.chaijs.com/" target="_blank">Chai</a>, so let's try that.</p>
<h3 id="archiving-tools-refrerence" tabindex="-1">Archiving Tools Refrerence</h3>
<p>It's also worthwhile to do exactly the sort of thing I'm talking about here and record some info about archiving links.</p>
<ul>
<li><a href="https://github.com/palewire/savemy.news" target="_blank">https://github.com/palewire/savemy.news</a></li>
<li><a href="https://github.com/palewire/archiveis" target="_blank">https://github.com/palewire/archiveis</a></li>
<li><a href="https://perma.cc/docs/developer" target="_blank">https://perma.cc/docs/developer</a></li>
<li><a href="https://conifer.rhizome.org/" target="_blank">https://conifer.rhizome.org/</a></li>
<li><a href="https://en.wikipedia.org/wiki/Help:Using_the_Wayback_Machine#JavaScript_bookmarklet" target="_blank">https://en.wikipedia.org/wiki/Help:Using_the_Wayback_Machine#JavaScript_bookmarklet</a></li>
<li><a href="https://help.archive.org/save-pages-in-the-wayback-machine/" target="_blank">https://help.archive.org/save-pages-in-the-wayback-machine/</a></li>
<li><a href="http://mementoweb.org/depot/native/archiveis/" target="_blank">http://mementoweb.org/depot/native/archiveis/</a></li>
<li><a href="http://mementoweb.org/guide/quick-intro/" target="_blank">http://mementoweb.org/guide/quick-intro/</a></li>
<li><a href="https://wiki.archiveteam.org/index.php/ArchiveTeam_Warrior" target="_blank">https://wiki.archiveteam.org/index.php/ArchiveTeam_Warrior</a></li>
<li><a href="https://wiki.archiveteam.org/index.php/Software" target="_blank">https://wiki.archiveteam.org/index.php/Software</a></li>
<li><a href="https://github.com/eloquence/freeyourstuff.cc" target="_blank">https://github.com/eloquence/freeyourstuff.cc</a></li>
<li><a href="https://github.com/dhamaniasad/WARCTools" target="_blank">https://github.com/dhamaniasad/WARCTools</a></li>
<li><a href="https://blog.risingstack.com/pdf-from-html-node-js-puppeteer/" target="_blank">https://blog.risingstack.com/pdf-from-html-node-js-puppeteer/</a></li>
<li><a href="https://www.npmjs.com/package/html-pdf-node" target="_blank">https://www.npmjs.com/package/html-pdf-node</a></li>
<li><a href="https://github.com/mozilla/readability" target="_blank">https://github.com/mozilla/readability</a></li>
</ul>
<p>This is all pretty much more extensive then I want to do for my first run at this project, but it is good to have a list. To start, let's turn link lists into HTML cards.</p>
<h3 id="sanitizing-the-url" tabindex="-1">Sanitizing the URL</h3>
<p>Ok, first thing is to sanitize the URL.</p>
<p>There's a fairly popular Node sanitation library, I'll start there.</p>
<p>I'll pull the regex WordPress uses to clean URLs, as I've used that in PHP and it's fairly reliable.</p>
<p>Finally, I want to strip marketing params that are commonly used in links. I could make my own code here, but a quick search around has revealed that <a href="https://github.com/mihaip/utm-stripper/blob/master/extension/background.js" target="_blank">someone built some good regexes to handle this</a>.</p>
<p>Ok, this makes for a good test setup. It looks like Chai builds on top of Mocha, so let's install that too.</p>
<p>Ok, it looks like <a href="https://www.chaijs.com/guide/styles/" target="_blank">Chai has a suite of tools, the major ones are should, expect and assert</a>.</p>
<p>Ok, let's make some bad links.</p>
<p>I want to invalidate <code>mailto</code> links also. So let's see if I can throw an error and capture it in Chai.</p>
<p>I should be able to capture the tests with <code>.should.Throw</code> and <code>expect(fn).to.throw(new Error('text'))</code></p>
<p>Hmm, that's not working.</p>
<p>Ok, <a href="https://stackoverflow.com/a/22340179" target="_blank">it looks like it has a different format</a> and does require we put the error-throwing function inside another function... for some reason. I also can't use the error object, just the error text. Also unclear from the docs.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/context-pages/day-1/#code-skip-day-1-1" id="skip-to-code-skip-day-1-1" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript"><span class="token function">it</span><span class="token punctuation">(</span><span class="token string">"should throw on mailto links"</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />	<span class="token function">expect</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />		<span class="token function">linkModule</span><span class="token punctuation">(</span><span class="token string">"mailto:test@example.com?subject=hello+world"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span>to<span class="token punctuation">.</span><span class="token function">throw</span><span class="token punctuation">(</span><span class="token string">"Invalid Mailto Link"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p id="code-skip-day-1-1">Ok, my sanitizer looks good and I think that I have some good coverage. Next step will be handling the Fetch step and building out the data model. But this is a good place to stop.</p>
<p><a target="_blank" href="https://github.com/AramZS/contexter/commit/222119ccab48e086f4c59e1f96328bd384e57517" class="git-commit-link"><code>git commit -am &quot;Set up sanitizer and unit tests&quot;</code></a></p>
]]></content:encoded>
	</item>
	
	<item>
		<title>Brute Forcing My Way Through Markdown-It</title>
		<link>https://fightwithtools.dev/posts/projects/devblog/retro-markdown-it/?source=rss</link>
		<pubDate>Fri, 31 Dec 2021 02:59:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/projects/devblog/retro-markdown-it/</guid>
		<description>I'm not sure why I decided to challenge myself with a different markdown parser than I usually use, but I'm glad I did.</description>
		<content:encoded><![CDATA[<h2 id="markdown-it-so-crunchy-so-useful-such-a-pain" tabindex="-1">Markdown-It - So Crunchy, So Useful, Such a Pain</h2>
<p>I am going to be critical of Markdown-It here, so I want to put this up front: the community was helpful, I got fast feedback on an issue, once I figured it out it was hugely useful. If you've got time and a willingness to figure stuff out yourself and a whole bunch of patience to really explore the tool... well then I couldn't recommend it more. If all you want to do is zero-config your way to a basic Markdown to HTML pipeline, then this should be fine (along with a variety of other tools). But if you want to do some basic modification, like some text-to-fun-CSS or shortcode-style template tags in Markdown itself instead of in something like Eleventy or Nunjucks (this is <a href="https://glitch.com/edit/#!/thespin?path=markdown-to-col.js%3A20%3A27" target="_blank">a thing I have definitely done</a>), then this likely isn't the Markdown renderer you're looking for.</p>
<p>And like... that's fine. That's totally cool. There's room in the world for more than one Markdown renderer. No one get mad. I'm not insulting any library here. Ok, onward.</p>
<h3 id="the-frustration" tabindex="-1">The Frustration</h3>
<p>I think it is generous to say that Markdown It's documentation is unclear. <a href="https://markdown-it.github.io/markdown-it/" target="_blank">It's very sparse</a> and everything about the project is difficult to navigate. At least it isn't misleading, which is good! But even the available in-project resources were difficult to find! The <a href="https://markdown-it.github.io/" target="_blank">Markdown-It demo page</a> was <em>really</em> useful or at least it would have been if I had found it earlier than a month+ into this project. I'm not even totally sure how I got to it? I don't think it is linked on the project readme. Maybe I just went to the URL because I was curious what the site home page was, not expecting anything? It should really be at the top of their readme. Also, <a href="https://github.com/markdown-it/markdown-it/blob/master/docs/architecture.md" target="_blank">their architecture doc</a> was hugely useful, but it was linked as plugin developer docs, so I almost didn't get to it.</p>
<p>The unclear documentation is especially difficult when paired with the standard problems of the Node ecosystem, which is a lot of badly maintained, no longer functioning, libraries. You can see me <a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-16/" target="_blank">wasting a lot of time on day 16 on the supposed Markdown-It Regex plugin</a>. This isn't Markdown It's fault, but it almost put me off using the tool at all.</p>
<p data-wordfix="true">I already noted that this combination of bad package maintenance, too many blog posts, and misleading resources seems to be especially common in Node for reasons that are unclear to me. Increasingly I think I'm going to rely less on random blogs and plugins and more on just trying to figure out how libraries work by tweezing them apart through use and logging and <strong>then</strong> maybe code reading (though good inline documentation is even more rare, even on otherwise good projects). I wish that wasn't the case, but I'm not sure what the alternatives are. One would think a more robust community would be an advantage, but it doesn't feel like it is in many mid-size projects' cases.</p>
<h3 id="project-feel-and-future-use" tabindex="-1">Project Feel and Future Use</h3>
<p>Now that I've bull-headed my way through learning Markdown It, I finally understand it. The decisions make sense. It's a smart project that is centered on a number of smart decisions that, while they might not be easy to find or initially figure out, all feel right. I understand now why the project is so popular, it's flexible, it's holistic, it's comprehensive. Like all the best libraries getting the hang of it feels like unlocking a super power.</p>
<p>It's likely that, for my future projects where I use Markdown, Markdown-It will be the project I'll use. There may be a few exceptions for extremely simple Markdown parsing, but I think I'll be continuing to use Markdown-It. It's a great tool.</p>
<h3 id="what-i-learned-(other-than-the-code-in-my-blog-posts)" tabindex="-1">What I Learned (other than the code in my blog posts)</h3>
<p>Working with Markdown-It was a great excuse to stretch my Regex legs and really try for some more complex patterns than I would usually deal with.</p>
<p>Other than that, and <a href="https://fightwithtools.dev/posts/projects/devblog/retro-getting-back-to-sass/#what-i-learned-(other-than-the-code-in-my-blog-posts)" target="_blank">what I learned about being more self-reliant when exploring libraries in the Sass project</a>, I think learning to use Markdown-It was a very code heavy experience. Which isn't at all a bad thing.</p>
<p>It was also great how responsive the project maintainers were. I don't think you can rely on that in every project, but in this case it was a great reminder that GitHub issues, if you follow the instructions and put together your example effectively, are a great place to ask questions and learn stuff, not just mark errors. I think phrasing it as &quot;what's the best practice for using your code&quot; is the right way to go, and an approach I might employ in the future.</p>
<p>Also, all things considered, I validated my approach of trying a new thing just for the sake of it being something different. I had no particular reason to stick with Markdown-It, but I'm glad I did.</p>
<h3 id="self-check:-assumptions-and-validations" tabindex="-1">Self-check: Assumptions and Validations</h3>
<h4 id="should-i-prefer-markdown-it-for-future-projects" tabindex="-1">Should I <strong>prefer</strong> Markdown-It for future projects?</h4>
<ul>
<li>I went in with the assumption being no. I assumed this would be a one-off experiment where I'd return to using Showdown later.</li>
<li>I did not validate this assumption. I will definitely use Markdown-It in the future.</li>
</ul>
<h4 id="was-markdown-it-effective" tabindex="-1">Was Markdown-It effective?</h4>
<ul>
<li>I did not go in with any particular assumptions, but early into the project I was highly frustrated and questioning Markdown It's effectiveness.</li>
<li>Invalidated. Markdown-It is absolutely effective.</li>
</ul>
<h4 id="does-markdown-it-block-collaboration" tabindex="-1">Does Markdown-It block collaboration?</h4>
<ul>
<li>I went in assuming yes.</li>
<li>This is a mixed bag. People familiar with the project already are out there and seem ready to collaborate, but I'm not sure I established enough information in my writing to make it easy for newcomers to enter my Markdown-It related code and understand what's going on.</li>
</ul>
<h4 id="does-markdown-it-have-effective-documentation-either-external-or-internal" tabindex="-1">Does Markdown-It Have Effective Documentation either External or Internal</h4>
<ul>
<li>I went in with no idea, but feeling no.</li>
<li>Validated. The documentation for Markdown-It just isn't there, either in the project or the community.</li>
</ul>
<h4 id="will-it-be-easy-to-maintain" tabindex="-1">Will it be easy to maintain?</h4>
<ul>
<li>I went in assuming no.</li>
<li>I... think it will be? Markdown It's structures, once understood, are pretty straightforward, make use of very standardized code and objects, and seem to be very stable and built on well-thought-out architecture.</li>
</ul>
<h4 id="did-learning-markdown-it-give-me-broadly-applicable-skills" tabindex="-1">Did learning Markdown-It give me broadly applicable skills?</h4>
<ul>
<li>I went in assuming no.</li>
<li>I think the exercise with Regex was very useful, but I'm not sure the rest is. Markdown is a thing I use for personal projects, but not a thing I ever anticipate using for professional projects. While their Token structure makes a lot of sense, it doesn't have a lot of overlap with text/html processing engines I've used.</li>
</ul>
<h4 id="working-on-this-will-allow-me-to-give-something-back-to-the-community" tabindex="-1">Working on this will allow me to give something back to the community</h4>
<ul>
<li>I went in assuming no.</li>
<li>Invalid. I have <a href="https://www.npmjs.com/package/markdown-it-find-and-replace" target="_blank">contributed one plugin</a> and could easily see myself writing another. There's a lot of cool things Markdown-It can do that I think I could leverage in new ways that the existing community (while large) hasn't done yet.</li>
</ul>
<h3 id="conclusion" tabindex="-1">Conclusion</h3>
<p>What an unexpected delight. After I got through the frustration of decoding how Markdown-It works, getting more advanced features up and running on my blog was just a lot of fun. I don't really know why I barreled forward on using Markdown-It, but I'm glad I did.</p>
<p><strong>Use of Markdown-It</strong>: <em>Validated</em></p>
]]></content:encoded>
	</item>
	
	<item>
		<title>Getting back to SASS</title>
		<link>https://fightwithtools.dev/posts/projects/devblog/retro-getting-back-to-sass/?source=rss</link>
		<pubDate>Wed, 29 Dec 2021 02:59:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/projects/devblog/retro-getting-back-to-sass/</guid>
		<description>Setting this devblog up ran me through a Sass refresher course, and presented an opportunity. But I'm not sure it was worth it</description>
		<content:encoded><![CDATA[<h2 id="back-into-sass" tabindex="-1">Back Into Sass</h2>
<p>I've dipped my toe in and out of Sass many times over the years. This, though, is the most I've focused on it in a while.</p>
<h3 id="rebuilding-my-build-process-from-scratch" tabindex="-1">Rebuilding my build process from scratch</h3>
<p>I think it was pretty wild to basically have to re-figure-out what is essentially a CSS build process from scratch with the end of Node Sass. It was a real slow down. Also, hardly the first time I have had to do that for a Sass project. It feels like I've had to rebuild my Sass build process every time I've worked on it. I'm also not sure when the split between SCSS and SASS formats happened? Perhaps it has always been there and I've just forgotten... or my build tools took care of it for me? It was easy enough to change grooves, but weird.</p>
<p data-wordfix="true">On the flip side, Dart Sass in Node seems to be significantly simpler than its predecessor. I will give it this: it is definitely an improvement. Once I was able to struggle through the meager documentation and log my way towards how it functioned I was able to get it working well enough and able to do some flexible things with it. Obviously, once I got the hang of it I was able to really get it working for me; well enough that I was able to write an Eleventy plugin based on my code and approach. It works so well and is so much clearer to me code-wise than the Node Sass alternative I was even ready to <a href="https://github.com/11ty/11ty-website/pull/1257#pullrequestreview-841555379" target="_blank">submit it</a> to the <a href="https://www.11ty.dev/docs/plugins/" target="_blank">Eleventy plugin directory</a>.</p>
<h3 id="leveraging-best-practices" tabindex="-1">Leveraging best practices</h3>
<p data-wordfix="true">I don't know if I used Sass as well as I could. I'd hoped to find some way to do intelligent code splitting, but the build process Dart Sass has doesn't interact with Eleventy in a way I could see that happening automatically, and so I ended up doing it manually. I also am not sure I fully took advantage of Sass features. I could likely do something better in regards to variables, mixins, etc... but having built my CSS by hand on my last few projects, I think it likely would have been simpler to have done that for this project and maybe stitch the files together for ease of managing my rules.</p>
<p>There's just a lot of advanced CSS features that are native now. Features like <code>calc</code>, CSS variables, and the ever growing list of nifty pseudo-selectors seems to make <strong>unnecessary</strong> much of the stuff I once relied on Sass to do.</p>
<h3 id="project-feel-and-future-use" tabindex="-1">Project feel and future use</h3>
<p>Compounding the issue, it doesn't feel like the Sass project is especially stable these days. It was extremely disconcerting to discover that one of their main rendering functions had apparently been marked for depreciation over the course of this project (about 10 minor versions in half a year). Especially considering that this switch to a new function didn't maintain the interface of the previous function which, as far as I can see, is one which most Sass projects would have used. Worse, the transition didn't seem to be clearly documented.</p>
<p>Perhaps this is all just a result of my distance from Sass over the last few years, where I was either ending up using hand-cranked CSS or I was going to go the CSS-in-JS route. But it doesn't feel that way. My last Sass project was in June of last year. It really makes me doubt if I should go the Sass route in the future. With Eleventy especially I feel like I could likely find or build a CSS compression + source map process that would be just as effective performance-wise and easier to use. It might be worth it to try, or to look into one of the fancy frameworks like <a href="https://tailwindcss.com/" target="_blank">Tailwind</a> or a CSS-in-JS <a href="https://lit.dev/" target="_blank">process</a> that doesn't feel gross and renders out to one or more stylesheets (though those seem to be hard to find).</p>
<h3 id="what-i-learned-(other-than-the-code-in-my-blog-posts)" tabindex="-1">What I Learned (other than the code in my blog posts)</h3>
<p>I think one of the major things I learned working on the Sass part of this project is how <em>bad</em> the reliance on the community to provide documentation is. In trying to get this to work I encountered:</p>
<ul>
<li>a ton of malfunctioning code examples;</li>
<li>a plugin that looks like it should work, was only 10 months old, but is completely non functional;</li>
<li>a full on <a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-2/" target="_blank">documentation error in the core Dart Sass library</a>;</li>
<li>some misleading blog posts with bad, old or just wrong info;</li>
<li>a major depreciation mid-project;</li>
</ul>
<p>None of this makes me feel great about reusing Sass but also I think it highlights a major realization:</p>
<p>A lot of these modern projects like Sass provide <a href="https://twitter.com/Chronotope/status/1472118035205042178" target="_blank">really</a> <a href="https://twitter.com/Chronotope/status/1374369144100024322" target="_blank">bare</a> <a href="https://twitter.com/Chronotope/status/1419441920951169027" target="_blank">minimum</a> documentation. I think they rely on the community to write about their libraries and then have those show up in search. And a lot of them do have communities that <strong>do</strong> write about their use of the code libraries and how to do interesting stuff with them but...</p>
<p><strong>All that is pointless if you change your library so frequently and radically as to invalidate community-generated materials.</strong></p>
<p>This isn't just a Sass problem, it seems to be a major issue I've seen a lot ever since React started becoming popular. I don't know why this is the case, maybe it comes from some mother projects, maybe it's just a Node community tendency? I'm not sure what it is but it <em>is</em> annoying.</p>
<p>It means that there are a ton of well-meaning developer bloggers (like myself now!) who write posts that are &quot;this is how to do x&quot; without a lot of information about why, or how they navigated the library to figure out how to do X, or how others might learn for themselves. Without better docs in the actual library site the end result is that picking up any of these packages new is made <em>harder</em> when there are more people blogging about the library because it is so easy to burn time on frustrating dead ends. I think I'll do a Markdown It retro as well, but a notable overlap is that the period I gave myself to work on it without referring to developer blogs or Stack Exchange was the time I was most productive in unlocking the library's value. There are just too many out-of-date blogs and false leads. The best source material ends up being Github Issues, which at least are easy to search and sort by date.</p>
<p>The two main things I took away from this to apply to my own projects are:</p>
<p>I should apply extensive documentation and examples in the core project documentation. It's nice when your project is popular enough that people start writing about it, but it's a mistake to act in a way that assumes those resource exist or are kept up to date. Sadly, blog posts don't have a filter that checks them for forward compatibility. Instead, I need to keep documentation for my own projects verbose, up to date, and explanatory.</p>
<p>The second take away is for how I blog here on this and future projects. I endeavored here not just to document what I did but also how I figured it out; what bad processes and incorrect assumptions I made; and how I taught myself the correct way forward. I think that for this type of blog that information is far more useful than a bunch of minimally documented code samples of &quot;How to do X&quot;. Even when the code itself might no longer be usable because of library changes my process will hopefully still be useful to future developers.</p>
<h3 id="self-check:-assumptions-and-validations" tabindex="-1">Self-check: Assumptions and Validations</h3>
<h4 id="should-i-prefer-sass-for-future-projects" tabindex="-1">Should I <strong>prefer</strong> Sass for future projects?</h4>
<ul>
<li>I went in with the assumption being yes. I made a beeline for Sass both because of preference and experience.</li>
<li>I did not validate this assumption. I should not start future projects with the assumption that Sass is the best tool for the job.</li>
</ul>
<h4 id="was-sass-effective" tabindex="-1">Was Sass effective?</h4>
<ul>
<li>I went in assuming yes.</li>
<li>Validated. It was effective. It was easy to build with, I was able to fly with it once I learned how. I <strong>can</strong> use it for projects like this. I don't know if it saved me time, but it didn't feel like it took up a ton of extra time.</li>
</ul>
<h4 id="does-sass-block-collaboration" tabindex="-1">Does Sass block collaboration?</h4>
<ul>
<li>I went in assuming no.</li>
<li>Validated. It was easy to form Site Maps once I nosed out a few errors. I think it creates easy to read code on both site maps and Github. It's hard to be final on this without hearing from others, but I think it worked out.</li>
</ul>
<h4 id="sass-is-a-broad-project-with-good-documentation-either-on-it's-site-or-through-self-documentation" tabindex="-1">Sass is a broad project with good documentation either on it's site or through self-documentation</h4>
<ul>
<li>I went in assuming yes.</li>
<li>Invalidated. See above. But also it turned out that getting a good VS Code plugin <em>significantly</em> helped the process.</li>
</ul>
<h4 id="sass-will-be-easy-to-maintain" tabindex="-1">Sass will be easy to maintain</h4>
<ul>
<li>I went in assuming yes.</li>
<li>Unclear. I stumbled on errors in the docs, at least two cases of depreciation, and one feature that was marked as for future use only. Major changes in Sass meant I basically had to starting over for everything but writing the style rules themselves. We'll have to see if the project gets leveled out, but for now it worries me for something like this where I want to do minimal maintenance of the project's core code.</li>
</ul>
<h4 id="did-learning-sass-give-me-broadly-applicable-skills-that-i-could-use-elsewhere" tabindex="-1">Did learning Sass give me broadly applicable skills that I could use elsewhere?</h4>
<ul>
<li>I went in assuming yes.</li>
<li>Unclear. One of the major things I noticed looking up CSS info was that people seem to be frequently moving to Tailwind or CSS-in-JS techniques. I'm not sure I appreciate either from an abstract or best practices perspective, but it doesn't speak to Sass skills being broadly applicable. Maybe I'll see a lot of users on the plugin I built and come back to this and say that the answer is yes later.</li>
</ul>
<h4 id="sass-will-help-me-do-smart-code-splitting" tabindex="-1">Sass will help me do smart code splitting</h4>
<ul>
<li>I went in assuming yes.</li>
<li>Invalid. It really didn't. I had to build that functionality on top entirely myself.</li>
</ul>
<h4 id="working-on-this-will-allow-me-to-give-something-back-to-the-community" tabindex="-1">Working on this will allow me to give something back to the community</h4>
<ul>
<li>I went in assuming no.</li>
<li>Invalid. It turned out that Eleventy's Sass plugin, though not even a year old, wasn't really working anymore. I built a new one. Maybe people will use it? It turned out that there were big things I needed to learn myself and ways I could take what I learned and make it broadly applicable. If everything else had been bad, this would have made using Sass worth it all on its own. It's good to give back.</li>
</ul>
<h3 id="conclusion" tabindex="-1">Conclusion</h3>
<p>Using Sass more may not be in my future, but I think it was a worthwhile process to go through for this project. At some future point I may switch the relatively simple CSS I'm maintaining for this project to just plain CSS files, but right now I think it'll be good to keep iterating using Sass. There are clearly others who want to use it. Continuing to have it in this project will help me maintain my plugin and help the wider community.</p>
<p><strong>Use of Sass</strong>: <em>Validated</em></p>
]]></content:encoded>
	</item>
	
	<item>
		<title>Day 42 - Analytics time!</title>
		<link>https://fightwithtools.dev/posts/projects/devblog/hello-day-42/?source=rss</link>
		<pubDate>Wed, 01 Dec 2021 02:59:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/projects/devblog/hello-day-42/</guid>
		<description>More devblog</description>
		<content:encoded><![CDATA[<h2 id="project-scope-and-todos" tabindex="-1">Project Scope and ToDos</h2>
<ol>
<li>Static Site Generator that can build the blog and let me host it on Github Pages</li>
<li>I want to write posts in Markdown because I'm lazy, it's easy, and it is how I take notes now.</li>
<li>I don't want to spend a ton of time doing design work. I'm doing complicated designs for other projects, so I want to pull a theme I like that I can rely on someone else to keep up.</li>
<li>Once it gets going, I want template changes to be easy.</li>
<li>It should be as easy as Jekyll, so I need to be able to build it using GitHub Actions, where I can just commit a template change or Markdown file and away it goes. If I can't figure this out than fk it, just use Jekyll.</li>
<li>I require it to be used by a significant percent of my professional peers so I can get easy answers when something goes wrong.</li>
<li>I want source maps. This is a dev log site which means whatever I do with it should be easy for other developers to read.</li>
</ol>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Also <a href="https://www.npmjs.com/package/@quasibit/eleventy-plugin-sitemap" target="_blank">the sitemap plugin</a> looks cool. Should grab that later.</li>
</ul>
<s>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> So does the <a href="https://www.npmjs.com/package/eleventy-plugin-reading-time" target="_blank">reading time one</a>.</li>
</ul>
</s>
<ul class="task-list">
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Also <a href="https://github.com/jdsteinbach/eleventy-plugin-toc/" target="_blank">this TOC plugin</a> mby?</p>
</li>
<li class="task-list-item">
<p data-wordfix="true"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Use <a href="https://www.11ty.dev/docs/data-deep-merge/" target="_blank">Data Deep Merge</a> in this blog.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Decide if I want to render the CSS fancier than just a base file and do per-template splitting.</p>
</li>
</ul>
<s>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Can I use the template inside of dinky that already exists instead of copy/pasting it?</li>
</ul>
</s>
<s>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Is there a way to have permalinks to posts contain metadata without organizing them into subfolders?</li>
</ul>
</s>
<ul class="task-list">
<li class="task-list-item">
<p data-wordfix="true"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> How do I cachebreak files on the basis of new build events? Datetime? <code>site.github.build_revision</code> is <a href="https://github.com/jekyll/github-metadata/blob/master/docs/site.github.md" target="_blank">how Jekyll accomplishes this</a>, but is there a way to push <a href="https://docs.github.com/en/actions/reference/context-and-expression-syntax-for-github-actions#github-context" target="_blank">that</a> <a href="https://stackoverflow.com/questions/54310050/how-to-version-build-artifacts-using-github-actions" target="_blank">into the build process</a> for Eleventy?</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Make link text look less shitty. It looks like it is a whole, lighter, font.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Code blocks do not have good syntax highlighting. I want good syntax highlighting.</p>
</li>
<li class="task-list-item">
<p data-wordfix="true"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Build a Markdown-it plugin to take my typing shortcuts <code>[prob, b/c, ...?]</code> and expand them on build.</p>
</li>
</ul>
<s>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> See if we can start Markdown's interpretation of H tags to <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/Heading_Elements#multiple_h1" target="_blank">start at 2, since H1</a> is always pulled from the page title metadata. If it isn't easy, I just have to change my pattern of writing in the MD documents.</li>
</ul>
</s>
<ul class="task-list">
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Should I <a href="https://www.madebymike.com.au/writing/11ty-filters-data-shortcodes/" target="_blank">explore some shortcodes</a>?</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Order projects listing by last posted blog in that project</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Limit the output of home page post lists to a specific number of posts</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Show the latest post below the site intro on the homepage.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Tags pages with Pagination</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Posts should be able to support a preview header image that can also be shown on post lists.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Create a Markdown-It plugin that reads the project's repo URL off the folder data file and renders commit messages with <a href="https://stackoverflow.com/questions/15919635/on-github-api-what-is-the-best-way-to-get-the-last-commit-message-associated-w" target="_blank">links to the referenced commit</a>. (Is this even possible?) (Is there a way to do it with eleventy instead?)</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Create Next Day/Previous Day links on each post / Next/Previous post on post templates from projects</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Tags should be in the sidebar of articles and link to tag pages</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Create a skiplink for the todo section (or would this be better served with the ToC plugin?) - Yes it would be!</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Add a Things I Learned section to the project pages that are the things I learned from that specific project.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Add a technical reading log to the homepage</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/:empty" target="_blank">Hide</a> empty sections.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Add byline to post pages</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Have table of contents attach to sidebar bottom on mobile</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Support dark mode</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Social Icons</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> SEO/Social/JSON-LD HEAD data</p>
</li>
</ul>
<h2 id="day-42" tabindex="-1">Day 42</h2>
<p>Ok. This site is almost ready to go. There are some enhancements I still want to do to code blocks and I want to add some more advanced content to tag pages, but it is at the point where I want to take this and show it to other people.</p>
<p>So one of the things I want to do is set up privacy-respecting analytics. I <a href="https://twitter.com/Chronotope/status/1444744757037707272" target="_blank">polled folks on this a while back and got some options</a>. I considered them and have basically come down to two options: <a href="https://plausible.io/privacy-focused-web-analytics" target="_blank">Plausible</a> or <a href="https://usefathom.com/" target="_blank">Fathom</a>. I'm going to read around both of them.</p>
<p>They both seem very privacy forward. They run in the EU to use GDPR to help them protect data. They both contribute to climate issues and have smart export settings. I think they both seem like fine services. I'm leaning towards Plausible because it is slightly cheaper, more open source, and the script itself seems to be just slightly lighter-weight (though they are both <em>very</em> lightweight). Also, I sort of like the idea of <a href="https://plausible.io/docs/visibility" target="_blank">opening up my analytics to anyone</a>. I think I'm going to start there. Oh... interesting... they let me do the 30 day trial for free, without entering anything credit card wise!</p>
<p>Very cool. Let's try it out.</p>
<p><a target="_blank" href="https://github.com/AramZS/devblog/commit/ce0b3656ed505d2f9f73279f76e25b9e588afc68" class="git-commit-link"><code>git commit -am &quot;Early commit to try out Plausible&quot;</code></a></p>
<p>Ok, it works, <a href="https://plausible.io/fightwithtools.dev" target="_blank">and I can flip on a public dashboard as well</a>!</p>
<p>Oh and it has a nice Google Search Console integration. I'll set that up as well. Huh, can I add a TXT record but there but it looks like this whole process has changed somewhat since the last time I was there. Ok. That's fine. I can get it working easily enough. Seems to be integrated now!</p>
<p>I guess that's it, it's working? Yeah! Ok. Well I don't think there's much blocking me now, I hit almost everything I wanted to hit.</p>
<p>There are a few features I'd still like to implement here, but I think things are well formed enough that I can put this out there for feedback. Last thing to do is some touch up regarding featured images, tags and titles that I can take care of tonight or tomorrow.</p>
]]></content:encoded>
	</item>
	
	<item>
		<title>Extract Sass into an Eleventy Plugin</title>
		<link>https://fightwithtools.dev/posts/projects/devblog/sass-plugin/?source=rss</link>
		<pubDate>Sun, 28 Nov 2021 02:59:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/projects/devblog/sass-plugin/</guid>
		<description>More devblog</description>
		<content:encoded><![CDATA[<h2 id="project-scope-and-todos" tabindex="-1">Project Scope and ToDos</h2>
<ol>
<li>Static Site Generator that can build the blog and let me host it on Github Pages</li>
<li>I want to write posts in Markdown because I'm lazy, it's easy, and it is how I take notes now.</li>
<li>I don't want to spend a ton of time doing design work. I'm doing complicated designs for other projects, so I want to pull a theme I like that I can rely on someone else to keep up.</li>
<li>Once it gets going, I want template changes to be easy.</li>
<li>It should be as easy as Jekyll, so I need to be able to build it using GitHub Actions, where I can just commit a template change or Markdown file and away it goes. If I can't figure this out than fk it, just use Jekyll.</li>
<li>I require it to be used by a significant percent of my professional peers so I can get easy answers when something goes wrong.</li>
<li>I want source maps. This is a dev log site which means whatever I do with it should be easy for other developers to read.</li>
</ol>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Also <a href="https://www.npmjs.com/package/@quasibit/eleventy-plugin-sitemap" target="_blank">the sitemap plugin</a> looks cool. Should grab that later.</li>
</ul>
<s>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> So does the <a href="https://www.npmjs.com/package/eleventy-plugin-reading-time" target="_blank">reading time one</a>.</li>
</ul>
</s>
<ul class="task-list">
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Also <a href="https://github.com/jdsteinbach/eleventy-plugin-toc/" target="_blank">this TOC plugin</a> mby?</p>
</li>
<li class="task-list-item">
<p data-wordfix="true"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Use <a href="https://www.11ty.dev/docs/data-deep-merge/" target="_blank">Data Deep Merge</a> in this blog.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Decide if I want to render the CSS fancier than just a base file and do per-template splitting.</p>
</li>
</ul>
<s>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Can I use the template inside of dinky that already exists instead of copy/pasting it?</li>
</ul>
</s>
<s>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Is there a way to have permalinks to posts contain metadata without organizing them into subfolders?</li>
</ul>
</s>
<ul class="task-list">
<li class="task-list-item">
<p data-wordfix="true"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> How do I cachebreak files on the basis of new build events? Datetime? <code>site.github.build_revision</code> is <a href="https://github.com/jekyll/github-metadata/blob/master/docs/site.github.md" target="_blank">how Jekyll accomplishes this</a>, but is there a way to push <a href="https://docs.github.com/en/actions/reference/context-and-expression-syntax-for-github-actions#github-context" target="_blank">that</a> <a href="https://stackoverflow.com/questions/54310050/how-to-version-build-artifacts-using-github-actions" target="_blank">into the build process</a> for Eleventy?</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Make link text look less shitty. It looks like it is a whole, lighter, font.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Code blocks do not have good syntax highlighting. I want good syntax highlighting.</p>
</li>
<li class="task-list-item">
<p data-wordfix="true"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Build a Markdown-it plugin to take my typing shortcuts <code>[prob, b/c, ...?]</code> and expand them on build.</p>
</li>
</ul>
<s>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> See if we can start Markdown's interpretation of H tags to <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/Heading_Elements#multiple_h1" target="_blank">start at 2, since H1</a> is always pulled from the page title metadata. If it isn't easy, I just have to change my pattern of writing in the MD documents.</li>
</ul>
</s>
<ul class="task-list">
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Should I <a href="https://www.madebymike.com.au/writing/11ty-filters-data-shortcodes/" target="_blank">explore some shortcodes</a>?</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Order projects listing by last posted blog in that project</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Limit the output of home page post lists to a specific number of posts</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Show the latest post below the site intro on the homepage.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Tags pages with Pagination</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Posts should be able to support a preview header image that can also be shown on post lists.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Create a Markdown-It plugin that reads the project's repo URL off the folder data file and renders commit messages with <a href="https://stackoverflow.com/questions/15919635/on-github-api-what-is-the-best-way-to-get-the-last-commit-message-associated-w" target="_blank">links to the referenced commit</a>. (Is this even possible?) (Is there a way to do it with eleventy instead?)</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Create Next Day/Previous Day links on each post / Next/Previous post on post templates from projects</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Tags should be in the sidebar of articles and link to tag pages</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Create a skiplink for the todo section (or would this be better served with the ToC plugin?) - Yes it would be!</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Add a Things I Learned section to the project pages that are the things I learned from that specific project.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Add a technical reading log to the homepage</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/:empty" target="_blank">Hide</a> empty sections.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Add byline to post pages</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Have table of contents attach to sidebar bottom on mobile</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Support dark mode</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Social Icons</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> SEO/Social/JSON-LD HEAD data</p>
</li>
</ul>
<h2 id="day-41" tabindex="-1">Day 41</h2>
<p>Ok, so I want to continue to get a better understanding of Eleventy so as part of my end-of-project clean up I'm extracting tools I wrote for this blog into general use plugins. Yesterday, a Markdown-It plugin. Today, let's see if I can make my Sass plugin generally usable, since that seems to be missing in the Eleventy community.</p>
<h3 id="basic-eleventy-plugin-setup" tabindex="-1">Basic Eleventy Plugin Setup</h3>
<p>Ok, so let's look at some of the useful plugins I'm familiar with: <a href="https://github.com/jdsteinbach/eleventy-plugin-toc/blob/main/.eleventy.js" target="_blank">the TOC plugin</a> and <a href="https://github.com/takanorip/eleventy-google-fonts/blob/master/.eleventy.js" target="_blank">Eleventy Google Fonts</a>. These both handle different Eleventy flows and so are useful examples.</p>
<p>The first thing to note is that Eleventy plugins initiate with <code>.eleventy.js</code> files and take an <code>eleventyConfig</code> object and passed <code>options</code> object.</p>
<p>In the <code>.eleventy.js</code> file I'll set up a very basic structure and work in my original JS.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/sass-plugin/#code-skip-sass-plugin-6" id="skip-to-code-skip-sass-plugin-6" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> generateSass <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">"./src/generate-sass"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br />module<span class="token punctuation">.</span><span class="token function-variable function">exports</span> <span class="token operator">=</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">eleventyConfig<span class="token punctuation">,</span> options</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />	<span class="token keyword">return</span> <span class="token function">generateSass</span><span class="token punctuation">(</span>eleventyConfig<span class="token punctuation">,</span> options<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
<p id="code-skip-sass-plugin-6">Ok, so now what and how do I handle this eleventyConfig object? Well let's take a look at it:</p>
<p>So here's what an eleventyConfig object looks like:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/sass-plugin/#code-skip-sass-plugin-5" id="skip-to-code-skip-sass-plugin-5" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript">Eleventy Plugin Info UserConfig <span class="token punctuation">{</span><br />  <span class="token literal-property property">events</span><span class="token operator">:</span> EventEmitter <span class="token punctuation">{</span><br />    <span class="token literal-property property">_events</span><span class="token operator">:</span> <span class="token punctuation">[</span>Object<span class="token operator">:</span> <span class="token keyword">null</span> prototype<span class="token punctuation">]</span> <span class="token punctuation">{</span> <span class="token literal-property property">beforeWatch</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token function">Function</span> <span class="token punctuation">(</span>anonymous<span class="token punctuation">)</span><span class="token punctuation">]</span> <span class="token punctuation">}</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">_eventsCount</span><span class="token operator">:</span> <span class="token number">1</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">_maxListeners</span><span class="token operator">:</span> <span class="token keyword">undefined</span><span class="token punctuation">,</span><br />    <span class="token punctuation">[</span><span class="token function">Symbol</span><span class="token punctuation">(</span>kCapture<span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token operator">:</span> <span class="token boolean">false</span><br />  <span class="token punctuation">}</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">collections</span><span class="token operator">:</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">templateFormats</span><span class="token operator">:</span> <span class="token keyword">undefined</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">liquidOptions</span><span class="token operator">:</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">liquidTags</span><span class="token operator">:</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">liquidFilters</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />    <span class="token literal-property property">slug</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token function">Function</span> <span class="token punctuation">(</span>anonymous<span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">url</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token function">Function</span> <span class="token punctuation">(</span>anonymous<span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">log</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token function">Function</span> <span class="token punctuation">(</span>anonymous<span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">getCollectionItem</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token function">Function</span> <span class="token punctuation">(</span>anonymous<span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">getPreviousCollectionItem</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token function">Function</span> <span class="token punctuation">(</span>anonymous<span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">getNextCollectionItem</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token function">Function</span> <span class="token punctuation">(</span>anonymous<span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">eleventyNavigation</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token function">Function</span> <span class="token punctuation">(</span>anonymous<span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">eleventyNavigationBreadcrumb</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token function">Function</span> <span class="token punctuation">(</span>anonymous<span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">eleventyNavigationToHtml</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token function">Function</span> <span class="token punctuation">(</span>anonymous<span class="token punctuation">)</span><span class="token punctuation">]</span><br />  <span class="token punctuation">}</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">liquidShortcodes</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">sitemap</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token function">Function</span> <span class="token punctuation">(</span>anonymous<span class="token punctuation">)</span><span class="token punctuation">]</span> <span class="token punctuation">}</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">liquidPairedShortcodes</span><span class="token operator">:</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">nunjucksFilters</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />    <span class="token literal-property property">slug</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token function">Function</span> <span class="token punctuation">(</span>anonymous<span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">url</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token function">Function</span> <span class="token punctuation">(</span>anonymous<span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">log</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token function">Function</span> <span class="token punctuation">(</span>anonymous<span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">getCollectionItem</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token function">Function</span> <span class="token punctuation">(</span>anonymous<span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">getPreviousCollectionItem</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token function">Function</span> <span class="token punctuation">(</span>anonymous<span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">getNextCollectionItem</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token function">Function</span> <span class="token punctuation">(</span>anonymous<span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">eleventyNavigation</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token function">Function</span> <span class="token punctuation">(</span>anonymous<span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">eleventyNavigationBreadcrumb</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token function">Function</span> <span class="token punctuation">(</span>anonymous<span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">eleventyNavigationToHtml</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token function">Function</span> <span class="token punctuation">(</span>anonymous<span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">absoluteUrl</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token function">Function</span> <span class="token punctuation">(</span>anonymous<span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">getNewestCollectionItemDate</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token function">Function</span> <span class="token punctuation">(</span>anonymous<span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">dateToRfc3339</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token function">Function</span> <span class="token punctuation">(</span>anonymous<span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">rssLastUpdatedDate</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token function">Function</span> <span class="token punctuation">(</span>anonymous<span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">rssDate</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token function">Function</span> <span class="token punctuation">(</span>anonymous<span class="token punctuation">)</span><span class="token punctuation">]</span><br />  <span class="token punctuation">}</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">nunjucksAsyncFilters</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">htmlToAbsoluteUrls</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token function">Function</span> <span class="token punctuation">(</span>anonymous<span class="token punctuation">)</span><span class="token punctuation">]</span> <span class="token punctuation">}</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">nunjucksTags</span><span class="token operator">:</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">nunjucksShortcodes</span><span class="token operator">:</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">nunjucksAsyncShortcodes</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">sitemap</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token function">Function</span> <span class="token punctuation">(</span>anonymous<span class="token punctuation">)</span><span class="token punctuation">]</span> <span class="token punctuation">}</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">nunjucksPairedShortcodes</span><span class="token operator">:</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">nunjucksAsyncPairedShortcodes</span><span class="token operator">:</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">handlebarsHelpers</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />    <span class="token literal-property property">slug</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token function">Function</span> <span class="token punctuation">(</span>anonymous<span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">url</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token function">Function</span> <span class="token punctuation">(</span>anonymous<span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">log</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token function">Function</span> <span class="token punctuation">(</span>anonymous<span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">getCollectionItem</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token function">Function</span> <span class="token punctuation">(</span>anonymous<span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">getPreviousCollectionItem</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token function">Function</span> <span class="token punctuation">(</span>anonymous<span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">getNextCollectionItem</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token function">Function</span> <span class="token punctuation">(</span>anonymous<span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">eleventyNavigation</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token function">Function</span> <span class="token punctuation">(</span>anonymous<span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">eleventyNavigationBreadcrumb</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token function">Function</span> <span class="token punctuation">(</span>anonymous<span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">eleventyNavigationToHtml</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token function">Function</span> <span class="token punctuation">(</span>anonymous<span class="token punctuation">)</span><span class="token punctuation">]</span><br />  <span class="token punctuation">}</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">handlebarsShortcodes</span><span class="token operator">:</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">handlebarsPairedShortcodes</span><span class="token operator">:</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">javascriptFunctions</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />    <span class="token literal-property property">slug</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token function">Function</span> <span class="token punctuation">(</span>anonymous<span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">url</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token function">Function</span> <span class="token punctuation">(</span>anonymous<span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">log</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token function">Function</span> <span class="token punctuation">(</span>anonymous<span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">getCollectionItem</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token function">Function</span> <span class="token punctuation">(</span>anonymous<span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">getPreviousCollectionItem</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token function">Function</span> <span class="token punctuation">(</span>anonymous<span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">getNextCollectionItem</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token function">Function</span> <span class="token punctuation">(</span>anonymous<span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">eleventyNavigation</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token function">Function</span> <span class="token punctuation">(</span>anonymous<span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">eleventyNavigationBreadcrumb</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token function">Function</span> <span class="token punctuation">(</span>anonymous<span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">eleventyNavigationToHtml</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token function">Function</span> <span class="token punctuation">(</span>anonymous<span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">sitemap</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token function">Function</span> <span class="token punctuation">(</span>anonymous<span class="token punctuation">)</span><span class="token punctuation">]</span><br />  <span class="token punctuation">}</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">pugOptions</span><span class="token operator">:</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">ejsOptions</span><span class="token operator">:</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">markdownHighlighter</span><span class="token operator">:</span> <span class="token keyword">null</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">libraryOverrides</span><span class="token operator">:</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">passthroughCopies</span><span class="token operator">:</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">layoutAliases</span><span class="token operator">:</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">linters</span><span class="token operator">:</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">filters</span><span class="token operator">:</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">activeNamespace</span><span class="token operator">:</span> <span class="token string">''</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">DateTime</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token keyword">class</span> <span class="token class-name">DateTime</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">dynamicPermalinks</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">useGitIgnore</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">dataDeepMerge</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">extensionMap</span><span class="token operator">:</span> <span class="token function">Set</span><span class="token punctuation">(</span><span class="token parameter"><span class="token number">0</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">watchJavaScriptDependencies</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">additionalWatchTargets</span><span class="token operator">:</span> <span class="token punctuation">[</span> <span class="token string">'./_custom-plugins/'</span><span class="token punctuation">,</span> <span class="token string">'./src/_sass'</span> <span class="token punctuation">]</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">browserSyncConfig</span><span class="token operator">:</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">chokidarConfig</span><span class="token operator">:</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">watchThrottleWaitTime</span><span class="token operator">:</span> <span class="token number">0</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">dataExtensions</span><span class="token operator">:</span> <span class="token function">Map</span><span class="token punctuation">(</span><span class="token parameter"><span class="token number">0</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">quietMode</span><span class="token operator">:</span> <span class="token boolean">false</span><br /><span class="token punctuation">}</span></code></pre>
<p id="code-skip-sass-plugin-5">It turns out that none of these things are... directly accessible though? I'm not sure how to get into any of those. Well, I have the usual <code>eleventyConfig</code> tools though, so I guess that's the point.</p>
<p>Let's set some default options that I'll need to build CSS files along with URL-domain-based source maps.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/sass-plugin/#code-skip-sass-plugin-4" id="skip-to-code-skip-sass-plugin-4" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> pluginDefaults <span class="token operator">=</span> <span class="token punctuation">{</span><br />	<span class="token literal-property property">domainName</span><span class="token operator">:</span> <span class="token string">"http://localhost:8080"</span><span class="token punctuation">,</span><br />	<span class="token literal-property property">includePaths</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">"**/*.{scss,sass}"</span><span class="token punctuation">,</span> <span class="token string">"!node_modules/**"</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br />	<span class="token literal-property property">sassLocation</span><span class="token operator">:</span> path<span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span>path<span class="token punctuation">.</span><span class="token function">resolve</span><span class="token punctuation">(</span><span class="token string">"../../"</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token string">"src/_sass/"</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br />	<span class="token literal-property property">sassIndexFile</span><span class="token operator">:</span> <span class="token string">"_index.sass"</span><span class="token punctuation">,</span><br />	<span class="token literal-property property">outDir</span><span class="token operator">:</span> path<span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span>path<span class="token punctuation">.</span><span class="token function">resolve</span><span class="token punctuation">(</span><span class="token string">"../../"</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token string">"docs"</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br />	<span class="token literal-property property">outPath</span><span class="token operator">:</span> <span class="token string">"/assets/css/"</span><span class="token punctuation">,</span><br />	<span class="token literal-property property">sourceMap</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span><br />	<span class="token literal-property property">perTemplateFiles</span><span class="token operator">:</span> <span class="token string">"template-"</span><span class="token punctuation">,</span><br />	<span class="token literal-property property">cacheBreak</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span><br /><span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
<p id="code-skip-sass-plugin-4">It's a lot, I know, but I don't think there's any way around it.</p>
<p>I could use <code>addTransform</code> to alter the HTML output to add the CSS to it, but as I explore more plugins it seems like the way to do this is to supply a shortcode and let the user leverage it. It would be fun to play with this, but I think I may end up removing it.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/sass-plugin/#code-skip-sass-plugin-3" id="skip-to-code-skip-sass-plugin-3" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript">	eleventyConfig<span class="token punctuation">.</span><span class="token function">addTransform</span><span class="token punctuation">(</span><span class="token string">"sassCore"</span><span class="token punctuation">,</span> <span class="token keyword">async</span> <span class="token punctuation">(</span><span class="token parameter">content<span class="token punctuation">,</span> outputPath</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />		<span class="token keyword">if</span> <span class="token punctuation">(</span>outputPath <span class="token operator">&amp;&amp;</span> outputPath<span class="token punctuation">.</span><span class="token function">endsWith</span><span class="token punctuation">(</span><span class="token string">".html"</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />		<span class="token punctuation">}</span><br /><br />		<span class="token keyword">return</span> content<span class="token punctuation">;</span><br />	<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p id="code-skip-sass-plugin-3">Ok, so I'll split this into three files to make it easy to handle, one each for: generating Sass stuff in the Eleventy context, creating Sass strings, writing Sass strings to the correct location.</p>
<p>It looks like my use of <code>renderSync</code> has been depreciated and <a href="https://sass-lang.com/documentation/js-api/modules#compile" target="_blank">replaced by <code>compile</code></a>. Ok.</p>
<p>You know what? I'm just going to lock patch version. I don't want to deal with this badly documented transition right now and it looks like <code>compile</code> is missing some options I depend on and has transformed other options to a new unclear property.</p>
<p>Now dependencies looks like:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/sass-plugin/#code-skip-sass-plugin-2" id="skip-to-code-skip-sass-plugin-2" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript">  <span class="token string-property property">"dependencies"</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />    <span class="token string-property property">"sass"</span><span class="token operator">:</span> <span class="token string">"~1.45.1"</span><br />  <span class="token punctuation">}</span></code></pre>
<p id="code-skip-sass-plugin-2">This feels like a problem I keep encountering in the Sass project which is that... it's a mess for no good reason and it doesn't do a great job documenting changes. Frustrating.</p>
<p>Ok, let's seperate out the functions and put in the variables.</p>
<p>Note to self: can't assume users are in Eleventy v1, so <code>addGlobalData</code> is out.</p>
<p>Ok, how am I going to pass my plugin options into the shortcode? <a href="https://github.com/gfscott/eleventy-plugin-youtube-embed/blob/main/.eleventy.js" target="_blank">Looks like it is in-scope as long as I have the call inside my function</a>.</p>
<p>Ok, some difficulty in making sure I get all my file names correct, but nothing to do other then 3 or 4 or 5 iterations until I'm sure all my filepaths are correct. Just keep going!</p>
<p>Ok, a little more fiddling on file names and source maps' names. Alrighty! It looks good.</p>
<p data-wordfix="true">Looks like <a href="https://www.11ty.dev/docs/events/#beforebuild" target="_blank">there is a way</a> I can make it rebuild that Sass on every build, even <code>watch</code> builds.</p>
<p>Let's test it as a module!</p>
<p>Oh right, I can't call it this. There's already <a href="https://www.npmjs.com/package/eleventy-plugin-sass" target="_blank">a plugin called &quot;eleventy-plugin-sass&quot;</a> that I struggled with <a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-1/" target="_blank">on Day 1</a>! Ok, let's call it the more accurate &quot;eleventy-plugin-dart-sass&quot;.</p>
<p>Works with passed configuration options. Let's try it with the defaults. Oo, nope. Ok, more path fiddling!</p>
<p>New default object figured out:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/sass-plugin/#code-skip-sass-plugin-1" id="skip-to-code-skip-sass-plugin-1" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> pluginDefaults <span class="token operator">=</span> <span class="token punctuation">{</span><br />	<span class="token literal-property property">domainName</span><span class="token operator">:</span> <span class="token string">"http://localhost:8080"</span><span class="token punctuation">,</span><br />	<span class="token literal-property property">includePaths</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">"**/*.{scss,sass}"</span><span class="token punctuation">,</span> <span class="token string">"!node_modules/**"</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br />	<span class="token literal-property property">sassLocation</span><span class="token operator">:</span> path<span class="token punctuation">.</span><span class="token function">normalize</span><span class="token punctuation">(</span>path<span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span>__dirname<span class="token punctuation">,</span> <span class="token string">"../../../"</span><span class="token punctuation">,</span> <span class="token string">"src/_sass/"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br />	<span class="token literal-property property">sassIndexFile</span><span class="token operator">:</span> <span class="token string">"_index.sass"</span><span class="token punctuation">,</span><br />	<span class="token literal-property property">outDir</span><span class="token operator">:</span> path<span class="token punctuation">.</span><span class="token function">normalize</span><span class="token punctuation">(</span>path<span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span>__dirname<span class="token punctuation">,</span> <span class="token string">"../../../"</span><span class="token punctuation">,</span> <span class="token string">"docs"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br />	<span class="token literal-property property">outPath</span><span class="token operator">:</span> <span class="token string">"/assets/css/"</span><span class="token punctuation">,</span><br />	<span class="token literal-property property">outFileName</span><span class="token operator">:</span> <span class="token string">"style"</span><span class="token punctuation">,</span><br />	<span class="token literal-property property">sourceMap</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span><br />	<span class="token literal-property property">perTemplateFiles</span><span class="token operator">:</span> <span class="token string">"template-"</span><span class="token punctuation">,</span><br />	<span class="token literal-property property">cacheBreak</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span><br />	<span class="token literal-property property">outputStyle</span><span class="token operator">:</span> <span class="token string">"compressed"</span><span class="token punctuation">,</span><br />	<span class="token literal-property property">watchSass</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span><br /><span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
<p id="code-skip-sass-plugin-1">Ok, yeah, everything is working now and even smoother than before! I guess I should write some tests? But that seems really really complicated right? I'm not sure where to start. Ok... well... maybe something to come back to. I'm going to write the docs and update the package. Let's test how it builds on remote first.</p>
<p>Oh, right, I need to path the paths until I update the NPM package. Ok, I will fix that annnnnddddd..... yeah, it works! Yay!</p>
<p>Ok, let's add the readme!</p>
<p>And <a href="https://www.npmjs.com/package/eleventy-plugin-dart-sass" target="_blank">it is published</a>!</p>
<p><a target="_blank" href="https://github.com/AramZS/devblog/commit/cd1a78c164a09b0ebdd8d05cc10252937f7d987b" class="git-commit-link"><code>git commit -am &quot;Add final notes for the Sass Plugin&quot;</code></a></p>
]]></content:encoded>
	</item>
	
	<item>
		<title>Markdown It Find and Replace as Plugin</title>
		<link>https://fightwithtools.dev/posts/projects/devblog/markdown-it-find-and-replace/?source=rss</link>
		<pubDate>Sat, 27 Nov 2021 02:59:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/projects/devblog/markdown-it-find-and-replace/</guid>
		<description>More devblog</description>
		<content:encoded><![CDATA[<h2 id="project-scope-and-todos" tabindex="-1">Project Scope and ToDos</h2>
<ol>
<li>Static Site Generator that can build the blog and let me host it on Github Pages</li>
<li>I want to write posts in Markdown because I'm lazy, it's easy, and it is how I take notes now.</li>
<li>I don't want to spend a ton of time doing design work. I'm doing complicated designs for other projects, so I want to pull a theme I like that I can rely on someone else to keep up.</li>
<li>Once it gets going, I want template changes to be easy.</li>
<li>It should be as easy as Jekyll, so I need to be able to build it using GitHub Actions, where I can just commit a template change or Markdown file and away it goes. If I can't figure this out than fk it, just use Jekyll.</li>
<li>I require it to be used by a significant percent of my professional peers so I can get easy answers when something goes wrong.</li>
<li>I want source maps. This is a dev log site which means whatever I do with it should be easy for other developers to read.</li>
</ol>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Also <a href="https://www.npmjs.com/package/@quasibit/eleventy-plugin-sitemap" target="_blank">the sitemap plugin</a> looks cool. Should grab that later.</li>
</ul>
<s>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> So does the <a href="https://www.npmjs.com/package/eleventy-plugin-reading-time" target="_blank">reading time one</a>.</li>
</ul>
</s>
<ul class="task-list">
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Also <a href="https://github.com/jdsteinbach/eleventy-plugin-toc/" target="_blank">this TOC plugin</a> mby?</p>
</li>
<li class="task-list-item">
<p data-wordfix="true"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Use <a href="https://www.11ty.dev/docs/data-deep-merge/" target="_blank">Data Deep Merge</a> in this blog.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Decide if I want to render the CSS fancier than just a base file and do per-template splitting.</p>
</li>
</ul>
<s>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Can I use the template inside of dinky that already exists instead of copy/pasting it?</li>
</ul>
</s>
<s>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Is there a way to have permalinks to posts contain metadata without organizing them into subfolders?</li>
</ul>
</s>
<ul class="task-list">
<li class="task-list-item">
<p data-wordfix="true"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> How do I cachebreak files on the basis of new build events? Datetime? <code>site.github.build_revision</code> is <a href="https://github.com/jekyll/github-metadata/blob/master/docs/site.github.md" target="_blank">how Jekyll accomplishes this</a>, but is there a way to push <a href="https://docs.github.com/en/actions/reference/context-and-expression-syntax-for-github-actions#github-context" target="_blank">that</a> <a href="https://stackoverflow.com/questions/54310050/how-to-version-build-artifacts-using-github-actions" target="_blank">into the build process</a> for Eleventy?</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Make link text look less shitty. It looks like it is a whole, lighter, font.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Code blocks do not have good syntax highlighting. I want good syntax highlighting.</p>
</li>
<li class="task-list-item">
<p data-wordfix="true"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Build a Markdown-it plugin to take my typing shortcuts <code>[prob, b/c, ...?]</code> and expand them on build.</p>
</li>
</ul>
<s>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> See if we can start Markdown's interpretation of H tags to <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/Heading_Elements#multiple_h1" target="_blank">start at 2, since H1</a> is always pulled from the page title metadata. If it isn't easy, I just have to change my pattern of writing in the MD documents.</li>
</ul>
</s>
<ul class="task-list">
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Should I <a href="https://www.madebymike.com.au/writing/11ty-filters-data-shortcodes/" target="_blank">explore some shortcodes</a>?</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Order projects listing by last posted blog in that project</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Limit the output of home page post lists to a specific number of posts</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Show the latest post below the site intro on the homepage.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Tags pages with Pagination</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Posts should be able to support a preview header image that can also be shown on post lists.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Create a Markdown-It plugin that reads the project's repo URL off the folder data file and renders commit messages with <a href="https://stackoverflow.com/questions/15919635/on-github-api-what-is-the-best-way-to-get-the-last-commit-message-associated-w" target="_blank">links to the referenced commit</a>. (Is this even possible?) (Is there a way to do it with eleventy instead?)</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Create Next Day/Previous Day links on each post / Next/Previous post on post templates from projects</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Tags should be in the sidebar of articles and link to tag pages</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Create a skiplink for the todo section (or would this be better served with the ToC plugin?) - Yes it would be!</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Add a Things I Learned section to the project pages that are the things I learned from that specific project.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Add a technical reading log to the homepage</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/:empty" target="_blank">Hide</a> empty sections.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Add byline to post pages</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Have table of contents attach to sidebar bottom on mobile</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Support dark mode</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Social Icons</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> SEO/Social/JSON-LD HEAD data</p>
</li>
</ul>
<h2 id="day-40" tabindex="-1">Day 40</h2>
<p>Ok, so I want to make my pretty simple but very useful Markdown-it short phrase replacer into a stand alone NPM package that others can use.</p>
<p>I need to set up the project, add the package.json file, the .npmignore file, the README and the other chunks of the initial setup.</p>
<p>The other thing I need to do is set it up so that a developer can pass in the patterns and replacement rules. So no more using a function outside of the exported function. Instead I need to let others pull it in. I also want to add some test coverage. I've always used Jest for testing, but never Mocha, so <a href="https://mochajs.org/#installation" target="_blank">let's try doing that</a>! I'll review the docs.</p>
<p>Good thing I wish they called out with more emphasis:</p>
<blockquote>
<p>Passing arrow functions (aka “lambdas”) to Mocha is discouraged. Lambdas lexically bind this and cannot access the Mocha context.</p>
</blockquote>
<p>I want to start testing, but that will mean a devDependency for markdown-it. It also made me realize <a href="https://nodejs.org/es/blog/npm/peer-dependencies/" target="_blank">I need to define a <code>peerDependencies</code> object</a>.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/markdown-it-find-and-replace/#code-skip-markdown-it-find-and-replace-2" id="skip-to-code-skip-markdown-it-find-and-replace-2" class="skip-link">Skip code block ▼</a></p>
<pre class="language-json"><code class="language-json"><span class="token property">"peerDependencies"</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />  <span class="token property">"markdown-it"</span><span class="token operator">:</span> <span class="token string">"*"</span><br /><span class="token punctuation">}</span></code></pre>
<p id="code-skip-markdown-it-find-and-replace-2">I want to test that the errors being thrown are working as expected, so <a href="https://github.com/Automattic/expect.js" target="_blank">I'm going to grab <code>expect.js</code></a>.</p>
<p>Using that I need to initiate the function I want to dump and error into the <code>expect</code> statement. And I need it to explicitly match a regex pattern (feeding a string in apparently doesn't work).</p>
<p>Ok, this works!</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/markdown-it-find-and-replace/#code-skip-markdown-it-find-and-replace-1" id="skip-to-code-skip-markdown-it-find-and-replace-1" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript"><span class="token function">it</span><span class="token punctuation">(</span><span class="token string">"should not initiate without an array"</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />	<span class="token function">expect</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token function">mdProcessor</span><span class="token punctuation">(</span>options<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">use</span><span class="token punctuation">(</span>plugin<span class="token punctuation">,</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">.</span>to<span class="token punctuation">.</span><span class="token function">throwException</span><span class="token punctuation">(</span><br />		<span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">Markdown-It-Find-and-Replace requires that options\.replaceRules be an array\.</span><span class="token regex-delimiter">/</span></span><br />	<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p id="code-skip-markdown-it-find-and-replace-1">Let's throw some more tests on there!</p>
<p>Ok, it works.</p>
<p data-wordfix="true">Oh, and in writing the tests I realized I don't have a setup for when it starts a sentence or token content or when it ends one! I can fix that though with a few more regexs.</p>
<p>Ok, plugin looks good. Tests work. You know what's sort of strange, I've never created an NPM module that I've also published before. I guess this is the first time! <a href="https://docs.npmjs.com/creating-a-new-npm-user-account" target="_blank">Let's go</a>!</p>
<p>I already have an NPM account I created earlier, so that part is easy.</p>
<p>I'll reformat my author property to match their requirements.</p>
<p>I tried pulling it into this project and it looks like it works, so I think the code is good to go.</p>
<p><code>npm publish --access public</code></p>
<p>Ok, that was easy!</p>
<p>I'll pull it in to this project and see if that version works.</p>
<p>And it does!</p>
<p>Awesome, made it into a module that hopefully some other people will find useful!</p>
<p>I'll add some documentation and update that and we're done! Very useful!</p>
<p><code>npm publish</code> to update the package listing.</p>
<p><a href="https://www.npmjs.com/package/markdown-it-find-and-replace" target="_blank">Markdown It plugin package is live and ready for others to use</a>!</p>
<p><a target="_blank" href="https://github.com/AramZS/devblog/commit/874612e280360a5ca95f22278c4ce5949cf50fb9" class="git-commit-link"><code>git commit -am &quot;Switching to use my newly published markdown-it plugin&quot;</code></a></p>
]]></content:encoded>
	</item>
	
	<item>
		<title>Part 39: Tweaking Code Blocks and Adding Skip Links</title>
		<link>https://fightwithtools.dev/posts/projects/devblog/hello-day-39/?source=rss</link>
		<pubDate>Fri, 26 Nov 2021 02:59:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/projects/devblog/hello-day-39/</guid>
		<description>More devblog</description>
		<content:encoded><![CDATA[<h2 id="project-scope-and-todos" tabindex="-1">Project Scope and ToDos</h2>
<ol>
<li>Static Site Generator that can build the blog and let me host it on Github Pages</li>
<li>I want to write posts in Markdown because I'm lazy, it's easy, and it is how I take notes now.</li>
<li>I don't want to spend a ton of time doing design work. I'm doing complicated designs for other projects, so I want to pull a theme I like that I can rely on someone else to keep up.</li>
<li>Once it gets going, I want template changes to be easy.</li>
<li>It should be as easy as Jekyll, so I need to be able to build it using GitHub Actions, where I can just commit a template change or Markdown file and away it goes. If I can't figure this out than fk it, just use Jekyll.</li>
<li>I require it to be used by a significant percent of my professional peers so I can get easy answers when something goes wrong.</li>
<li>I want source maps. This is a dev log site which means whatever I do with it should be easy for other developers to read.</li>
</ol>
<ul class="task-list">
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Also <a href="https://www.npmjs.com/package/@quasibit/eleventy-plugin-sitemap" target="_blank">the sitemap plugin</a> looks cool. Should grab that later.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> So does the <a href="https://www.npmjs.com/package/eleventy-plugin-reading-time" target="_blank">reading time one</a>.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Also <a href="https://github.com/jdsteinbach/eleventy-plugin-toc/" target="_blank">this TOC plugin</a> mby?</p>
</li>
<li class="task-list-item">
<p data-wordfix="true"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Use <a href="https://www.11ty.dev/docs/data-deep-merge/" target="_blank">Data Deep Merge</a> in this blog.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Decide if I want to render the CSS fancier than just a base file and do per-template splitting.</p>
</li>
</ul>
<s>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Can I use the template inside of dinky that already exists instead of copy/pasting it?</li>
</ul>
</s>
<s>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Is there a way to have permalinks to posts contain metadata without organizing them into subfolders?</li>
</ul>
</s>
<ul class="task-list">
<li class="task-list-item">
<p data-wordfix="true"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> How do I cachebreak files on the basis of new build events? Datetime? <code>site.github.build_revision</code> is <a href="https://github.com/jekyll/github-metadata/blob/master/docs/site.github.md" target="_blank">how Jekyll accomplishes this</a>, but is there a way to push <a href="https://docs.github.com/en/actions/reference/context-and-expression-syntax-for-github-actions#github-context" target="_blank">that</a> <a href="https://stackoverflow.com/questions/54310050/how-to-version-build-artifacts-using-github-actions" target="_blank">into the build process</a> for Eleventy?</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Make link text look less shitty. It looks like it is a whole, lighter, font.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Code blocks do not have good syntax highlighting. I want good syntax highlighting.</p>
</li>
<li class="task-list-item">
<p data-wordfix="true"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Build a Markdown-it plugin to take my typing shortcuts <code>[prob, b/c, ...?]</code> and expand them on build.</p>
</li>
</ul>
<s>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> See if we can start Markdown's interpretation of H tags to <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/Heading_Elements#multiple_h1" target="_blank">start at 2, since H1</a> is always pulled from the page title metadata. If it isn't easy, I just have to change my pattern of writing in the MD documents.</li>
</ul>
</s>
<ul class="task-list">
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Should I <a href="https://www.madebymike.com.au/writing/11ty-filters-data-shortcodes/" target="_blank">explore some shortcodes</a>?</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Order projects listing by last posted blog in that project</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Limit the output of home page post lists to a specific number of posts</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Show the latest post below the site intro on the homepage.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Tags pages with Pagination</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Posts should be able to support a preview header image that can also be shown on post lists.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Create a Markdown-It plugin that reads the project's repo URL off the folder data file and renders commit messages with <a href="https://stackoverflow.com/questions/15919635/on-github-api-what-is-the-best-way-to-get-the-last-commit-message-associated-w" target="_blank">links to the referenced commit</a>. (Is this even possible?) (Is there a way to do it with eleventy instead?)</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Create Next Day/Previous Day links on each post / Next/Previous post on post templates from projects</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Tags should be in the sidebar of articles and link to tag pages</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Create a skiplink for the todo section (or would this be better served with the ToC plugin?) - Yes it would be!</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Add a Things I Learned section to the project pages that are the things I learned from that specific project.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Add a technical reading log to the homepage</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/:empty" target="_blank">Hide</a> empty sections.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Add byline to post pages</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Have table of contents attach to sidebar bottom on mobile</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Support dark mode</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Social Icons</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> SEO/Social/JSON-LD HEAD data</p>
</li>
</ul>
<h2 id="day-39" tabindex="-1">Day 39</h2>
<p>Look at this! Every checkmark I want to check off is checked off! Now all I have left to do is close off the last few things that are broken!</p>
<h3 id="fix-anchors" tabindex="-1">Fix anchors</h3>
<p>My anchor link generator is being broken by double-quote marks.</p>
<p>I'll change the configuration for <code>markdown-it-anchor</code> as follows:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-39/#code-skip-hello-day-39-16" id="skip-to-code-skip-hello-day-39-16" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript"><span class="token punctuation">.</span><span class="token function">use</span><span class="token punctuation">(</span><span class="token function">require</span><span class="token punctuation">(</span><span class="token string">"markdown-it-anchor"</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token punctuation">{</span><br />			<span class="token function-variable function">slugify</span><span class="token operator">:</span> <span class="token punctuation">(</span><span class="token parameter">s</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token function">slugify</span><span class="token punctuation">(</span>s<span class="token punctuation">.</span><span class="token function">toLowerCase</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span><span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">"</span><span class="token regex-delimiter">/</span><span class="token regex-flags">g</span></span><span class="token punctuation">,</span> <span class="token string">""</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br />		<span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre>
<p id="code-skip-hello-day-39-16">And yeah, that works!</p>
<h3 id="making-code-blocks-more-readable" tabindex="-1">Making Code Blocks More Readable</h3>
<p>So I'm going to make a few changes to the codeblocks in general here to make them more consumable.</p>
<p>First, it looks like the wisdom of the crowds is leaning towards wrapping code lines. So I'm going to add some CSSto do that:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-39/#code-skip-hello-day-39-15" id="skip-to-code-skip-hello-day-39-15" class="skip-link">Skip code block ▼</a></p>
<pre class="language-css"><code class="language-css"><span class="token selector">code[class*="language-"], pre[class*="language-"]</span> <span class="token punctuation">{</span><br />	<span class="token property">white-space</span><span class="token punctuation">:</span>pre-wrap<span class="token punctuation">;</span><br /><span class="token punctuation">}</span></code></pre>
<p id="code-skip-hello-day-39-15">Next, I use 4-space tabs and that can make my code blocks pretty roomy. Let's resize those tabs by adding a new property to the same css rule. Instead I can shrink it down to <code>1em</code> with <code>tab-size: 1em;</code>. This won't change spaces in codeblocks like YAML, but it helps with most of the rest I think.</p>
<p>There's one problem that I don't think I can solve with CSS? Some of my early code blocks take the tab level of their files so they have a bunch of extra tabs that aren't needed and make them less readable. Is there a way to fix this? I can't think of one, so I'll just try and remember to collapse my code blocks to start at zero tabs.</p>
<p>Finally, for the very long code blocks, they <em>badly</em> need skip links, both for accessibility and good UI reasons.</p>
<p>I guess... this needs to be another markdown-it plugin? That is where the code-blocks are made. Ok!</p>
<p><a target="_blank" href="https://github.com/AramZS/devblog/commit/47464cbd5d34d5a1ad5ed1aef0bc001ccde6956b" class="git-commit-link"><code>git commit -am &quot;Fix some basic readability issues&quot;</code></a></p>
<h3 id="add-skip-links-to-code-blocks" tabindex="-1">Add skip links to code blocks</h3>
<p>Ok, I'm not going to make the same mistake I did before of starting in my <code>.eleventy</code> file. Let's open up a new custom plugin folder.</p>
<p>Now, because of my investigation on <a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-36/" target="_blank">Day 36</a> I know that there is a <code>code_block</code> rule that is absolutely the one I'm going to need to deal with. And, because I need to manipulate the token tree <em>around</em> the code block, I know that I'm going to have to use <code>ruler</code> and not <code>renderer</code>.</p>
<p>Ok, so first I'm going to figure out what token types exist:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-39/#code-skip-hello-day-39-14" id="skip-to-code-skip-hello-day-39-14" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript">console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Token Types'</span><span class="token punctuation">,</span> state<span class="token punctuation">.</span>tokens<span class="token punctuation">.</span><span class="token function">reduce</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">prevV<span class="token punctuation">,</span> currV</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />	<span class="token keyword">return</span> prevV<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span>currV<span class="token punctuation">.</span>type<span class="token punctuation">)</span><br /><span class="token punctuation">}</span><span class="token punctuation">,</span><span class="token keyword">new</span> <span class="token class-name">Set</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span></code></pre>
<p id="code-skip-hello-day-39-14">Result:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-39/#code-skip-hello-day-39-13" id="skip-to-code-skip-hello-day-39-13" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript"><span class="token punctuation">[</span><br />  <span class="token string">'ordered_list_open'</span><span class="token punctuation">,</span><br />  <span class="token string">'list_item_open'</span><span class="token punctuation">,</span><br />  <span class="token string">'paragraph_open'</span><span class="token punctuation">,</span><br />  <span class="token string">'inline'</span><span class="token punctuation">,</span><br />  <span class="token string">'paragraph_close'</span><span class="token punctuation">,</span><br />  <span class="token string">'list_item_close'</span><span class="token punctuation">,</span><br />  <span class="token string">'ordered_list_close'</span><span class="token punctuation">,</span><br />  <span class="token string">'bullet_list_open'</span><span class="token punctuation">,</span><br />  <span class="token string">'bullet_list_close'</span><span class="token punctuation">,</span><br />  <span class="token string">'html_block'</span><span class="token punctuation">,</span><br />  <span class="token string">'heading_open'</span><span class="token punctuation">,</span><br />  <span class="token string">'heading_close'</span><span class="token punctuation">,</span><br />  <span class="token string">'blockquote_open'</span><span class="token punctuation">,</span><br />  <span class="token string">'blockquote_close'</span><span class="token punctuation">,</span><br />  <span class="token string">'fence'</span><br /><span class="token punctuation">]</span></code></pre>
<p id="code-skip-hello-day-39-13">Ok, so nothing clearly shows my codeblocks. So, let's try a different strategy. What about looking for my markdown codeblock indicator the three backticks?</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-39/#code-skip-hello-day-39-12" id="skip-to-code-skip-hello-day-39-12" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">let</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&lt;</span> tokens<span class="token punctuation">.</span>length<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />	<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">```</span><span class="token regex-delimiter">/</span></span><span class="token punctuation">.</span><span class="token function">test</span><span class="token punctuation">(</span>tokens<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">.</span>content<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">{</span><br />		console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>tokens<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">)</span><br />	<span class="token punctuation">}</span><br /><span class="token punctuation">}</span></code></pre>
<p id="code-skip-hello-day-39-12">Nope...</p>
<p>Ok, let's look for <code>&lt;code&gt;</code>?</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-39/#code-skip-hello-day-39-11" id="skip-to-code-skip-hello-day-39-11" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">let</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&lt;</span> tokens<span class="token punctuation">.</span>length<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />	<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">\&lt;code\></span><span class="token regex-delimiter">/</span></span><span class="token punctuation">.</span><span class="token function">test</span><span class="token punctuation">(</span>tokens<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">.</span>content<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">{</span><br />		console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>tokens<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">)</span><br />	<span class="token punctuation">}</span><br /><span class="token punctuation">}</span></code></pre>
<p id="code-skip-hello-day-39-11">Ok, that sort of worked! This is good!</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-39/#code-skip-hello-day-39-10" id="skip-to-code-skip-hello-day-39-10" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript">Token <span class="token punctuation">{</span><br />  <span class="token literal-property property">type</span><span class="token operator">:</span> <span class="token string">'fence'</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">tag</span><span class="token operator">:</span> <span class="token string">'code'</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">attrs</span><span class="token operator">:</span> <span class="token keyword">null</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">map</span><span class="token operator">:</span> <span class="token punctuation">[</span> <span class="token number">161</span><span class="token punctuation">,</span> <span class="token number">168</span> <span class="token punctuation">]</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">nesting</span><span class="token operator">:</span> <span class="token number">0</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">level</span><span class="token operator">:</span> <span class="token number">0</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">children</span><span class="token operator">:</span> <span class="token keyword">null</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">content</span><span class="token operator">:</span> <span class="token string">'for (let i = 0; i &lt; tokens.length; i++) {\n'</span> <span class="token operator">+</span><br />    <span class="token string">'\tif (/```/.test(tokens[i].content)){\n'</span> <span class="token operator">+</span><br />    <span class="token string">'\t\tconsole.log(tokens[i])\n'</span> <span class="token operator">+</span><br />    <span class="token string">'\t}\n'</span> <span class="token operator">+</span><br />    <span class="token string">'}\n'</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">markup</span><span class="token operator">:</span> <span class="token string">'```'</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">info</span><span class="token operator">:</span> <span class="token string">'javascript'</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">meta</span><span class="token operator">:</span> <span class="token keyword">null</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">block</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">hidden</span><span class="token operator">:</span> <span class="token boolean">false</span><br /><span class="token punctuation">}</span></code></pre>
<p id="code-skip-hello-day-39-10">Interesting. Maybe this could eventually be a way to fix some of the bad tabbing? I think this is a little out of scope, so I'll put that aside for now. This is a good place to start!</p>
<p>What does this token tree look like? Maybe I can look around it.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-39/#code-skip-hello-day-39-9" id="skip-to-code-skip-hello-day-39-9" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">let</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&lt;</span> tokens<span class="token punctuation">.</span>length<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />	<span class="token keyword">if</span> <span class="token punctuation">(</span>tokens<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">.</span>type <span class="token operator">==</span> <span class="token string">"fence"</span> <span class="token operator">&amp;&amp;</span> tokens<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">.</span>tag <span class="token operator">==</span> <span class="token string">"code"</span><span class="token punctuation">)</span><span class="token punctuation">{</span><br />		console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>tokens<span class="token punctuation">[</span>i<span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">,</span> tokens<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">,</span> tokens<span class="token punctuation">[</span>i<span class="token operator">+</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">)</span><br />	<span class="token punctuation">}</span><br /><span class="token punctuation">}</span></code></pre>
<p id="code-skip-hello-day-39-9">Ok, I guess there isn't anything relevant? All are surrounded by <code>paragraph_close</code> and <code>paragraph_open</code>. So I'll need to construct the skip links around the token basically from scratch. Likely I'll need to create new paragraphs?</p>
<p>Though to make the skip link work effectively I think I'll need to add an ID to the following <code>paragraph_open</code> token that looks like this:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-39/#code-skip-hello-day-39-8" id="skip-to-code-skip-hello-day-39-8" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript">Token <span class="token punctuation">{</span><br />  <span class="token literal-property property">type</span><span class="token operator">:</span> <span class="token string">'paragraph_open'</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">tag</span><span class="token operator">:</span> <span class="token string">'p'</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">attrs</span><span class="token operator">:</span> <span class="token punctuation">[</span> <span class="token punctuation">[</span> <span class="token string">'data-wordfix'</span><span class="token punctuation">,</span> <span class="token string">'true'</span> <span class="token punctuation">]</span> <span class="token punctuation">]</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">map</span><span class="token operator">:</span> <span class="token punctuation">[</span> <span class="token number">113</span><span class="token punctuation">,</span> <span class="token number">114</span> <span class="token punctuation">]</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">nesting</span><span class="token operator">:</span> <span class="token number">1</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">level</span><span class="token operator">:</span> <span class="token number">0</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">children</span><span class="token operator">:</span> <span class="token keyword">null</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">content</span><span class="token operator">:</span> <span class="token string">''</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">markup</span><span class="token operator">:</span> <span class="token string">''</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">info</span><span class="token operator">:</span> <span class="token string">''</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">meta</span><span class="token operator">:</span> <span class="token keyword">null</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">block</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">hidden</span><span class="token operator">:</span> <span class="token boolean">false</span><br /><span class="token punctuation">}</span></code></pre>
<p id="code-skip-hello-day-39-8"><a target="_blank" href="https://github.com/AramZS/devblog/commit/28b520ed3b9bdad03c8c470a9113c330ea69fb94" class="git-commit-link"><code>git commit -am &quot;Saving part way through day 39&quot;</code></a></p>
<p>I'll also need some way to name the skip links. I've been thinking about this and I think I should be able to just increment a count on <code>state.env</code> since Markdown It processing occurs synchronously, right? I can pull the <code>fileSlug</code> off the page object just to be sure the anchor links are unique enough.</p>
<p>Ok, so I'm going to create the skip link name:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-39/#code-skip-hello-day-39-7" id="skip-to-code-skip-hello-day-39-7" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>env<span class="token punctuation">.</span>state<span class="token punctuation">.</span>page<span class="token punctuation">.</span><span class="token function">hasOwnProperty</span><span class="token punctuation">(</span><span class="token string">'skipCount'</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">{</span><br />	env<span class="token punctuation">.</span>state<span class="token punctuation">.</span>page<span class="token punctuation">.</span>skipCount <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span><br /><span class="token keyword">const</span> skipCount <span class="token operator">=</span> env<span class="token punctuation">.</span>state<span class="token punctuation">.</span>page<span class="token punctuation">.</span>skipCount <span class="token operator">+</span> <span class="token number">1</span><br />env<span class="token punctuation">.</span>state<span class="token punctuation">.</span>page<span class="token punctuation">.</span>skipCount <span class="token operator">=</span> skipCount<span class="token punctuation">;</span><br /><span class="token keyword">const</span> skipName <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">code-skip-</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>skipCount<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span></code></pre>
<p id="code-skip-hello-day-39-7">And I'm going to apply the skip name to the following paragraph. But, what if the next block isn't a paragraph? I guess we got to check for that.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-39/#code-skip-hello-day-39-6" id="skip-to-code-skip-hello-day-39-6" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> foundGraf <span class="token operator">=</span> <span class="token boolean">false</span><br /><span class="token keyword">let</span> nextI <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span><br /><span class="token keyword">while</span> <span class="token punctuation">(</span><span class="token operator">!</span>foundGraf<span class="token punctuation">)</span> <span class="token punctuation">{</span><br />	<span class="token keyword">if</span> <span class="token punctuation">(</span>tokens<span class="token punctuation">[</span>i<span class="token operator">+</span><span class="token punctuation">(</span><span class="token operator">++</span>nextI<span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">.</span>type <span class="token operator">===</span> <span class="token string">"paragraph_open"</span><span class="token punctuation">)</span><span class="token punctuation">{</span><br />		foundGraf <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">;</span><br />		<span class="token keyword">break</span><span class="token punctuation">;</span><br />	<span class="token punctuation">}</span><br /><span class="token punctuation">}</span></code></pre>
<p id="code-skip-hello-day-39-6">Ok, didn't quite work. I guess there could be an end of the article or a non-paragraph token? Let's take that into account.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-39/#code-skip-hello-day-39-5" id="skip-to-code-skip-hello-day-39-5" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">while</span> <span class="token punctuation">(</span><span class="token operator">!</span>foundGraf<span class="token punctuation">)</span> <span class="token punctuation">{</span><br />	<span class="token keyword">if</span> <span class="token punctuation">(</span>tokens<span class="token punctuation">[</span>i<span class="token operator">+</span><span class="token punctuation">(</span><span class="token operator">++</span>nextI<span class="token punctuation">)</span><span class="token punctuation">]</span> <span class="token operator">&amp;&amp;</span> tokens<span class="token punctuation">[</span>i<span class="token operator">+</span>nextI<span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">hasOwnProperty</span><span class="token punctuation">(</span><span class="token string">'type'</span><span class="token punctuation">)</span> <span class="token operator">&amp;&amp;</span> tokens<span class="token punctuation">[</span>i<span class="token operator">+</span>nextI<span class="token punctuation">]</span><span class="token punctuation">.</span>type <span class="token operator">===</span> <span class="token string">"paragraph_open"</span><span class="token punctuation">)</span><span class="token punctuation">{</span><br />		foundGraf <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">;</span><br />		<span class="token function">addSkipGrafID</span><span class="token punctuation">(</span>tokens<span class="token punctuation">[</span>i<span class="token operator">+</span>nextI<span class="token punctuation">]</span><span class="token punctuation">,</span> skipName<span class="token punctuation">)</span><br />		<span class="token keyword">break</span><span class="token punctuation">;</span><br />	<span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>tokens<span class="token punctuation">[</span>i<span class="token operator">+</span>nextI<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">{</span><br />		<span class="token comment">// do something</span><br />		<span class="token comment">// I guess we're at the end?</span><br />		foundGraf <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">;</span><br />		<span class="token keyword">break</span><br />	<span class="token punctuation">}</span><br /><span class="token punctuation">}</span></code></pre>
<p id="code-skip-hello-day-39-5">Ok so this applies the needed ID! I now need to build the paragraph block above the code block and place te skip link. Good to refer to <a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-34/#a-more-complex-markdown-it-token" target="_blank">the complex Markdown It chain I recorded on Day 34</a>.</p>
<p>I'm really unclear how the nesting property is supposed to work? I guess we will just try it and see!</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-39/#code-skip-hello-day-39-4" id="skip-to-code-skip-hello-day-39-4" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> <span class="token function-variable function">createSkipLink</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">TokenConstructor<span class="token punctuation">,</span> skipName</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />	<span class="token keyword">const</span> p_open <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">TokenConstructor</span><span class="token punctuation">(</span><span class="token string">"paragraph_open"</span><span class="token punctuation">,</span> <span class="token string">"p"</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token function">setAttr</span><span class="token punctuation">(</span>p_open<span class="token punctuation">,</span> <span class="token string">"class"</span><span class="token punctuation">,</span> <span class="token string">"skip-link-graf"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />	p_open<span class="token punctuation">.</span>children <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><br />	<span class="token keyword">const</span> link_open <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">TokenConstructor</span><span class="token punctuation">(</span><span class="token string">"link_open"</span><span class="token punctuation">,</span> <span class="token string">"a"</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token function">setAttr</span><span class="token punctuation">(</span>link_open<span class="token punctuation">,</span> <span class="token string">"href"</span><span class="token punctuation">,</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">#</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>skipName<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token function">setAttr</span><span class="token punctuation">(</span>link_open<span class="token punctuation">,</span> <span class="token string">"id"</span><span class="token punctuation">,</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">skip-to-</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>skipName<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token function">setAttr</span><span class="token punctuation">(</span>link_open<span class="token punctuation">,</span> <span class="token string">"class"</span><span class="token punctuation">,</span> <span class="token string">"skip-link"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />	p_open<span class="token punctuation">.</span>children<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span>link_open<span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token keyword">const</span> link_text <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">TokenConstructor</span><span class="token punctuation">(</span><span class="token string">"text"</span><span class="token punctuation">,</span> <span class="token string">""</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />	link_text<span class="token punctuation">.</span>content <span class="token operator">=</span> <span class="token string">"Skip code block &amp;#9660;"</span><br />	p_open<span class="token punctuation">.</span>children<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span>link_text<span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token keyword">const</span> link_close <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">TokenConstructor</span><span class="token punctuation">(</span><span class="token string">"link_close"</span><span class="token punctuation">,</span> <span class="token string">"a"</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />	p_open<span class="token punctuation">.</span>children<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span>link_close<span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token keyword">const</span> p_close <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">TokenConstructor</span><span class="token punctuation">(</span><span class="token string">"paragraph_close"</span><span class="token punctuation">,</span> <span class="token string">"p"</span><span class="token punctuation">,</span> <span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token keyword">return</span> <span class="token punctuation">{</span> p_open<span class="token punctuation">,</span> p_close <span class="token punctuation">}</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
<p id="code-skip-hello-day-39-4">Once I have my tokens, I can splce them into the token tree!</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-39/#code-skip-hello-day-39-3" id="skip-to-code-skip-hello-day-39-3" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript">console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Create skip link'</span><span class="token punctuation">)</span><br /><span class="token keyword">const</span> <span class="token punctuation">{</span> p_open<span class="token punctuation">,</span> p_close <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token function">createSkipLink</span><span class="token punctuation">(</span>state<span class="token punctuation">.</span>Token<span class="token punctuation">,</span> skipName<span class="token punctuation">)</span><br />tokens<span class="token punctuation">.</span><span class="token function">splice</span><span class="token punctuation">(</span>i<span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> p_close<span class="token punctuation">)</span><br />tokens<span class="token punctuation">.</span><span class="token function">splice</span><span class="token punctuation">(</span>i<span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> p_open<span class="token punctuation">)</span></code></pre>
<p id="code-skip-hello-day-39-3">Ok, apparently doing this drives the build process into an infinite loop? That's not great. What do I do now?</p>
<p>Ok, found the nesting info:</p>
<blockquote>
<p>Level change (number in {-1, 0, 1} set), where:</p>
<ul>
<li>1 means the tag is opening</li>
<li>0 means the tag is self-closing</li>
<li>-1 means the tag is closing</li>
</ul>
</blockquote>
<p>Got it. Well, fixing that doesn't seem to have fixed anything, still looping.</p>
<p>Let's <a href="https://github.com/markdown-it/markdown-it/blob/master/docs/architecture.md" target="_blank">read some docs I guess</a>!</p>
<p>Well <a href="https://markdown-it.github.io/" target="_blank">it looks like</a> I'm not supposed to put children on the paragraph token. In fact, it looks like it is supposed to be flat.</p>
<p>Ok tried:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-39/#code-skip-hello-day-39-2" id="skip-to-code-skip-hello-day-39-2" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> <span class="token function-variable function">createSkipLink</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">TokenConstructor<span class="token punctuation">,</span> skipName</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />	<span class="token keyword">const</span> p_open <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">TokenConstructor</span><span class="token punctuation">(</span><span class="token string">"paragraph_open"</span><span class="token punctuation">,</span> <span class="token string">"p"</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token function">setAttr</span><span class="token punctuation">(</span>p_open<span class="token punctuation">,</span> <span class="token string">"class"</span><span class="token punctuation">,</span> <span class="token string">"skip-link-graf"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />	p_open<span class="token punctuation">.</span>level <span class="token operator">=</span> <span class="token number">0</span><br />	<span class="token comment">// p_open.children = []</span><br />	<span class="token keyword">const</span> link_open <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">TokenConstructor</span><span class="token punctuation">(</span><span class="token string">"link_open"</span><span class="token punctuation">,</span> <span class="token string">"a"</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token function">setAttr</span><span class="token punctuation">(</span>link_open<span class="token punctuation">,</span> <span class="token string">"href"</span><span class="token punctuation">,</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">#</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>skipName<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token function">setAttr</span><span class="token punctuation">(</span>link_open<span class="token punctuation">,</span> <span class="token string">"id"</span><span class="token punctuation">,</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">skip-to-</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>skipName<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token function">setAttr</span><span class="token punctuation">(</span>link_open<span class="token punctuation">,</span> <span class="token string">"class"</span><span class="token punctuation">,</span> <span class="token string">"skip-link"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />	link_open<span class="token punctuation">.</span>level <span class="token operator">=</span> <span class="token number">1</span><br />	<span class="token comment">// p_open.children.push(link_open);</span><br />	<span class="token keyword">const</span> link_text <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">TokenConstructor</span><span class="token punctuation">(</span><span class="token string">"text"</span><span class="token punctuation">,</span> <span class="token string">""</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />	link_text<span class="token punctuation">.</span>content <span class="token operator">=</span> <span class="token string">"Skip code block &amp;#9660;"</span><br />	link_text<span class="token punctuation">.</span>level <span class="token operator">=</span> <span class="token number">2</span><br />	<span class="token comment">// p_open.children.push(link_text);</span><br />	<span class="token keyword">const</span> link_close <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">TokenConstructor</span><span class="token punctuation">(</span><span class="token string">"link_close"</span><span class="token punctuation">,</span> <span class="token string">"a"</span><span class="token punctuation">,</span> <span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />	link_close<span class="token punctuation">.</span>level <span class="token operator">=</span> <span class="token number">1</span><br />	<span class="token comment">// p_open.children.push(link_close);</span><br />	<span class="token keyword">const</span> p_close <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">TokenConstructor</span><span class="token punctuation">(</span><span class="token string">"paragraph_close"</span><span class="token punctuation">,</span> <span class="token string">"p"</span><span class="token punctuation">,</span> <span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token keyword">return</span> <span class="token punctuation">{</span> p_open<span class="token punctuation">,</span> link_open<span class="token punctuation">,</span> link_text<span class="token punctuation">,</span> link_close<span class="token punctuation">,</span> p_close <span class="token punctuation">}</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
<p id="code-skip-hello-day-39-2">Still looping.</p>
<p>Ok, it is not my token making process, it's what happens when I splice the tokens into the chain.</p>
<p>Ok... so how <em>do</em> I add new tokens?</p>
<p>Ok, did some searching and <a href="https://docs.joshuatz.com/cheatsheets/node-and-npm/markdown-it/" target="_blank">maybe there are functions to handle this</a> on the <code>state</code> object?</p>
<p>Let's see what keys are available on the <code>state</code> object.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-39/#code-skip-hello-day-39-1" id="skip-to-code-skip-hello-day-39-1" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript"><span class="token punctuation">[</span> <span class="token string">'src'</span><span class="token punctuation">,</span> <span class="token string">'env'</span><span class="token punctuation">,</span> <span class="token string">'tokens'</span><span class="token punctuation">,</span> <span class="token string">'inlineMode'</span><span class="token punctuation">,</span> <span class="token string">'md'</span> <span class="token punctuation">]</span></code></pre>
<p id="code-skip-hello-day-39-1">Ok, not useful.</p>
<p>Ok, maybe it is an issue with a particular token? My approach <a href="https://github.com/valeriangalliat/markdown-it-anchor/issues/100" target="_blank">looks</a> like it should work. Let's see what we can add without the loop happening.</p>
<p>Oh, duh, ok the for loop is hitting the same item over and over again as new items are added above it. I'm dumb. I can <a href="https://github.com/markdown-it/markdown-it/blob/master/lib/rules_core/linkify.js#L39" target="_blank">take the approach from the linkify plugin</a> and just reverse it.</p>
<p>Oh, only now my little renderer hack for adding <code>_blank</code> targets to all the links is adding targets to the skip links which is bad. I can use the <code>meta</code> property of the tokens to note that these links are skip links and they should not be treated to <code>_blank</code> targeting.</p>
<p>Ok, looking good. It's working!</p>
<p><a target="_blank" href="https://github.com/AramZS/devblog/commit/f0cf05c92218260c5f768cbe40aa6d60616fde9b" class="git-commit-link"><code>git commit -am &quot;Adding skip links to code blocks&quot;</code></a></p>
<p>Ok. So now I just need to give it some better styling!</p>
<p>Looking good enough for now! I may want to play with it a bit but this looks like a good place to stop.</p>
<p><a target="_blank" href="https://github.com/AramZS/devblog/commit/c786f12bc6709dfec2ed1104c0a078e3eb101a0e" class="git-commit-link"><code>git commit -am &quot;Finish day 39&quot;</code></a></p>
]]></content:encoded>
	</item>
	
	<item>
		<title>Part 38: Tag Level Pagination</title>
		<link>https://fightwithtools.dev/posts/projects/devblog/hello-day-38/?source=rss</link>
		<pubDate>Tue, 23 Nov 2021 02:59:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/projects/devblog/hello-day-38/</guid>
		<description>More devblog</description>
		<content:encoded><![CDATA[<h2 id="project-scope-and-todos" tabindex="-1">Project Scope and ToDos</h2>
<ol>
<li>Static Site Generator that can build the blog and let me host it on Github Pages</li>
<li>I want to write posts in Markdown because I'm lazy, it's easy, and it is how I take notes now.</li>
<li>I don't want to spend a ton of time doing design work. I'm doing complicated designs for other projects, so I want to pull a theme I like that I can rely on someone else to keep up.</li>
<li>Once it gets going, I want template changes to be easy.</li>
<li>It should be as easy as Jekyll, so I need to be able to build it using GitHub Actions, where I can just commit a template change or Markdown file and away it goes. If I can't figure this out than fk it, just use Jekyll.</li>
<li>I require it to be used by a significant percent of my professional peers so I can get easy answers when something goes wrong.</li>
<li>I want source maps. This is a dev log site which means whatever I do with it should be easy for other developers to read.</li>
</ol>
<ul class="task-list">
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Also <a href="https://www.npmjs.com/package/@quasibit/eleventy-plugin-sitemap" target="_blank">the sitemap plugin</a> looks cool. Should grab that later.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> So does the <a href="https://www.npmjs.com/package/eleventy-plugin-reading-time" target="_blank">reading time one</a>.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Also <a href="https://github.com/jdsteinbach/eleventy-plugin-toc/" target="_blank">this TOC plugin</a> mby?</p>
</li>
<li class="task-list-item">
<p data-wordfix="true"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Use <a href="https://www.11ty.dev/docs/data-deep-merge/" target="_blank">Data Deep Merge</a> in this blog.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Decide if I want to render the CSS fancier than just a base file and do per-template splitting.</p>
</li>
</ul>
<s>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Can I use the template inside of dinky that already exists instead of copy/pasting it?</li>
</ul>
</s>
<s>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Is there a way to have permalinks to posts contain metadata without organizing them into subfolders?</li>
</ul>
</s>
<ul class="task-list">
<li class="task-list-item">
<p data-wordfix="true"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> How do I cachebreak files on the basis of new build events? Datetime? <code>site.github.build_revision</code> is <a href="https://github.com/jekyll/github-metadata/blob/master/docs/site.github.md" target="_blank">how Jekyll accomplishes this</a>, but is there a way to push <a href="https://docs.github.com/en/actions/reference/context-and-expression-syntax-for-github-actions#github-context" target="_blank">that</a> <a href="https://stackoverflow.com/questions/54310050/how-to-version-build-artifacts-using-github-actions" target="_blank">into the build process</a> for Eleventy?</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Make link text look less shitty. It looks like it is a whole, lighter, font.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Code blocks do not have good syntax highlighting. I want good syntax highlighting.</p>
</li>
<li class="task-list-item">
<p data-wordfix="true"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Build a Markdown-it plugin to take my typing shortcuts <code>[prob, b/c, ...?]</code> and expand them on build.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> See if we can start Markdown's interpretation of H tags to <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/Heading_Elements#multiple_h1" target="_blank">start at 2, since H1</a> is always pulled from the page title metadata. If it isn't easy, I just have to change my pattern of writing in the MD documents.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Should I <a href="https://www.madebymike.com.au/writing/11ty-filters-data-shortcodes/" target="_blank">explore some shortcodes</a>?</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Order projects listing by last posted blog in that project</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Limit the output of home page post lists to a specific number of posts</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Show the latest post below the site intro on the homepage.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Tags pages with Pagination</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Posts should be able to support a preview header image that can also be shown on post lists.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Create a Markdown-It plugin that reads the project's repo URL off the folder data file and renders commit messages with <a href="https://stackoverflow.com/questions/15919635/on-github-api-what-is-the-best-way-to-get-the-last-commit-message-associated-w" target="_blank">links to the referenced commit</a>. (Is this even possible?) (Is there a way to do it with eleventy instead?)</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Create Next Day/Previous Day links on each post / Next/Previous post on post templates from projects</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Tags should be in the sidebar of articles and link to tag pages</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Create a skiplink for the todo section (or would this be better served with the ToC plugin?) - Yes it would be!</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Add a Things I Learned section to the project pages that are the things I learned from that specific project.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Add a technical reading log to the homepage</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/:empty" target="_blank">Hide</a> empty sections.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Add byline to post pages</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Have table of contents attach to sidebar bottom on mobile</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Support dark mode</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Social Icons</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> SEO/Social/JSON-LD HEAD data</p>
</li>
</ul>
<h2 id="day-38" tabindex="-1">Day 38</h2>
<p>Ok, as I listed in <a href="https://github.com/AramZS/devblog/issues/7" target="_blank">Issue 7</a> there are a few URL paths in my site that I don't want to see 404ing.</p>
<p>I thought this would be a pretty straightforward but it turned out to be harder than I thought, so instead of letting it go undocumented I figured I'd write it up.</p>
<h3 id="filling-in-fake-tags" tabindex="-1">Filling in &quot;Fake&quot; Tags</h3>
<p>Ok so I want a paginated list of all things tagged &quot;posts&quot; in a place other than the previously created <code>tag</code> structure. I can reuse the <code>tag</code> layout. But I'll need a new data structure to handle it.</p>
<p>I'm going to create a <code>postsPages</code> collection to fill <code>/posts/</code>.</p>
<p>I'll need to grab the <code>posts</code> collection with <code>collection.getFilteredByTag(&quot;posts&quot;)</code>.</p>
<p>Then I'll need to sort the collection into page-ready objects the same way I had done for <code>deepTagList</code>.</p>
<p>The first step is I'll define the form of the page object as a function.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-38/#code-skip-hello-day-38-11" id="skip-to-code-skip-hello-day-38-11" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> <span class="token function-variable function">makePageObject</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">tagName<span class="token punctuation">,</span> slug<span class="token punctuation">,</span> number<span class="token punctuation">,</span> posts<span class="token punctuation">,</span> first<span class="token punctuation">,</span> last</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />  <span class="token keyword">return</span> <span class="token punctuation">{</span><br />	<span class="token literal-property property">tagName</span><span class="token operator">:</span> tagName<span class="token punctuation">,</span><br />	<span class="token literal-property property">slug</span><span class="token operator">:</span> slug <span class="token operator">?</span> slug <span class="token operator">:</span> <span class="token function">slugify</span><span class="token punctuation">(</span>tagName<span class="token punctuation">.</span><span class="token function">toLowerCase</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br />	<span class="token literal-property property">number</span><span class="token operator">:</span> number<span class="token punctuation">,</span><br />	<span class="token literal-property property">posts</span><span class="token operator">:</span> posts<span class="token punctuation">,</span><br />	<span class="token literal-property property">first</span><span class="token operator">:</span> first<span class="token punctuation">,</span><br />	<span class="token literal-property property">last</span><span class="token operator">:</span> last<span class="token punctuation">,</span><br />  <span class="token punctuation">}</span><br /><span class="token punctuation">}</span></code></pre>
<p data-wordfix="true" id="code-skip-hello-day-38-11">This is the object that I can handle via the Eleventy <a href="https://www.11ty.dev/docs/pagination/" target="_blank">paginate</a> process.</p>
<p>Next I want to get the posts per each page object. I want 10 per page and I'll again be using a similar process to the <code>deepTagList</code> in order to do so.</p>
<p>First a function to take a single array and turn it into an array of arrays, each containing the contents of my 10-post long page. I took this function straight from a Stack Overflow response.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-38/#code-skip-hello-day-38-10" id="skip-to-code-skip-hello-day-38-10" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript"><br /><span class="token keyword">const</span> <span class="token function-variable function">paginate</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">arr<span class="token punctuation">,</span> size</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />	<span class="token keyword">return</span> arr<span class="token punctuation">.</span><span class="token function">reduce</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">acc<span class="token punctuation">,</span> val<span class="token punctuation">,</span> i</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />		<span class="token keyword">let</span> idx <span class="token operator">=</span> Math<span class="token punctuation">.</span><span class="token function">floor</span><span class="token punctuation">(</span>i <span class="token operator">/</span> size<span class="token punctuation">)</span><span class="token punctuation">;</span><br />		<span class="token keyword">let</span> page <span class="token operator">=</span> acc<span class="token punctuation">[</span>idx<span class="token punctuation">]</span> <span class="token operator">||</span> <span class="token punctuation">(</span>acc<span class="token punctuation">[</span>idx<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />		page<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span>val<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br />		<span class="token keyword">return</span> acc<span class="token punctuation">;</span><br />	<span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span><span class="token punctuation">;</span><br /></code></pre>
<p id="code-skip-hello-day-38-10">Now I have the tools to make the collection.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-38/#code-skip-hello-day-38-9" id="skip-to-code-skip-hello-day-38-9" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript"><br /><span class="token function-variable function">getPostClusters</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">allPosts<span class="token punctuation">,</span> tagName<span class="token punctuation">,</span> slug</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />  aSet <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Set</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />  <span class="token keyword">let</span> postArray <span class="token operator">=</span> allPosts<span class="token punctuation">.</span><span class="token function">reverse</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />  aSet <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token operator">...</span>postArray<span class="token punctuation">]</span><span class="token punctuation">;</span><br />  postArray <span class="token operator">=</span> <span class="token function">paginate</span><span class="token punctuation">(</span>aSet<span class="token punctuation">,</span> <span class="token number">10</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />  <span class="token keyword">let</span> paginatedPostArray <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span><br />  postArray<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">p<span class="token punctuation">,</span> i</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />  	paginatedPostArray<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span><span class="token punctuation">{</span><br />  		tagName<span class="token punctuation">,</span><br />  		<span class="token literal-property property">slug</span><span class="token operator">:</span> slug <span class="token operator">?</span> slug <span class="token operator">:</span> <span class="token function">slugify</span><span class="token punctuation">(</span>tagName<span class="token punctuation">.</span><span class="token function">toLowerCase</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br />  		<span class="token literal-property property">number</span><span class="token operator">:</span> i <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">,</span><br />  		<span class="token literal-property property">posts</span><span class="token operator">:</span> p<span class="token punctuation">,</span><br />  		<span class="token literal-property property">first</span><span class="token operator">:</span> i <span class="token operator">===</span> <span class="token number">0</span><span class="token punctuation">,</span><br />  		<span class="token literal-property property">last</span><span class="token operator">:</span> i <span class="token operator">===</span> postArray<span class="token punctuation">.</span>length <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">,</span><br />  	<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />  <span class="token comment">// console.log(paginatedPostArray)</span><br />  <span class="token keyword">return</span> paginatedPostArray<span class="token punctuation">;</span><br /><span class="token punctuation">}</span><span class="token punctuation">;</span><br /><br />eleventyConfig<span class="token punctuation">.</span><span class="token function">addCollection</span><span class="token punctuation">(</span><span class="token string">"postsPages"</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token parameter">collection</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />	<span class="token keyword">return</span> <span class="token function">getPostClusters</span><span class="token punctuation">(</span>collection<span class="token punctuation">.</span><span class="token function">getFilteredByTag</span><span class="token punctuation">(</span><span class="token string">"posts"</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token string">"Posts"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p id="code-skip-hello-day-38-9">I can use the exact same process to build a collection for projects.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-38/#code-skip-hello-day-38-8" id="skip-to-code-skip-hello-day-38-8" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript">eleventyConfig<span class="token punctuation">.</span><span class="token function">addCollection</span><span class="token punctuation">(</span><span class="token string">"projectsPages"</span><span class="token punctuation">,</span><span class="token punctuation">(</span><span class="token parameter">collection</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />	<span class="token keyword">return</span> <span class="token function">getPostClusters</span><span class="token punctuation">(</span><br />		collection<span class="token punctuation">.</span><span class="token function">getFilteredByTag</span><span class="token punctuation">(</span><span class="token string">"projects"</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br />		<span class="token string">"Projects"</span><br />	<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p data-wordfix="true" id="code-skip-hello-day-38-8">With these new collections I can build corresponding pages in Eleventy.</p>
<p>Posts:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-38/#code-skip-hello-day-38-7" id="skip-to-code-skip-hello-day-38-7" class="skip-link">Skip code block ▼</a></p>
<pre class="language-liquid"><code class="language-liquid">---<br />layout: tags<br />templateName: tag<br />eleventyExcludeFromCollections: true<br />pagination:<br />    data: collections.postsPages<br />    size: 1<br />    alias: paged<br />permalink: "posts/{%<span class="token templateTag"> <span class="token keyword">if</span> paged<span class="token punctuation">.</span>number <span class="token operator">></span> <span class="token number">1</span> </span>%}{{ paged.number }}/{%<span class="token templateTag"> endif </span>%}index.html"<br />eleventyComputed:<br />    title: "All Posts{%<span class="token templateTag"> <span class="token keyword">if</span> paged<span class="token punctuation">.</span>number <span class="token operator">></span> <span class="token number">1</span> </span>%} | Page {{paged.number}}{%<span class="token templateTag"> endif </span>%}"<br />    description: "Posts"<br />---</code></pre>
<p id="code-skip-hello-day-38-7">Projects:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-38/#code-skip-hello-day-38-6" id="skip-to-code-skip-hello-day-38-6" class="skip-link">Skip code block ▼</a></p>
<pre class="language-liquid"><code class="language-liquid">---<br />layout: tags<br />templateName: tag<br />eleventyExcludeFromCollections: true<br />pagination:<br />    data: collections.deepProjectPostsList<br />    size: 1<br />    alias: paged<br />permalink: "posts/projects/{{ paged.slug }}/{%<span class="token templateTag"> <span class="token keyword">if</span> paged<span class="token punctuation">.</span>number <span class="token operator">></span> <span class="token number">1</span> </span>%}{{ paged.number }}/{%<span class="token templateTag"> endif </span>%}index.html"<br />eleventyComputed:<br />    title: "Posts from Project: {{ paged.tagName }}{%<span class="token templateTag"> <span class="token keyword">if</span> paged<span class="token punctuation">.</span>number <span class="token operator">></span> <span class="token number">1</span> </span>%} | Page {{paged.number}}{%<span class="token templateTag"> endif </span>%}"<br />    description: "Project Posts tagged with {{ paged.tagName }}"<br />---</code></pre>
<p id="code-skip-hello-day-38-6">Now for the last step I need to generate pages to fill <code>posts/projects/projectName</code> pages.</p>
<p>Now I can query posts into collections by their project property. I can use my <code>projects</code> collection and filter posts based on matches.</p>
<p>Now, this is my second try. The first time I did this I screwed up because of two reasons. I forgot that it needed to be a flat array (that is one array of posts).</p>
<p>The other hard thing for me to wrap my mind around is that I don't need to separate each project into its own array or project.</p>
<p>So first I need to get the posts, separated out by projects.</p>
<p>It seems like the global data object isn't set up in <code>.eleventy.js</code>. So I'll need to import the object for use in this project with <code>const projectSet = require(&quot;./src/_data/projects&quot;);</code></p>
<p>Then I can use it to filter my posts by their project property.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-38/#code-skip-hello-day-38-5" id="skip-to-code-skip-hello-day-38-5" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">let</span> deepProjectPostList <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span><br /><span class="token comment">// Run this for each of the projects in the `project` collection I build in my data file.</span><br />projectSet<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">project</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />	<span class="token comment">// Step into an individual project and only run this process for projects that have posts, otherwise we'll throw errors during the build process.</span><br />	<span class="token keyword">if</span> <span class="token punctuation">(</span>project<span class="token punctuation">.</span>count <span class="token operator">></span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />		<span class="token comment">// This gets all posts with the project tag, those that fall under the `src/posts/projects` folder.</span><br />		<span class="token keyword">let</span> allProjectPosts <span class="token operator">=</span> collection<span class="token punctuation">.</span><span class="token function">getFilteredByTag</span><span class="token punctuation">(</span><span class="token string">"projects"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />		<span class="token comment">// Now I'm going to use the filter function to return only those posts that match the project I've stepped into.</span><br />		<span class="token keyword">let</span> allPosts <span class="token operator">=</span> allProjectPosts<span class="token punctuation">.</span><span class="token function">filter</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">post</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />			<span class="token keyword">if</span> <span class="token punctuation">(</span>post<span class="token punctuation">.</span>data<span class="token punctuation">.</span>project <span class="token operator">==</span> project<span class="token punctuation">.</span>projectName<span class="token punctuation">)</span> <span class="token punctuation">{</span><br />				<span class="token keyword">return</span> <span class="token boolean">true</span><span class="token punctuation">;</span><br />			<span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span><br />				<span class="token keyword">return</span> <span class="token boolean">false</span><span class="token punctuation">;</span><br />			<span class="token punctuation">}</span><br />		<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />		<span class="token comment">// Now I have an array of all the posts that are in this particular project, based on their project property. This isn't being called at the post level, and it is a new array anyway, so I seem to be safe to reverse it.</span><br />		allPosts<span class="token punctuation">.</span><span class="token function">reverse</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />		<span class="token comment">// I take the set of all the project posts and turn it into page clusters.</span><br />		<span class="token keyword">const</span> postClusters <span class="token operator">=</span> <span class="token function">getPostClusters</span><span class="token punctuation">(</span><br />			allPosts<span class="token punctuation">,</span><br />			project<span class="token punctuation">.</span>projectName<span class="token punctuation">,</span><br />			project<span class="token punctuation">.</span>slug<br />		<span class="token punctuation">)</span><span class="token punctuation">;</span><br />		<span class="token comment">// And I can put those clusters into an array.</span><br />		deepProjectPostList<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span><br />			<span class="token function">getPostClusters</span><span class="token punctuation">(</span>allPosts<span class="token punctuation">,</span> project<span class="token punctuation">.</span>projectName<span class="token punctuation">,</span> project<span class="token punctuation">.</span>slug<span class="token punctuation">)</span><br />		<span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token punctuation">}</span><br /><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p id="code-skip-hello-day-38-5">So now I have an array of pages. This is good, but too deep.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-38/#code-skip-hello-day-38-4" id="skip-to-code-skip-hello-day-38-4" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript"><span class="token punctuation">[</span> <span class="token comment">// deepProjectPostList</span><br />	<span class="token punctuation">[</span> <span class="token comment">// Level of a project</span><br />		<span class="token punctuation">[</span> <span class="token comment">// a "page" of 10 posts</span><br /><br />		<span class="token punctuation">]</span><br />	<span class="token punctuation">]</span><br /><span class="token punctuation">]</span></code></pre>
<p data-wordfix="true" id="code-skip-hello-day-38-4">That's way too deep. Like I said earlier, my initial mistake was leaving this as is. I forgot that it needs to be one layer deep to work with how Eleventy does pagination.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-38/#code-skip-hello-day-38-3" id="skip-to-code-skip-hello-day-38-3" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">let</span> pagedDeepProjectList <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span><br />deepProjectPostList<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">projectCluster</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />	<span class="token comment">// Inside each projectCluster array is a set of "pages" each with this object.</span><br />	<span class="token comment">/**<br />	 * 	tagName,<br />		slug: slug ? slug : slugify(tagName.toLowerCase()),<br />		number: i + 1,<br />		posts: p,<br />		first: i === 0,<br />		last: i === postArray.length - 1,<br />	*/</span><br />	pagedDeepProjectList<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span><span class="token operator">...</span>projectCluster<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p id="code-skip-hello-day-38-3">So I can use the spread operator here! Makes it much easier. This takes the array of arrays and pulls out the inner array and delivers it into the single level array I intend to use.</p>
<p>The end result is a much simpler array that can work with the page functionality.</p>
<p>Now I have an array of objects that look like this:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-38/#code-skip-hello-day-38-2" id="skip-to-code-skip-hello-day-38-2" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript"><span class="token punctuation">[</span><br />	<span class="token punctuation">{</span><br />	 	tagName<span class="token punctuation">,</span><br />		<span class="token literal-property property">slug</span><span class="token operator">:</span> slug<span class="token punctuation">,</span><br />		<span class="token literal-property property">number</span><span class="token operator">:</span> <span class="token number">1</span><span class="token punctuation">,</span><br />		<span class="token literal-property property">posts</span><span class="token operator">:</span> postsObject<span class="token punctuation">,</span><br />		<span class="token literal-property property">first</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span><br />		<span class="token literal-property property">last</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span><br />	<span class="token punctuation">}</span><br />	<span class="token operator">...</span><br /><span class="token punctuation">]</span></code></pre>
<p id="code-skip-hello-day-38-2"><a target="_blank" href="https://github.com/AramZS/devblog/commit/0c930f0c719377b204c0919ac83d5eb340261dce" class="git-commit-link"><code>git commit -am &quot;Trying to figure out the project pages&quot;</code></a></p>
<p>See I forgot that I control the permalink structure not through the structures in the array, but the objects. So I can now take this array and use it to generate any number of paged collections at <code>/posts/projects/projectSlug/</code>. So now I can use this new collection with this <code>md</code> file:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-38/#code-skip-hello-day-38-1" id="skip-to-code-skip-hello-day-38-1" class="skip-link">Skip code block ▼</a></p>
<pre class="language-liquid"><code class="language-liquid">---<br />layout: tags<br />templateName: tag<br />eleventyExcludeFromCollections: true<br />pagination:<br />    data: collections.deepProjectPostsList<br />    size: 1<br />    alias: paged<br />permalink: "posts/projects/{{ paged.slug }}/{%<span class="token templateTag"> <span class="token keyword">if</span> paged<span class="token punctuation">.</span>number <span class="token operator">></span> <span class="token number">1</span> </span>%}{{ paged.number }}/{%<span class="token templateTag"> endif </span>%}index.html"<br />eleventyComputed:<br />    title: "Posts from Project: {{ paged.tagName }}{%<span class="token templateTag"> <span class="token keyword">if</span> paged<span class="token punctuation">.</span>number <span class="token operator">></span> <span class="token number">1</span> </span>%} | Page {{paged.number}}{%<span class="token templateTag"> endif </span>%}"<br />    description: "Project Posts tagged with {{ paged.tagName }}"<br />---</code></pre>
<p id="code-skip-hello-day-38-1"><a target="_blank" href="https://github.com/AramZS/devblog/commit/0c930f0c719377b204c0919ac83d5eb340261dce" class="git-commit-link"><code>git commit -am &quot;Trying to figure out the project pages&quot;</code></a></p>
<p>And this should resolve Issue 7!</p>
<p><a target="_blank" href="https://github.com/AramZS/devblog/commit/0ce4a9689d154be15876bd3190fd39ba8a0899a7" class="git-commit-link"><code>git commit -am &quot;Finish off day 38 and resolve #7&quot;</code></a></p>
]]></content:encoded>
	</item>
	
	<item>
		<title>Part 37:  Markdown It, Caching and Automatic Commit Links</title>
		<link>https://fightwithtools.dev/posts/projects/devblog/hello-day-37/?source=rss</link>
		<pubDate>Thu, 18 Nov 2021 02:59:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/projects/devblog/hello-day-37/</guid>
		<description>More devblog</description>
		<content:encoded><![CDATA[<h2 id="project-scope-and-todos" tabindex="-1">Project Scope and ToDos</h2>
<ol>
<li>Static Site Generator that can build the blog and let me host it on Github Pages</li>
<li>I want to write posts in Markdown because I'm lazy, it's easy, and it is how I take notes now.</li>
<li>I don't want to spend a ton of time doing design work. I'm doing complicated designs for other projects, so I want to pull a theme I like that I can rely on someone else to keep up.</li>
<li>Once it gets going, I want template changes to be easy.</li>
<li>It should be as easy as Jekyll, so I need to be able to build it using GitHub Actions, where I can just commit a template change or Markdown file and away it goes. If I can't figure this out than fk it, just use Jekyll.</li>
<li>I require it to be used by a significant percent of my professional peers so I can get easy answers when something goes wrong.</li>
<li>I want source maps. This is a dev log site which means whatever I do with it should be easy for other developers to read.</li>
</ol>
<ul class="task-list">
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Also <a href="https://www.npmjs.com/package/@quasibit/eleventy-plugin-sitemap" target="_blank">the sitemap plugin</a> looks cool. Should grab that later.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> So does the <a href="https://www.npmjs.com/package/eleventy-plugin-reading-time" target="_blank">reading time one</a>.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Also <a href="https://github.com/jdsteinbach/eleventy-plugin-toc/" target="_blank">this TOC plugin</a> mby?</p>
</li>
<li class="task-list-item">
<p data-wordfix="true"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Use <a href="https://www.11ty.dev/docs/data-deep-merge/" target="_blank">Data Deep Merge</a> in this blog.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Decide if I want to render the CSS fancier than just a base file and do per-template splitting.</p>
</li>
</ul>
<s>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Can I use the template inside of dinky that already exists instead of copy/pasting it?</li>
</ul>
</s>
<s>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Is there a way to have permalinks to posts contain metadata without organizing them into subfolders?</li>
</ul>
</s>
<ul class="task-list">
<li class="task-list-item">
<p data-wordfix="true"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> How do I cachebreak files on the basis of new build events? Datetime? <code>site.github.build_revision</code> is <a href="https://github.com/jekyll/github-metadata/blob/master/docs/site.github.md" target="_blank">how Jekyll accomplishes this</a>, but is there a way to push <a href="https://docs.github.com/en/actions/reference/context-and-expression-syntax-for-github-actions#github-context" target="_blank">that</a> <a href="https://stackoverflow.com/questions/54310050/how-to-version-build-artifacts-using-github-actions" target="_blank">into the build process</a> for Eleventy?</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Make link text look less shitty. It looks like it is a whole, lighter, font.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Code blocks do not have good syntax highlighting. I want good syntax highlighting.</p>
</li>
<li class="task-list-item">
<p data-wordfix="true"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Build a Markdown-it plugin to take my typing shortcuts <code>[prob, b/c, ...?]</code> and expand them on build.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> See if we can start Markdown's interpretation of H tags to <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/Heading_Elements#multiple_h1" target="_blank">start at 2, since H1</a> is always pulled from the page title metadata. If it isn't easy, I just have to change my pattern of writing in the MD documents.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Should I <a href="https://www.madebymike.com.au/writing/11ty-filters-data-shortcodes/" target="_blank">explore some shortcodes</a>?</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Order projects listing by last posted blog in that project</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Limit the output of home page post lists to a specific number of posts</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Show the latest post below the site intro on the homepage.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Tags pages with Pagination</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Posts should be able to support a preview header image that can also be shown on post lists.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Create a Markdown-It plugin that reads the project's repo URL off the folder data file and renders commit messages with <a href="https://stackoverflow.com/questions/15919635/on-github-api-what-is-the-best-way-to-get-the-last-commit-message-associated-w" target="_blank">links to the referenced commit</a>. (Is this even possible?) (Is there a way to do it with eleventy instead?)</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Create Next Day/Previous Day links on each post / Next/Previous post on post templates from projects</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Tags should be in the sidebar of articles and link to tag pages</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Create a skiplink for the todo section (or would this be better served with the ToC plugin?) - Yes it would be!</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Add a Things I Learned section to the project pages that are the things I learned from that specific project.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Add a technical reading log to the homepage</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/:empty" target="_blank">Hide</a> empty sections.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Add byline to post pages</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Have table of contents attach to sidebar bottom on mobile</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Support dark mode</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Social Icons</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> SEO/Social/JSON-LD HEAD data</p>
</li>
</ul>
<h2 id="day-37" tabindex="-1">Day 37</h2>
<p>Ok,so I need to apply the rules properly.</p>
<p>First, let's see what rules exist:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-37/#code-skip-hello-day-37-16" id="skip-to-code-skip-hello-day-37-16" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript">console<span class="token punctuation">.</span><span class="token function">dir</span><span class="token punctuation">(</span>md<span class="token punctuation">.</span>core<span class="token punctuation">.</span>ruler<span class="token punctuation">)</span></code></pre>
<p id="code-skip-hello-day-37-16">Ok:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-37/#code-skip-hello-day-37-15" id="skip-to-code-skip-hello-day-37-15" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript">Ruler <span class="token punctuation">{</span><br />  <span class="token literal-property property">__rules__</span><span class="token operator">:</span> <span class="token punctuation">[</span><br />    <span class="token punctuation">{</span><br />      <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'normalize'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">enabled</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">fn</span><span class="token operator">:</span> <span class="token punctuation">[</span>Function<span class="token operator">:</span> normalize<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">alt</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><br />    <span class="token punctuation">}</span><span class="token punctuation">,</span><br />    <span class="token punctuation">{</span> <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'block'</span><span class="token punctuation">,</span> <span class="token literal-property property">enabled</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span> <span class="token literal-property property">fn</span><span class="token operator">:</span> <span class="token punctuation">[</span>Function<span class="token operator">:</span> block<span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token literal-property property">alt</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token punctuation">}</span><span class="token punctuation">,</span><br />    <span class="token punctuation">{</span> <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'inline'</span><span class="token punctuation">,</span> <span class="token literal-property property">enabled</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span> <span class="token literal-property property">fn</span><span class="token operator">:</span> <span class="token punctuation">[</span>Function<span class="token operator">:</span> inline<span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token literal-property property">alt</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token punctuation">}</span><span class="token punctuation">,</span><br />    <span class="token punctuation">{</span><br />      <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'short-phrase-fixer'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">enabled</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">fn</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token function">Function</span> <span class="token punctuation">(</span>anonymous<span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">alt</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><br />    <span class="token punctuation">}</span><span class="token punctuation">,</span><br />    <span class="token punctuation">{</span><br />      <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'evernote-todo'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">enabled</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">fn</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token function">Function</span> <span class="token punctuation">(</span>anonymous<span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">alt</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><br />    <span class="token punctuation">}</span><span class="token punctuation">,</span><br />    <span class="token punctuation">{</span><br />      <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'replace-link'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">enabled</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">fn</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token function">Function</span> <span class="token punctuation">(</span>anonymous<span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">alt</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><br />    <span class="token punctuation">}</span><span class="token punctuation">,</span><br />    <span class="token punctuation">{</span><br />      <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'linkify'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">enabled</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">fn</span><span class="token operator">:</span> <span class="token punctuation">[</span>Function<span class="token operator">:</span> linkify<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">alt</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><br />    <span class="token punctuation">}</span><span class="token punctuation">,</span><br />    <span class="token punctuation">{</span><br />      <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'replacements'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">enabled</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">fn</span><span class="token operator">:</span> <span class="token punctuation">[</span>Function<span class="token operator">:</span> replace<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">alt</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><br />    <span class="token punctuation">}</span><span class="token punctuation">,</span><br />    <span class="token punctuation">{</span><br />      <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'smartquotes'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">enabled</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">fn</span><span class="token operator">:</span> <span class="token punctuation">[</span>Function<span class="token operator">:</span> smartquotes<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">alt</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><br />    <span class="token punctuation">}</span><span class="token punctuation">,</span><br />    <span class="token punctuation">{</span><br />      <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'anchor'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">enabled</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">fn</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token function">Function</span> <span class="token punctuation">(</span>anonymous<span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">alt</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><br />    <span class="token punctuation">}</span><br />  <span class="token punctuation">]</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">__cache__</span><span class="token operator">:</span> <span class="token keyword">null</span><br /><span class="token punctuation">}</span></code></pre>
<h3 id="finding-the-inline-token" tabindex="-1">Finding the inline token</h3>
<p id="code-skip-hello-day-37-15">Ok, so I need to set up a token type starting with inline. Let's try and match the right token:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-37/#code-skip-hello-day-37-14" id="skip-to-code-skip-hello-day-37-14" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> testPattern <span class="token operator">=</span> <span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">(?&lt;=git commit \-am [\"|\'])(.*)(?=[\"|\'])</span><span class="token regex-delimiter">/</span><span class="token regex-flags">i</span></span><span class="token punctuation">;</span><br /><br /><span class="token comment">// console.dir(md.core.ruler)</span><br />md<span class="token punctuation">.</span>core<span class="token punctuation">.</span>ruler<span class="token punctuation">.</span><span class="token function">after</span><span class="token punctuation">(</span><span class="token string">'inline'</span><span class="token punctuation">,</span> <span class="token string">'git_commit'</span><span class="token punctuation">,</span> <span class="token parameter">state</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />  <span class="token keyword">const</span> tokens <span class="token operator">=</span> state<span class="token punctuation">.</span>tokens<br />  <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">let</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&lt;</span> tokens<span class="token punctuation">.</span>length<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />  	<span class="token keyword">if</span> <span class="token punctuation">(</span>testPattern<span class="token punctuation">.</span><span class="token function">test</span><span class="token punctuation">(</span>tokens<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">.</span>content<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />  		console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'tokens round 1: '</span><span class="token punctuation">,</span> tokens<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">)</span><br />  	<span class="token punctuation">}</span><br />  <span class="token punctuation">}</span><br /><span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre>
<p id="code-skip-hello-day-37-14">Results:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-37/#code-skip-hello-day-37-13" id="skip-to-code-skip-hello-day-37-13" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript"> Token <span class="token punctuation">{</span><br />  <span class="token literal-property property">type</span><span class="token operator">:</span> <span class="token string">'inline'</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">tag</span><span class="token operator">:</span> <span class="token string">''</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">attrs</span><span class="token operator">:</span> <span class="token keyword">null</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">map</span><span class="token operator">:</span> <span class="token punctuation">[</span> <span class="token number">143</span><span class="token punctuation">,</span> <span class="token number">144</span> <span class="token punctuation">]</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">nesting</span><span class="token operator">:</span> <span class="token number">0</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">level</span><span class="token operator">:</span> <span class="token number">1</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">children</span><span class="token operator">:</span> <span class="token punctuation">[</span><br />    Token <span class="token punctuation">{</span><br />      <span class="token literal-property property">type</span><span class="token operator">:</span> <span class="token string">'code_inline'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">tag</span><span class="token operator">:</span> <span class="token string">'code'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">attrs</span><span class="token operator">:</span> <span class="token keyword">null</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">map</span><span class="token operator">:</span> <span class="token keyword">null</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">nesting</span><span class="token operator">:</span> <span class="token number">0</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">level</span><span class="token operator">:</span> <span class="token number">0</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">children</span><span class="token operator">:</span> <span class="token keyword">null</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">content</span><span class="token operator">:</span> <span class="token string">'git commit -am "Get macros in the mix."'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">markup</span><span class="token operator">:</span> <span class="token string">'`'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">info</span><span class="token operator">:</span> <span class="token string">''</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">meta</span><span class="token operator">:</span> <span class="token keyword">null</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">block</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">hidden</span><span class="token operator">:</span> <span class="token boolean">false</span><br />    <span class="token punctuation">}</span><br />  <span class="token punctuation">]</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">content</span><span class="token operator">:</span> <span class="token string">'`git commit -am "Get macros in the mix."`'</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">markup</span><span class="token operator">:</span> <span class="token string">''</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">info</span><span class="token operator">:</span> <span class="token string">''</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">meta</span><span class="token operator">:</span> <span class="token keyword">null</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">block</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">hidden</span><span class="token operator">:</span> <span class="token boolean">false</span><br /><span class="token punctuation">}</span></code></pre>
<h3 id="markdown-it-state-obj" tabindex="-1">Markdown-it State Obj</h3>
<p id="code-skip-hello-day-37-13">Good to know, ok, what is in this state object anyway?</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-37/#code-skip-hello-day-37-12" id="skip-to-code-skip-hello-day-37-12" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript">StateCore <span class="token punctuation">{</span><br />  <span class="token literal-property property">src</span><span class="token operator">:</span> <span class="token string">''</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">env</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />    <span class="token literal-property property">defaults</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">layout</span><span class="token operator">:</span> <span class="token string">'default.njk'</span><span class="token punctuation">,</span> <span class="token literal-property property">description</span><span class="token operator">:</span> <span class="token string">'Talking about code'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">description</span><span class="token operator">:</span> <span class="token string">'Posts tagged with Markdown-It'</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">layout</span><span class="token operator">:</span> <span class="token string">'tags'</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">projects</span><span class="token operator">:</span> <span class="token punctuation">[</span> <span class="token punctuation">[</span>Object<span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">[</span>Object<span class="token punctuation">]</span> <span class="token punctuation">]</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">site</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />      <span class="token literal-property property">lang</span><span class="token operator">:</span> <span class="token string">'en-US'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">github</span><span class="token operator">:</span> <span class="token punctuation">[</span>Object<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">site_url</span><span class="token operator">:</span> <span class="token string">'http://localhost:8080'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">site_name</span><span class="token operator">:</span> <span class="token string">'Fight With Tools: A Dev Blog'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">description</span><span class="token operator">:</span> <span class="token string">'A site opening up my development process to all.'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">featuredImage</span><span class="token operator">:</span> <span class="token string">'nyc_noir.jpg'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">aramPhoto</span><span class="token operator">:</span> <span class="token string">'https://raw.githubusercontent.com/AramZS/aramzs.github.io/master/_includes/Aram-Zucker-Scharff-square.jpg'</span><br />    <span class="token punctuation">}</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">pkg</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />      <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'fightwithtooldev'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">version</span><span class="token operator">:</span> <span class="token string">'1.0.0'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">description</span><span class="token operator">:</span> <span class="token string">"This is the repo for Aram ZS's developer notes and log, keeping track of code experiments and decisions."</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">main</span><span class="token operator">:</span> <span class="token string">'index.js'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">scripts</span><span class="token operator">:</span> <span class="token punctuation">[</span>Object<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">keywords</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">author</span><span class="token operator">:</span> <span class="token string">''</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">license</span><span class="token operator">:</span> <span class="token string">'ISC'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">devDependencies</span><span class="token operator">:</span> <span class="token punctuation">[</span>Object<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">dependencies</span><span class="token operator">:</span> <span class="token punctuation">[</span>Object<span class="token punctuation">]</span><br />    <span class="token punctuation">}</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">templateName</span><span class="token operator">:</span> <span class="token string">'tag'</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">eleventyExcludeFromCollections</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">pagination</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />      <span class="token literal-property property">data</span><span class="token operator">:</span> <span class="token string">'collections.deepTagList'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">size</span><span class="token operator">:</span> <span class="token number">1</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">alias</span><span class="token operator">:</span> <span class="token string">'paged'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">pages</span><span class="token operator">:</span> <span class="token punctuation">[</span>Array<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">page</span><span class="token operator">:</span> <span class="token punctuation">[</span>Object<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">items</span><span class="token operator">:</span> <span class="token punctuation">[</span>Array<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">pageNumber</span><span class="token operator">:</span> <span class="token number">37</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">previousPageLink</span><span class="token operator">:</span> <span class="token string">'/tag/smo/index.html'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">previous</span><span class="token operator">:</span> <span class="token string">'/tag/smo/index.html'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">nextPageLink</span><span class="token operator">:</span> <span class="token keyword">null</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">next</span><span class="token operator">:</span> <span class="token keyword">null</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">firstPageLink</span><span class="token operator">:</span> <span class="token string">'/tag/blogroll/index.html'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">lastPageLink</span><span class="token operator">:</span> <span class="token string">'/tag/markdown-it/index.html'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">links</span><span class="token operator">:</span> <span class="token punctuation">[</span>Array<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">pageLinks</span><span class="token operator">:</span> <span class="token punctuation">[</span>Array<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">previousPageHref</span><span class="token operator">:</span> <span class="token string">'/tag/smo/'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">nextPageHref</span><span class="token operator">:</span> <span class="token keyword">null</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">firstPageHref</span><span class="token operator">:</span> <span class="token string">'/tag/blogroll/'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">lastPageHref</span><span class="token operator">:</span> <span class="token string">'/tag/markdown-it/'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">hrefs</span><span class="token operator">:</span> <span class="token punctuation">[</span>Array<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">href</span><span class="token operator">:</span> <span class="token punctuation">[</span>Object<span class="token punctuation">]</span><br />    <span class="token punctuation">}</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">permalink</span><span class="token operator">:</span> <span class="token string">'tag/{{ paged.tagName | slug }}/{% if paged.number > 1 %}{{ paged.number }}/{% endif %}index.html'</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">eleventyComputed</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />      <span class="token literal-property property">title</span><span class="token operator">:</span> <span class="token string">'Tag: {{ paged.tagName }}{% if paged.number > 1 %} | Page {{paged.number}}{% endif %}'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">description</span><span class="token operator">:</span> <span class="token string">'Posts tagged with {{ paged.tagName }}'</span><br />    <span class="token punctuation">}</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">page</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />      <span class="token literal-property property">date</span><span class="token operator">:</span> <span class="token number">2021</span><span class="token operator">-</span><span class="token number">11</span><span class="token operator">-</span>13T22<span class="token operator">:</span><span class="token number">11</span><span class="token operator">:</span><span class="token number">01</span><span class="token punctuation">.</span>651Z<span class="token punctuation">,</span><br />      <span class="token literal-property property">inputPath</span><span class="token operator">:</span> <span class="token string">'./src/tags-pages.md'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">fileSlug</span><span class="token operator">:</span> <span class="token string">'tags-pages'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">filePathStem</span><span class="token operator">:</span> <span class="token string">'/tags-pages'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">url</span><span class="token operator">:</span> <span class="token string">'/tag/markdown-it/'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">outputPath</span><span class="token operator">:</span> <span class="token string">'docs/tag/markdown-it/index.html'</span><br />    <span class="token punctuation">}</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">paged</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />      <span class="token literal-property property">tagName</span><span class="token operator">:</span> <span class="token string">'Markdown-It'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">number</span><span class="token operator">:</span> <span class="token number">1</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">posts</span><span class="token operator">:</span> <span class="token punctuation">[</span>Array<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">first</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">last</span><span class="token operator">:</span> <span class="token boolean">true</span><br />    <span class="token punctuation">}</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">title</span><span class="token operator">:</span> <span class="token string">'Tag: Markdown-It'</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">collections</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />      <span class="token literal-property property">all</span><span class="token operator">:</span> <span class="token punctuation">[</span>Array<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">blogroll</span><span class="token operator">:</span> <span class="token punctuation">[</span>Array<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token string-property property">'Personal Blog'</span><span class="token operator">:</span> <span class="token punctuation">[</span>Array<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">links</span><span class="token operator">:</span> <span class="token punctuation">[</span>Array<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token string-property property">'Tech Critical'</span><span class="token operator">:</span> <span class="token punctuation">[</span>Array<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">Blockchain</span><span class="token operator">:</span> <span class="token punctuation">[</span>Array<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">Cryptocurrency</span><span class="token operator">:</span> <span class="token punctuation">[</span>Array<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token string-property property">'Code Reference'</span><span class="token operator">:</span> <span class="token punctuation">[</span>Array<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token string-property property">'Ad Tech'</span><span class="token operator">:</span> <span class="token punctuation">[</span>Array<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token string-property property">'BAd Tech'</span><span class="token operator">:</span> <span class="token punctuation">[</span>Array<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token string-property property">'Broken By Design'</span><span class="token operator">:</span> <span class="token punctuation">[</span>Array<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">posts</span><span class="token operator">:</span> <span class="token punctuation">[</span>Array<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">projects</span><span class="token operator">:</span> <span class="token punctuation">[</span>Array<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">Starters</span><span class="token operator">:</span> <span class="token punctuation">[</span>Array<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token string-property property">'11ty'</span><span class="token operator">:</span> <span class="token punctuation">[</span>Array<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">Node</span><span class="token operator">:</span> <span class="token punctuation">[</span>Array<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">Sass</span><span class="token operator">:</span> <span class="token punctuation">[</span>Array<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">WiP</span><span class="token operator">:</span> <span class="token punctuation">[</span>Array<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token string-property property">'Github Actions'</span><span class="token operator">:</span> <span class="token punctuation">[</span>Array<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token constant">GPC</span><span class="token operator">:</span> <span class="token punctuation">[</span>Array<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token constant">CSS</span><span class="token operator">:</span> <span class="token punctuation">[</span>Array<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">Aggregation</span><span class="token operator">:</span> <span class="token punctuation">[</span>Array<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token constant">SEO</span><span class="token operator">:</span> <span class="token punctuation">[</span>Array<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token constant">SMO</span><span class="token operator">:</span> <span class="token punctuation">[</span>Array<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token string-property property">'Markdown-It'</span><span class="token operator">:</span> <span class="token punctuation">[</span>Array<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">tagList</span><span class="token operator">:</span> <span class="token punctuation">[</span>Array<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">deepTagList</span><span class="token operator">:</span> <span class="token punctuation">[</span>Array<span class="token punctuation">]</span><br />    <span class="token punctuation">}</span><br />  <span class="token punctuation">}</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">tokens</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">inlineMode</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">md</span><span class="token operator">:</span> MarkdownIt <span class="token punctuation">{</span><br />    <span class="token literal-property property">inline</span><span class="token operator">:</span> ParserInline <span class="token punctuation">{</span> <span class="token literal-property property">ruler</span><span class="token operator">:</span> <span class="token punctuation">[</span>Ruler<span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token literal-property property">ruler2</span><span class="token operator">:</span> <span class="token punctuation">[</span>Ruler<span class="token punctuation">]</span> <span class="token punctuation">}</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">block</span><span class="token operator">:</span> ParserBlock <span class="token punctuation">{</span> <span class="token literal-property property">ruler</span><span class="token operator">:</span> <span class="token punctuation">[</span>Ruler<span class="token punctuation">]</span> <span class="token punctuation">}</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">core</span><span class="token operator">:</span> Core <span class="token punctuation">{</span> <span class="token literal-property property">ruler</span><span class="token operator">:</span> <span class="token punctuation">[</span>Ruler<span class="token punctuation">]</span> <span class="token punctuation">}</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">renderer</span><span class="token operator">:</span> Renderer <span class="token punctuation">{</span> <span class="token literal-property property">rules</span><span class="token operator">:</span> <span class="token punctuation">[</span>Object<span class="token punctuation">]</span> <span class="token punctuation">}</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">linkify</span><span class="token operator">:</span> LinkifyIt <span class="token punctuation">{</span><br />      <span class="token literal-property property">__opts__</span><span class="token operator">:</span> <span class="token punctuation">[</span>Object<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">__index__</span><span class="token operator">:</span> <span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">__last_index__</span><span class="token operator">:</span> <span class="token number">29</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">__schema__</span><span class="token operator">:</span> <span class="token string">''</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">__text_cache__</span><span class="token operator">:</span> <span class="token string">'Especially with the variable name in the '</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">__schemas__</span><span class="token operator">:</span> <span class="token punctuation">[</span>Object<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">__compiled__</span><span class="token operator">:</span> <span class="token punctuation">[</span>Object<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">__tlds__</span><span class="token operator">:</span> <span class="token punctuation">[</span>Array<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">__tlds_replaced__</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">re</span><span class="token operator">:</span> <span class="token punctuation">[</span>Object<span class="token punctuation">]</span><br />    <span class="token punctuation">}</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">validateLink</span><span class="token operator">:</span> <span class="token punctuation">[</span>Function<span class="token operator">:</span> validateLink<span class="token punctuation">]</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">normalizeLink</span><span class="token operator">:</span> <span class="token punctuation">[</span>Function<span class="token operator">:</span> normalizeLink<span class="token punctuation">]</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">normalizeLinkText</span><span class="token operator">:</span> <span class="token punctuation">[</span>Function<span class="token operator">:</span> normalizeLinkText<span class="token punctuation">]</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">utils</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />      <span class="token literal-property property">lib</span><span class="token operator">:</span> <span class="token punctuation">[</span>Object<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">assign</span><span class="token operator">:</span> <span class="token punctuation">[</span>Function<span class="token operator">:</span> assign<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">isString</span><span class="token operator">:</span> <span class="token punctuation">[</span>Function<span class="token operator">:</span> isString<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">has</span><span class="token operator">:</span> <span class="token punctuation">[</span>Function<span class="token operator">:</span> has<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">unescapeMd</span><span class="token operator">:</span> <span class="token punctuation">[</span>Function<span class="token operator">:</span> unescapeMd<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">unescapeAll</span><span class="token operator">:</span> <span class="token punctuation">[</span>Function<span class="token operator">:</span> unescapeAll<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">isValidEntityCode</span><span class="token operator">:</span> <span class="token punctuation">[</span>Function<span class="token operator">:</span> isValidEntityCode<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">fromCodePoint</span><span class="token operator">:</span> <span class="token punctuation">[</span>Function<span class="token operator">:</span> fromCodePoint<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">escapeHtml</span><span class="token operator">:</span> <span class="token punctuation">[</span>Function<span class="token operator">:</span> escapeHtml<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">arrayReplaceAt</span><span class="token operator">:</span> <span class="token punctuation">[</span>Function<span class="token operator">:</span> arrayReplaceAt<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">isSpace</span><span class="token operator">:</span> <span class="token punctuation">[</span>Function<span class="token operator">:</span> isSpace<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">isWhiteSpace</span><span class="token operator">:</span> <span class="token punctuation">[</span>Function<span class="token operator">:</span> isWhiteSpace<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">isMdAsciiPunct</span><span class="token operator">:</span> <span class="token punctuation">[</span>Function<span class="token operator">:</span> isMdAsciiPunct<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">isPunctChar</span><span class="token operator">:</span> <span class="token punctuation">[</span>Function<span class="token operator">:</span> isPunctChar<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">escapeRE</span><span class="token operator">:</span> <span class="token punctuation">[</span>Function<span class="token operator">:</span> escapeRE<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">normalizeReference</span><span class="token operator">:</span> <span class="token punctuation">[</span>Function<span class="token operator">:</span> normalizeReference<span class="token punctuation">]</span><br />    <span class="token punctuation">}</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">helpers</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />      <span class="token literal-property property">parseLinkLabel</span><span class="token operator">:</span> <span class="token punctuation">[</span>Function<span class="token operator">:</span> parseLinkLabel<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">parseLinkDestination</span><span class="token operator">:</span> <span class="token punctuation">[</span>Function<span class="token operator">:</span> parseLinkDestination<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">parseLinkTitle</span><span class="token operator">:</span> <span class="token punctuation">[</span>Function<span class="token operator">:</span> parseLinkTitle<span class="token punctuation">]</span><br />    <span class="token punctuation">}</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">options</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />      <span class="token literal-property property">html</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">xhtmlOut</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">breaks</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">langPrefix</span><span class="token operator">:</span> <span class="token string">'language-'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">linkify</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">typographer</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">quotes</span><span class="token operator">:</span> <span class="token string">'“”‘’'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">highlight</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token function">Function</span> <span class="token punctuation">(</span>anonymous<span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">maxNesting</span><span class="token operator">:</span> <span class="token number">100</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">replaceLink</span><span class="token operator">:</span> <span class="token punctuation">[</span>Function<span class="token operator">:</span> replaceLink<span class="token punctuation">]</span><br />    <span class="token punctuation">}</span><br />  <span class="token punctuation">}</span><br /><span class="token punctuation">}</span></code></pre>
<p id="code-skip-hello-day-37-12">Oh, look at that. Everything I need to handle it at the rule level, instead of the <code>rerender</code> process!</p>
<p>Ok, so now I can make a plugin pretty similar to the one I did before.</p>
<h3 id="searching-for-git-commit-via-api" tabindex="-1">Searching for git commit via API</h3>
<p>I can find the commit message by searching through <code>inline</code> tokens, and pull the repo out of <code>state.env.repo</code>. I can then pull the commit message out of the inline token's <code>content</code> and use it with Octokit to search for the repo. The API query results in a <code>data</code> object with an <code>items</code> property that returns an array that looks like:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-37/#code-skip-hello-day-37-11" id="skip-to-code-skip-hello-day-37-11" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript"><span class="token punctuation">[</span><br />  <span class="token punctuation">{</span><br />    <span class="token literal-property property">url</span><span class="token operator">:</span> <span class="token string">'https://api.github.com/repos/AramZS/devblog/commits/29ae79850439397742e0b7147a0fd9b5683058a4'</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">sha</span><span class="token operator">:</span> <span class="token string">'29ae79850439397742e0b7147a0fd9b5683058a4'</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">node_id</span><span class="token operator">:</span> <span class="token string">'MDY6Q29tbWl0Mzc2NzA2MzI2OjI5YWU3OTg1MDQzOTM5Nzc0MmUwYjcxNDdhMGZkOWI1NjgzMDU4YTQ='</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">html_url</span><span class="token operator">:</span> <span class="token string">'https://github.com/AramZS/devblog/commit/29ae79850439397742e0b7147a0fd9b5683058a4'</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">comments_url</span><span class="token operator">:</span> <span class="token string">'https://api.github.com/repos/AramZS/devblog/commits/29ae79850439397742e0b7147a0fd9b5683058a4/comments'</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">commit</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />      <span class="token literal-property property">url</span><span class="token operator">:</span> <span class="token string">'https://api.github.com/repos/AramZS/devblog/git/commits/29ae79850439397742e0b7147a0fd9b5683058a4'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">author</span><span class="token operator">:</span> <span class="token punctuation">[</span>Object<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">committer</span><span class="token operator">:</span> <span class="token punctuation">[</span>Object<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">message</span><span class="token operator">:</span> <span class="token string">'Set up blogroll and links and write up day 26'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">tree</span><span class="token operator">:</span> <span class="token punctuation">[</span>Object<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">comment_count</span><span class="token operator">:</span> <span class="token number">0</span><br />    <span class="token punctuation">}</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">author</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />      <span class="token literal-property property">login</span><span class="token operator">:</span> <span class="token string">'AramZS'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">id</span><span class="token operator">:</span> <span class="token number">748069</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">node_id</span><span class="token operator">:</span> <span class="token string">'MDQ6VXNlcjc0ODA2OQ=='</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">avatar_url</span><span class="token operator">:</span> <span class="token string">'https://avatars.githubusercontent.com/u/748069?v=4'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">gravatar_id</span><span class="token operator">:</span> <span class="token string">''</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">url</span><span class="token operator">:</span> <span class="token string">'https://api.github.com/users/AramZS'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">html_url</span><span class="token operator">:</span> <span class="token string">'https://github.com/AramZS'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">followers_url</span><span class="token operator">:</span> <span class="token string">'https://api.github.com/users/AramZS/followers'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">following_url</span><span class="token operator">:</span> <span class="token string">'https://api.github.com/users/AramZS/following{/other_user}'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">gists_url</span><span class="token operator">:</span> <span class="token string">'https://api.github.com/users/AramZS/gists{/gist_id}'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">starred_url</span><span class="token operator">:</span> <span class="token string">'https://api.github.com/users/AramZS/starred{/owner}{/repo}'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">subscriptions_url</span><span class="token operator">:</span> <span class="token string">'https://api.github.com/users/AramZS/subscriptions'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">organizations_url</span><span class="token operator">:</span> <span class="token string">'https://api.github.com/users/AramZS/orgs'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">repos_url</span><span class="token operator">:</span> <span class="token string">'https://api.github.com/users/AramZS/repos'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">events_url</span><span class="token operator">:</span> <span class="token string">'https://api.github.com/users/AramZS/events{/privacy}'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">received_events_url</span><span class="token operator">:</span> <span class="token string">'https://api.github.com/users/AramZS/received_events'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">type</span><span class="token operator">:</span> <span class="token string">'User'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">site_admin</span><span class="token operator">:</span> <span class="token boolean">false</span><br />    <span class="token punctuation">}</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">committer</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />      <span class="token literal-property property">login</span><span class="token operator">:</span> <span class="token string">'AramZS'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">id</span><span class="token operator">:</span> <span class="token number">748069</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">node_id</span><span class="token operator">:</span> <span class="token string">'MDQ6VXNlcjc0ODA2OQ=='</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">avatar_url</span><span class="token operator">:</span> <span class="token string">'https://avatars.githubusercontent.com/u/748069?v=4'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">gravatar_id</span><span class="token operator">:</span> <span class="token string">''</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">url</span><span class="token operator">:</span> <span class="token string">'https://api.github.com/users/AramZS'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">html_url</span><span class="token operator">:</span> <span class="token string">'https://github.com/AramZS'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">followers_url</span><span class="token operator">:</span> <span class="token string">'https://api.github.com/users/AramZS/followers'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">following_url</span><span class="token operator">:</span> <span class="token string">'https://api.github.com/users/AramZS/following{/other_user}'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">gists_url</span><span class="token operator">:</span> <span class="token string">'https://api.github.com/users/AramZS/gists{/gist_id}'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">starred_url</span><span class="token operator">:</span> <span class="token string">'https://api.github.com/users/AramZS/starred{/owner}{/repo}'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">subscriptions_url</span><span class="token operator">:</span> <span class="token string">'https://api.github.com/users/AramZS/subscriptions'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">organizations_url</span><span class="token operator">:</span> <span class="token string">'https://api.github.com/users/AramZS/orgs'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">repos_url</span><span class="token operator">:</span> <span class="token string">'https://api.github.com/users/AramZS/repos'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">events_url</span><span class="token operator">:</span> <span class="token string">'https://api.github.com/users/AramZS/events{/privacy}'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">received_events_url</span><span class="token operator">:</span> <span class="token string">'https://api.github.com/users/AramZS/received_events'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">type</span><span class="token operator">:</span> <span class="token string">'User'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">site_admin</span><span class="token operator">:</span> <span class="token boolean">false</span><br />    <span class="token punctuation">}</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">parents</span><span class="token operator">:</span> <span class="token punctuation">[</span> <span class="token punctuation">[</span>Object<span class="token punctuation">]</span> <span class="token punctuation">]</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">repository</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />      <span class="token literal-property property">id</span><span class="token operator">:</span> <span class="token number">376706326</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">node_id</span><span class="token operator">:</span> <span class="token string">'MDEwOlJlcG9zaXRvcnkzNzY3MDYzMjY='</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'devblog'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">full_name</span><span class="token operator">:</span> <span class="token string">'AramZS/devblog'</span><span class="token punctuation">,</span><br />      <span class="token keyword">private</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">owner</span><span class="token operator">:</span> <span class="token punctuation">[</span>Object<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">html_url</span><span class="token operator">:</span> <span class="token string">'https://github.com/AramZS/devblog'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">description</span><span class="token operator">:</span> <span class="token keyword">null</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">fork</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">url</span><span class="token operator">:</span> <span class="token string">'https://api.github.com/repos/AramZS/devblog'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">forks_url</span><span class="token operator">:</span> <span class="token string">'https://api.github.com/repos/AramZS/devblog/forks'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">keys_url</span><span class="token operator">:</span> <span class="token string">'https://api.github.com/repos/AramZS/devblog/keys{/key_id}'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">collaborators_url</span><span class="token operator">:</span> <span class="token string">'https://api.github.com/repos/AramZS/devblog/collaborators{/collaborator}'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">teams_url</span><span class="token operator">:</span> <span class="token string">'https://api.github.com/repos/AramZS/devblog/teams'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">hooks_url</span><span class="token operator">:</span> <span class="token string">'https://api.github.com/repos/AramZS/devblog/hooks'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">issue_events_url</span><span class="token operator">:</span> <span class="token string">'https://api.github.com/repos/AramZS/devblog/issues/events{/number}'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">events_url</span><span class="token operator">:</span> <span class="token string">'https://api.github.com/repos/AramZS/devblog/events'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">assignees_url</span><span class="token operator">:</span> <span class="token string">'https://api.github.com/repos/AramZS/devblog/assignees{/user}'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">branches_url</span><span class="token operator">:</span> <span class="token string">'https://api.github.com/repos/AramZS/devblog/branches{/branch}'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">tags_url</span><span class="token operator">:</span> <span class="token string">'https://api.github.com/repos/AramZS/devblog/tags'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">blobs_url</span><span class="token operator">:</span> <span class="token string">'https://api.github.com/repos/AramZS/devblog/git/blobs{/sha}'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">git_tags_url</span><span class="token operator">:</span> <span class="token string">'https://api.github.com/repos/AramZS/devblog/git/tags{/sha}'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">git_refs_url</span><span class="token operator">:</span> <span class="token string">'https://api.github.com/repos/AramZS/devblog/git/refs{/sha}'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">trees_url</span><span class="token operator">:</span> <span class="token string">'https://api.github.com/repos/AramZS/devblog/git/trees{/sha}'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">statuses_url</span><span class="token operator">:</span> <span class="token string">'https://api.github.com/repos/AramZS/devblog/statuses/{sha}'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">languages_url</span><span class="token operator">:</span> <span class="token string">'https://api.github.com/repos/AramZS/devblog/languages'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">stargazers_url</span><span class="token operator">:</span> <span class="token string">'https://api.github.com/repos/AramZS/devblog/stargazers'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">contributors_url</span><span class="token operator">:</span> <span class="token string">'https://api.github.com/repos/AramZS/devblog/contributors'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">subscribers_url</span><span class="token operator">:</span> <span class="token string">'https://api.github.com/repos/AramZS/devblog/subscribers'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">subscription_url</span><span class="token operator">:</span> <span class="token string">'https://api.github.com/repos/AramZS/devblog/subscription'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">commits_url</span><span class="token operator">:</span> <span class="token string">'https://api.github.com/repos/AramZS/devblog/commits{/sha}'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">git_commits_url</span><span class="token operator">:</span> <span class="token string">'https://api.github.com/repos/AramZS/devblog/git/commits{/sha}'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">comments_url</span><span class="token operator">:</span> <span class="token string">'https://api.github.com/repos/AramZS/devblog/comments{/number}'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">issue_comment_url</span><span class="token operator">:</span> <span class="token string">'https://api.github.com/repos/AramZS/devblog/issues/comments{/number}'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">contents_url</span><span class="token operator">:</span> <span class="token string">'https://api.github.com/repos/AramZS/devblog/contents/{+path}'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">compare_url</span><span class="token operator">:</span> <span class="token string">'https://api.github.com/repos/AramZS/devblog/compare/{base}...{head}'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">merges_url</span><span class="token operator">:</span> <span class="token string">'https://api.github.com/repos/AramZS/devblog/merges'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">archive_url</span><span class="token operator">:</span> <span class="token string">'https://api.github.com/repos/AramZS/devblog/{archive_format}{/ref}'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">downloads_url</span><span class="token operator">:</span> <span class="token string">'https://api.github.com/repos/AramZS/devblog/downloads'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">issues_url</span><span class="token operator">:</span> <span class="token string">'https://api.github.com/repos/AramZS/devblog/issues{/number}'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">pulls_url</span><span class="token operator">:</span> <span class="token string">'https://api.github.com/repos/AramZS/devblog/pulls{/number}'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">milestones_url</span><span class="token operator">:</span> <span class="token string">'https://api.github.com/repos/AramZS/devblog/milestones{/number}'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">notifications_url</span><span class="token operator">:</span> <span class="token string">'https://api.github.com/repos/AramZS/devblog/notifications{?since,all,participating}'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">labels_url</span><span class="token operator">:</span> <span class="token string">'https://api.github.com/repos/AramZS/devblog/labels{/name}'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">releases_url</span><span class="token operator">:</span> <span class="token string">'https://api.github.com/repos/AramZS/devblog/releases{/id}'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">deployments_url</span><span class="token operator">:</span> <span class="token string">'https://api.github.com/repos/AramZS/devblog/deployments'</span><br />    <span class="token punctuation">}</span><span class="token punctuation">,</span><br />    <span class="token literal-property property">score</span><span class="token operator">:</span> <span class="token number">1</span><br />  <span class="token punctuation">}</span><br /><span class="token punctuation">]</span></code></pre>
<p data-wordfix="true" id="code-skip-hello-day-37-11">So what I need is definitely in there. Now I just need to figure out how to get it out of the async request on on to my new token.</p>
<h3 id="caching-commit-links" tabindex="-1">Caching Commit Links</h3>
<p data-wordfix="true">Hmm, <a href="https://github.com/markdown-it/markdown-it/blob/master/docs/development.md#i-need-async-rule-how-to-do-it" target="_blank">it looks like getting the async data into there is going to be the most complex part</a>. The right answer has to be caching, and it looks like there is <a href="https://www.11ty.dev/docs/plugins/cache/" target="_blank">an Eleventy native tool for that</a>, but I think that might be overkill. Especially because I want something I <em>can</em> save as basically a static file, since this won't be changing. Also, the Eleventy plugin won't work because it is still async. This means I'm basically required to handle this as a file. Also, need to watch out as if I write to the directory I'm watching, I may end up triggering the watch in a loop.</p>
<p>Another thing I'll need to be careful of when caching this data is if I'm automatically creating files, I should likely be using the query as a file key, that query may contain characters not safe for file names, so I'll need to pull something in to handle sanitization.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-37/#code-skip-hello-day-37-10" id="skip-to-code-skip-hello-day-37-10" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">var</span> sanitizeFilename <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">"sanitize-filename"</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p id="code-skip-hello-day-37-10">Ok, so let's start putting it down.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-37/#code-skip-hello-day-37-9" id="skip-to-code-skip-hello-day-37-9" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> <span class="token function-variable function">commit_pattern</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />	<span class="token keyword">return</span> <span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">(?&lt;=git commit \-am [\"|\'])(.+)(?=[\"|\'])</span><span class="token regex-delimiter">/</span><span class="token regex-flags">i</span></span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span><br /><span class="token comment">// I can get the "repo" from the post object</span><br /><span class="token comment">// Then I need to change the commit message I captured</span><br /><span class="token comment">// Queries don't allow spaces, so replace them with "+"</span><br /><span class="token keyword">const</span> <span class="token function-variable function">gitSearchQuery</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">repo<span class="token punctuation">,</span> commitMsg</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />	<span class="token keyword">const</span> searchCommitMsg <span class="token operator">=</span> commitMsg<span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span><span class="token string">" "</span><span class="token punctuation">,</span> <span class="token string">"+"</span><span class="token punctuation">)</span><br />	<span class="token keyword">const</span> repoName <span class="token operator">=</span> repo<span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span><span class="token string">"https://github.com/"</span><span class="token punctuation">,</span> <span class="token string">""</span><span class="token punctuation">)</span><br />	<span class="token keyword">return</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">repo:</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>repoName<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">+</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>searchCommitMsg<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><br /><span class="token punctuation">}</span></code></pre>
<p id="code-skip-hello-day-37-9">Now let's create a function to figure out the path to the new cache folder.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-37/#code-skip-hello-day-37-8" id="skip-to-code-skip-hello-day-37-8" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> <span class="token function-variable function">cacheFilePath</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">pageFilePath<span class="token punctuation">,</span> searchKey</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />	<span class="token keyword">const</span> cacheFolder <span class="token operator">=</span> path<span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span>__dirname<span class="token punctuation">,</span> <span class="token string">"../../"</span><span class="token punctuation">,</span> <span class="token string">'/_queryCache'</span><span class="token punctuation">,</span> pageFilePath<span class="token punctuation">)</span><br />	<span class="token keyword">const</span> cacheFile <span class="token operator">=</span> cacheFolder<span class="token operator">+</span><span class="token function">sanitizeFilename</span><span class="token punctuation">(</span><span class="token function">slugify</span><span class="token punctuation">(</span>searchKey<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span><span class="token string">"."</span><span class="token punctuation">,</span> <span class="token string">""</span><span class="token punctuation">)</span><span class="token punctuation">)</span><br />	<span class="token comment">// console.log('cacheFile: ', cacheFile)</span><br />	<span class="token keyword">return</span> <span class="token punctuation">{</span> cacheFolder<span class="token punctuation">,</span> cacheFile <span class="token punctuation">}</span><br /><span class="token punctuation">}</span></code></pre>
<p id="code-skip-hello-day-37-8">I can use <code>fs.accessSync</code> to check if the file exists before creating a cache. After all I don't want to query GitHub every time I do a build. So we can use this in the process to find the repo commit link.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-37/#code-skip-hello-day-37-7" id="skip-to-code-skip-hello-day-37-7" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> <span class="token function-variable function">getLinkToRepo</span> <span class="token operator">=</span> <span class="token keyword">async</span> <span class="token punctuation">(</span><span class="token parameter">repo<span class="token punctuation">,</span> commitMsg<span class="token punctuation">,</span> pageFilePath</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />	<span class="token keyword">const</span> searchKey <span class="token operator">=</span> <span class="token function">gitSearchQuery</span><span class="token punctuation">(</span>repo<span class="token punctuation">,</span> commitMsg<span class="token punctuation">)</span><br />	<span class="token keyword">const</span> <span class="token punctuation">{</span>cacheFolder<span class="token punctuation">,</span> cacheFile<span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token function">cacheFilePath</span><span class="token punctuation">(</span>pageFilePath<span class="token punctuation">,</span> searchKey<span class="token punctuation">)</span><br />	<span class="token keyword">try</span> <span class="token punctuation">{</span><br />		fs<span class="token punctuation">.</span><span class="token function">accessSync</span><span class="token punctuation">(</span>cacheFile<span class="token punctuation">,</span> fs<span class="token punctuation">.</span>constants<span class="token punctuation">.</span><span class="token constant">F_OK</span><span class="token punctuation">)</span><br />		<span class="token keyword">return</span> <span class="token boolean">true</span><span class="token punctuation">;</span></code></pre>
<p id="code-skip-hello-day-37-7">If it exists the function ends here and returns true.</p>
<p>But when we know the file doesn't exist we will have to continue using the <code>catch</code>. I'll make a request to GitHub using Octokit. I'm pretty much skipping over how I set up Octokit because this is basically the boilerplate.</p>
<p>The only thing that I have added into the mix here is to get my Github Key using the environment. Locally I'll use DotEnv <code>require('dotenv').config()</code>. But I'll have to figure out how to handle it on GitHub next. And I get the searchKey using my above function <code>gitSearchQuery</code>.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-37/#code-skip-hello-day-37-6" id="skip-to-code-skip-hello-day-37-6" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript"><span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span>e<span class="token punctuation">)</span> <span class="token punctuation">{</span><br />		console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Query is not cached: '</span><span class="token punctuation">,</span> cacheFile<span class="token punctuation">,</span> e<span class="token punctuation">)</span><br />		<span class="token keyword">const</span> MyOctokit <span class="token operator">=</span> Octokit<span class="token punctuation">.</span><span class="token function">plugin</span><span class="token punctuation">(</span>retry<span class="token punctuation">,</span> throttling<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br />		<span class="token keyword">const</span> myOctokit <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">MyOctokit</span><span class="token punctuation">(</span><span class="token punctuation">{</span><br />		<span class="token literal-property property">auth</span><span class="token operator">:</span> process<span class="token punctuation">.</span>env<span class="token punctuation">.</span><span class="token constant">GITHUB_KEY</span><span class="token punctuation">,</span><br />		<span class="token literal-property property">throttle</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />			<span class="token function-variable function">onRateLimit</span><span class="token operator">:</span> <span class="token punctuation">(</span><span class="token parameter">retryAfter<span class="token punctuation">,</span> options</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />			myOctokit<span class="token punctuation">.</span>log<span class="token punctuation">.</span><span class="token function">warn</span><span class="token punctuation">(</span><br />				<span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">Request quota exhausted for request </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>options<span class="token punctuation">.</span>method<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>options<span class="token punctuation">.</span>url<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><br />			<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br />			<span class="token keyword">if</span> <span class="token punctuation">(</span>options<span class="token punctuation">.</span>request<span class="token punctuation">.</span>retryCount <span class="token operator">===</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />				<span class="token comment">// only retries once</span><br />				myOctokit<span class="token punctuation">.</span>log<span class="token punctuation">.</span><span class="token function">info</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">Retrying after </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>retryAfter<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> seconds!</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />				<span class="token keyword">return</span> <span class="token boolean">true</span><span class="token punctuation">;</span><br />			<span class="token punctuation">}</span><br />			<span class="token punctuation">}</span><span class="token punctuation">,</span><br />			<span class="token function-variable function">onAbuseLimit</span><span class="token operator">:</span> <span class="token punctuation">(</span><span class="token parameter">retryAfter<span class="token punctuation">,</span> options</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />			<span class="token comment">// does not retry, only logs a warning</span><br />				myOctokit<span class="token punctuation">.</span>log<span class="token punctuation">.</span><span class="token function">warn</span><span class="token punctuation">(</span><br />					<span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">Abuse detected for request </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>options<span class="token punctuation">.</span>method<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>options<span class="token punctuation">.</span>url<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><br />				<span class="token punctuation">)</span><span class="token punctuation">;</span><br />			<span class="token punctuation">}</span><span class="token punctuation">,</span><br />		<span class="token punctuation">}</span><span class="token punctuation">,</span><br />		<span class="token literal-property property">retry</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />			<span class="token literal-property property">doNotRetry</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">"429"</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br />		<span class="token punctuation">}</span><span class="token punctuation">,</span><br />		<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />		<span class="token keyword">const</span> r <span class="token operator">=</span> <span class="token keyword">await</span> myOctokit<span class="token punctuation">.</span>rest<span class="token punctuation">.</span>search<span class="token punctuation">.</span><span class="token function">commits</span><span class="token punctuation">(</span><span class="token punctuation">{</span><br />			<span class="token literal-property property">q</span><span class="token operator">:</span> searchKey<span class="token punctuation">,</span><br />		<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />		<span class="token keyword">if</span> <span class="token punctuation">(</span>r <span class="token operator">&amp;&amp;</span> r<span class="token punctuation">.</span>data <span class="token operator">&amp;&amp;</span> r<span class="token punctuation">.</span>data<span class="token punctuation">.</span>items <span class="token operator">&amp;&amp;</span> r<span class="token punctuation">.</span>data<span class="token punctuation">.</span>items<span class="token punctuation">.</span>length<span class="token punctuation">)</span><span class="token punctuation">{</span></code></pre>
<p id="code-skip-hello-day-37-6">Once the commit is found, I'll try to cache it by writing a file using the path to the post and then the search query as a file key.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-37/#code-skip-hello-day-37-5" id="skip-to-code-skip-hello-day-37-5" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">try</span> <span class="token punctuation">{</span><br />	fs<span class="token punctuation">.</span><span class="token function">mkdirSync</span><span class="token punctuation">(</span>cacheFolder<span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">recursive</span><span class="token operator">:</span> <span class="token boolean">true</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><br />	<span class="token comment">// console.log('write data to file', cacheFile)</span><br />	fs<span class="token punctuation">.</span><span class="token function">writeFileSync</span><span class="token punctuation">(</span>cacheFile<span class="token punctuation">,</span> r<span class="token punctuation">.</span>data<span class="token punctuation">.</span>items<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">.</span>html_url<span class="token punctuation">)</span><br /><span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span>e<span class="token punctuation">)</span> <span class="token punctuation">{</span><br />	console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'writing to cache failed:'</span><span class="token punctuation">,</span> e<span class="token punctuation">)</span><br /><span class="token punctuation">}</span><br /><span class="token keyword">return</span> r<span class="token punctuation">.</span>data<span class="token punctuation">.</span>items<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">.</span>html_url</code></pre>
<p id="code-skip-hello-day-37-5">Now that I have a way to handle caching, I need to trigger it as part of the markdown building process.</p>
<h3 id="rendering-link-with-markdown-it" tabindex="-1">Rendering link with Markdown It</h3>
<p>I'll need a process to actually create the link on the commit in the <code>markdown-it</code> way.</p>
<p>I'll need to create HTML tokens for the link open and close as follows:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-37/#code-skip-hello-day-37-4" id="skip-to-code-skip-hello-day-37-4" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> <span class="token function-variable function">createLinkTokens</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">TokenConstructor<span class="token punctuation">,</span>commitLink</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />	<span class="token keyword">const</span> link_open <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">TokenConstructor</span><span class="token punctuation">(</span><span class="token string">'html_inline'</span><span class="token punctuation">,</span> <span class="token string">''</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">)</span><br />	link_open<span class="token punctuation">.</span>content <span class="token operator">=</span> <span class="token string">'&lt;a href="'</span><span class="token operator">+</span>commitLink<span class="token operator">+</span><span class="token string">'" target="_blank">'</span><br />	<span class="token keyword">const</span> link_close <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">TokenConstructor</span><span class="token punctuation">(</span><span class="token string">'html_inline'</span><span class="token punctuation">,</span> <span class="token string">''</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">)</span><br />	link_close<span class="token punctuation">.</span>content <span class="token operator">=</span> <span class="token string">'&lt;/a>'</span><br />	<span class="token keyword">return</span> <span class="token punctuation">{</span>link_open<span class="token punctuation">,</span> link_close<span class="token punctuation">}</span><br /><span class="token punctuation">}</span></code></pre>
<p id="code-skip-hello-day-37-4">I'll need to take the markdown-it object and create a new <code>ruler</code> rule. I'll use <code>state.env</code> to check for the <code>repo</code> property and test for the commit pattern in each <code>inline</code> token. By using <code>inline</code> instead of <code>code_inline</code> I will be able to place my new <code>html_inline</code> token around the commit text.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-37/#code-skip-hello-day-37-3" id="skip-to-code-skip-hello-day-37-3" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript"><br /><span class="token keyword">const</span> <span class="token function-variable function">gitCommitRule</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">md</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />	md<span class="token punctuation">.</span>core<span class="token punctuation">.</span>ruler<span class="token punctuation">.</span><span class="token function">after</span><span class="token punctuation">(</span><span class="token string">'inline'</span><span class="token punctuation">,</span> <span class="token string">'git_commit'</span><span class="token punctuation">,</span> <span class="token parameter">state</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />		<span class="token keyword">const</span> tokens <span class="token operator">=</span> state<span class="token punctuation">.</span>tokens<br />		<span class="token keyword">if</span> <span class="token punctuation">(</span>state<span class="token punctuation">.</span>env<span class="token punctuation">.</span><span class="token function">hasOwnProperty</span><span class="token punctuation">(</span><span class="token string">'repo'</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">{</span><br />			<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">let</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&lt;</span> tokens<span class="token punctuation">.</span>length<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />				<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">commit_pattern</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">test</span><span class="token punctuation">(</span>tokens<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">.</span>content<span class="token punctuation">)</span> <span class="token operator">&amp;&amp;</span> tokens<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">.</span>type <span class="token operator">===</span> <span class="token string">'inline'</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />					<span class="token comment">// console.log('tokens round 1: ', tokens[i])</span><br />					<span class="token keyword">const</span> commitMessage <span class="token operator">=</span> tokens<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">.</span>content<span class="token punctuation">.</span><span class="token function">match</span><span class="token punctuation">(</span><span class="token function">commit_pattern</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><br />					<span class="token keyword">const</span> searchKey <span class="token operator">=</span> <span class="token function">gitSearchQuery</span><span class="token punctuation">(</span>state<span class="token punctuation">.</span>env<span class="token punctuation">.</span>repo<span class="token punctuation">,</span> commitMessage<span class="token punctuation">)</span><br />					<span class="token keyword">const</span> <span class="token punctuation">{</span>cacheFolder<span class="token punctuation">,</span> cacheFile<span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token function">cacheFilePath</span><span class="token punctuation">(</span>state<span class="token punctuation">.</span>env<span class="token punctuation">.</span>page<span class="token punctuation">.</span>url<span class="token punctuation">,</span> searchKey<span class="token punctuation">)</span><br />					<span class="token function">getLinkToRepo</span><span class="token punctuation">(</span>state<span class="token punctuation">.</span>env<span class="token punctuation">.</span>repo<span class="token punctuation">,</span> commitMessage<span class="token punctuation">,</span> state<span class="token punctuation">.</span>env<span class="token punctuation">.</span>page<span class="token punctuation">.</span>url<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">commitLink</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br /><br />					<span class="token punctuation">}</span><span class="token punctuation">)</span><br />					<span class="token keyword">let</span> envRepo <span class="token operator">=</span> state<span class="token punctuation">.</span>env<span class="token punctuation">.</span>repo<span class="token punctuation">;</span><br />					<span class="token keyword">let</span> linkToRepo <span class="token operator">=</span> <span class="token string">''</span><br />					<span class="token comment">// Let's make the default link go to the commit log, that makes more sense.</span><br />					linkToRepo <span class="token operator">=</span> envRepo<br />					<span class="token keyword">if</span> <span class="token punctuation">(</span>envRepo<span class="token punctuation">.</span><span class="token function">slice</span><span class="token punctuation">(</span><span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">)</span> <span class="token operator">!=</span> <span class="token string">"/"</span><span class="token punctuation">)</span><span class="token punctuation">{</span><br />						<span class="token comment">// Assure the last character is a "/"</span><br />						linkToRepo <span class="token operator">+=</span> <span class="token string">"/"</span><br />					<span class="token punctuation">}</span><br />					linkToRepo <span class="token operator">+=</span> <span class="token string">"commits/main"</span><br />					<span class="token keyword">try</span> <span class="token punctuation">{</span><br />						fs<span class="token punctuation">.</span><span class="token function">accessSync</span><span class="token punctuation">(</span>cacheFile<span class="token punctuation">,</span> fs<span class="token punctuation">.</span>constants<span class="token punctuation">.</span><span class="token constant">F_OK</span><span class="token punctuation">)</span><br />						linkToRepo <span class="token operator">=</span> <span class="token punctuation">(</span>fs<span class="token punctuation">.</span><span class="token function">readFileSync</span><span class="token punctuation">(</span>cacheFile<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toString</span><span class="token punctuation">(</span><span class="token punctuation">)</span><br />					<span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span>e<span class="token punctuation">)</span> <span class="token punctuation">{</span><br />						<span class="token comment">// No file yet</span><br />						console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Cached link to repo not ready'</span><span class="token punctuation">,</span> e<span class="token punctuation">)</span><br />					<span class="token punctuation">}</span><br />					<span class="token keyword">const</span> <span class="token punctuation">{</span> link_open<span class="token punctuation">,</span> link_close <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token function">createLinkTokens</span><span class="token punctuation">(</span>state<span class="token punctuation">.</span>Token<span class="token punctuation">,</span>linkToRepo<span class="token punctuation">)</span><br />					tokens<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">.</span>children<span class="token punctuation">.</span><span class="token function">unshift</span><span class="token punctuation">(</span>link_open<span class="token punctuation">)</span><br />					tokens<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">.</span>children<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span>link_close<span class="token punctuation">)</span><br /><br />				<span class="token punctuation">}</span><br />			<span class="token punctuation">}</span><br />		<span class="token punctuation">}</span><br />	<span class="token punctuation">}</span><span class="token punctuation">)</span><br /><span class="token punctuation">}</span><br /><br />module<span class="token punctuation">.</span><span class="token function-variable function">exports</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">md</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />	<span class="token function">gitCommitRule</span><span class="token punctuation">(</span>md<span class="token punctuation">)</span><br /><span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
<h3 id="adding-link-css" tabindex="-1">Adding Link CSS</h3>
<p id="code-skip-hello-day-37-3">It's looking good here, though it isn't super clear that it is a link. Maybe I can add some style to it. Let me grab an <a href="https://www.pinclipart.com/downpngs/iRxxRho_link-icon-navy-blue-blue-link-icon-png/" target="_blank">image of a link</a> to add to the style. <a href="https://onlinepngtools.com/resize-png" target="_blank">I'll need to size it down</a>.</p>
<p><a target="_blank" href="https://github.com/AramZS/devblog/commit/16c34c4dc621d3784e9cf14be6b8be8574c2368f" class="git-commit-link"><code>git commit -am &quot;Adding links to commits across all new posts along with a whole new plugin for building links to commits automatically into new posts for day 37&quot;</code></a></p>
<p>Then I can add the CSS.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-37/#code-skip-hello-day-37-2" id="skip-to-code-skip-hello-day-37-2" class="skip-link">Skip code block ▼</a></p>
<pre class="language-scss"><code class="language-scss">.git-commit-link<br />    <span class="token property">text-decoration</span><span class="token punctuation">:</span> underline<br />    &amp;<span class="token punctuation">:</span>hover<br />        <span class="token property">text-decoration-color</span><span class="token punctuation">:</span> grey<br />    &amp;<span class="token punctuation">:</span>after<br />        <span class="token property">content</span><span class="token punctuation">:</span> <span class="token string">' '</span><br />        <span class="token property">background</span><span class="token punctuation">:</span> transparent <span class="token url">url</span><span class="token punctuation">(</span>/img/linkicon-s.png<span class="token punctuation">)</span> center right no-repeat<br />        <span class="token property">font-weight</span><span class="token punctuation">:</span> normal<br />        <span class="token property">font-style</span><span class="token punctuation">:</span> normal<br />        <span class="token property">margin</span><span class="token punctuation">:</span> 0px 0px 0px 10px<br />        <span class="token property">text-decoration</span><span class="token punctuation">:</span> none<br />        <span class="token property">background-size</span><span class="token punctuation">:</span> contain<br />        <span class="token property">display</span><span class="token punctuation">:</span> inline-block<br />        <span class="token property">width</span><span class="token punctuation">:</span> 12px<br />        <span class="token property">height</span><span class="token punctuation">:</span> 12px</code></pre>
<p id="code-skip-hello-day-37-2"><a target="_blank" href="https://github.com/AramZS/devblog/commit/342836cd4780ce10e42d18a5c34d4403e5101d3c" class="git-commit-link"><code>git commit -am &quot;Set the default link for repos to go to the main commit log&quot;</code></a></p>
<h3 id="touch-up-of-markdown-it-link-process" tabindex="-1">Touch Up of Markdown It Link Process</h3>
<p>After <a href="https://github.com/markdown-it/markdown-it/issues/834" target="_blank">getting a very helpful response from the Markdown-It team</a> it looks like the <code>html_inline</code> process I used to add the link isn't really best practice.</p>
<h4 id="push-to-end-of-core-rules" tabindex="-1">Push to end of core rules</h4>
<p>So I found two changes I needed to make. First, I needed to push the rule as the last <code>core</code> rule. It turns out there is a function specifically for this, so I used it and now declare my rule using <code>md.core.ruler.push('git_commit', state =&gt; {</code>.</p>
<h4 id="create-link-tokens" tabindex="-1">Create link tokens</h4>
<p>The other change is to use <code>TokenConstructer</code> to make a real token and not <code>html_inline</code> which doesn't have any of the tools and hooks that a normal token does. So now my function to create tokens looks like:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-37/#code-skip-hello-day-37-1" id="skip-to-code-skip-hello-day-37-1" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">function</span> <span class="token function">setAttr</span><span class="token punctuation">(</span><span class="token parameter">token<span class="token punctuation">,</span> name<span class="token punctuation">,</span> value</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />	<span class="token keyword">const</span> index <span class="token operator">=</span> token<span class="token punctuation">.</span><span class="token function">attrIndex</span><span class="token punctuation">(</span>name<span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token keyword">const</span> attr <span class="token operator">=</span> <span class="token punctuation">[</span>name<span class="token punctuation">,</span> value<span class="token punctuation">]</span><span class="token punctuation">;</span><br /><br />	<span class="token keyword">if</span> <span class="token punctuation">(</span>index <span class="token operator">&lt;</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />		token<span class="token punctuation">.</span><span class="token function">attrPush</span><span class="token punctuation">(</span>attr<span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span><br />		token<span class="token punctuation">.</span>attrs<span class="token punctuation">[</span>index<span class="token punctuation">]</span> <span class="token operator">=</span> attr<span class="token punctuation">;</span><br />	<span class="token punctuation">}</span><br /><span class="token punctuation">}</span><br /><br /><span class="token keyword">const</span> <span class="token function-variable function">createLinkTokens</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">TokenConstructor<span class="token punctuation">,</span> commitLink</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />	<span class="token keyword">const</span> link_open <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">TokenConstructor</span><span class="token punctuation">(</span><span class="token string">"link_open"</span><span class="token punctuation">,</span> <span class="token string">"a"</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token function">setAttr</span><span class="token punctuation">(</span>link_open<span class="token punctuation">,</span> <span class="token string">"target"</span><span class="token punctuation">,</span> <span class="token string">"_blank"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token function">setAttr</span><span class="token punctuation">(</span>link_open<span class="token punctuation">,</span> <span class="token string">"href"</span><span class="token punctuation">,</span> commitLink<span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token function">setAttr</span><span class="token punctuation">(</span>link_open<span class="token punctuation">,</span> <span class="token string">"class"</span><span class="token punctuation">,</span> <span class="token string">"git-commit-link"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token comment">// This is haunting me, so I asked - https://github.com/markdown-it/markdown-it/issues/834</span><br />	<span class="token keyword">const</span> link_close <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">TokenConstructor</span><span class="token punctuation">(</span><span class="token string">"link_close"</span><span class="token punctuation">,</span> <span class="token string">"a"</span><span class="token punctuation">,</span> <span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token keyword">return</span> <span class="token punctuation">{</span> link_open<span class="token punctuation">,</span> link_close <span class="token punctuation">}</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
<p id="code-skip-hello-day-37-1">The 1/-1 here allows me to open and close the <code>a</code> tag and now I can use the <code>attrPush</code> on the token which is a much better practice.</p>
<p>Great!</p>
<p><a target="_blank" href="https://github.com/AramZS/devblog/commit/af17fab3dd8a9f99200ecd93518eef2e5d7aaccc" class="git-commit-link"><code>git commit -am &quot;Switching git-commit process to build link using link_open and link_close&quot;</code></a></p>
<h4 id="can't-start-secrets-with-github" tabindex="-1">Can't start secrets with GITHUB</h4>
<p>While prepping to merge I wanted to add the GITHUB_KEY <code>env</code> secret. But it turns out I can't start my keynames with <code>GITHUB_</code>. So I gotta rename it.</p>
]]></content:encoded>
	</item>
	
	<item>
		<title>Part 36: A Markdown It Plugin - Understand the Ruler</title>
		<link>https://fightwithtools.dev/posts/projects/devblog/hello-day-36/?source=rss</link>
		<pubDate>Sat, 13 Nov 2021 02:59:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/projects/devblog/hello-day-36/</guid>
		<description>More devblog</description>
		<content:encoded><![CDATA[<h2 id="project-scope-and-todos" tabindex="-1">Project Scope and ToDos</h2>
<ol>
<li>Static Site Generator that can build the blog and let me host it on Github Pages</li>
<li>I want to write posts in Markdown because I'm lazy, it's easy, and it is how I take notes now.</li>
<li>I don't want to spend a ton of time doing design work. I'm doing complicated designs for other projects, so I want to pull a theme I like that I can rely on someone else to keep up.</li>
<li>Once it gets going, I want template changes to be easy.</li>
<li>It should be as easy as Jekyll, so I need to be able to build it using GitHub Actions, where I can just commit a template change or Markdown file and away it goes. If I can't figure this out than fk it, just use Jekyll.</li>
<li>I require it to be used by a significant percent of my professional peers so I can get easy answers when something goes wrong.</li>
<li>I want source maps. This is a dev log site which means whatever I do with it should be easy for other developers to read.</li>
</ol>
<ul class="task-list">
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Also <a href="https://www.npmjs.com/package/@quasibit/eleventy-plugin-sitemap" target="_blank">the sitemap plugin</a> looks cool. Should grab that later.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> So does the <a href="https://www.npmjs.com/package/eleventy-plugin-reading-time" target="_blank">reading time one</a>.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Also <a href="https://github.com/jdsteinbach/eleventy-plugin-toc/" target="_blank">this TOC plugin</a> mby?</p>
</li>
<li class="task-list-item">
<p data-wordfix="true"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Use <a href="https://www.11ty.dev/docs/data-deep-merge/" target="_blank">Data Deep Merge</a> in this blog.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Decide if I want to render the CSS fancier than just a base file and do per-template splitting.</p>
</li>
</ul>
<s>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Can I use the template inside of dinky that already exists instead of copy/pasting it?</li>
</ul>
</s>
<s>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Is there a way to have permalinks to posts contain metadata without organizing them into subfolders?</li>
</ul>
</s>
<ul class="task-list">
<li class="task-list-item">
<p data-wordfix="true"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> How do I cachebreak files on the basis of new build events? Datetime? <code>site.github.build_revision</code> is <a href="https://github.com/jekyll/github-metadata/blob/master/docs/site.github.md" target="_blank">how Jekyll accomplishes this</a>, but is there a way to push <a href="https://docs.github.com/en/actions/reference/context-and-expression-syntax-for-github-actions#github-context" target="_blank">that</a> <a href="https://stackoverflow.com/questions/54310050/how-to-version-build-artifacts-using-github-actions" target="_blank">into the build process</a> for Eleventy?</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Make link text look less shitty. It looks like it is a whole, lighter, font.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Code blocks do not have good syntax highlighting. I want good syntax highlighting.</p>
</li>
<li class="task-list-item">
<p data-wordfix="true"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Build a Markdown-it plugin to take my typing shortcuts <code>[prob, b/c, ...?]</code> and expand them on build.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> See if we can start Markdown's interpretation of H tags to <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/Heading_Elements#multiple_h1" target="_blank">start at 2, since H1</a> is always pulled from the page title metadata. If it isn't easy, I just have to change my pattern of writing in the MD documents.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Should I <a href="https://www.madebymike.com.au/writing/11ty-filters-data-shortcodes/" target="_blank">explore some shortcodes</a>?</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Order projects listing by last posted blog in that project</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Limit the output of home page post lists to a specific number of posts</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Show the latest post below the site intro on the homepage.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Tags pages with Pagination</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Posts should be able to support a preview header image that can also be shown on post lists.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Create a Markdown-It plugin that reads the project's repo URL off the folder data file and renders commit messages with <a href="https://stackoverflow.com/questions/15919635/on-github-api-what-is-the-best-way-to-get-the-last-commit-message-associated-w" target="_blank">links to the referenced commit</a>. (Is this even possible?) (Is there a way to do it with eleventy instead?)</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Create Next Day/Previous Day links on each post / Next/Previous post on post templates from projects</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Tags should be in the sidebar of articles and link to tag pages</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Create a skiplink for the todo section (or would this be better served with the ToC plugin?) - Yes it would be!</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Add a Things I Learned section to the project pages that are the things I learned from that specific project.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Add a technical reading log to the homepage</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/:empty" target="_blank">Hide</a> empty sections.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Add byline to post pages</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Have table of contents attach to sidebar bottom on mobile</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Support dark mode</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Social Icons</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> SEO/Social/JSON-LD HEAD data</p>
</li>
</ul>
<h2 id="day-36" tabindex="-1">Day 36</h2>
<p>I'm realizing that if I want to pull the repo in for the Markdown It shortcode. How do I get the page-level data?</p>
<p>Ok, so I'm checking in the callback passed into <code>md.core.ruler.after</code> and I'm not seeing anything. Not even any <code>process.env</code>. Not a good sign. I'm going to try to <code>console.log</code> in a few places to see if I can see if any of them give me the right rights.</p>
<p>Ok, it looks like <code>ruler.after</code> isn't the right place to be. I've gone into <code>rerender.rules</code> instead.</p>
<p>Cool to see all my rules by logging them!</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-36/#code-skip-hello-day-36-4" id="skip-to-code-skip-hello-day-36-4" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript"><span class="token punctuation">[</span><br />  <span class="token string">'code_inline'</span><span class="token punctuation">,</span><br />  <span class="token string">'code_block'</span><span class="token punctuation">,</span><br />  <span class="token string">'fence'</span><span class="token punctuation">,</span><br />  <span class="token string">'image'</span><span class="token punctuation">,</span><br />  <span class="token string">'hardbreak'</span><span class="token punctuation">,</span><br />  <span class="token string">'softbreak'</span><span class="token punctuation">,</span><br />  <span class="token string">'text'</span><span class="token punctuation">,</span><br />  <span class="token string">'html_block'</span><span class="token punctuation">,</span><br />  <span class="token string">'html_inline'</span><br /><span class="token punctuation">]</span></code></pre>
<p id="code-skip-hello-day-36-4">Now I've got a small plugin</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-36/#code-skip-hello-day-36-3" id="skip-to-code-skip-hello-day-36-3" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript">		<span class="token punctuation">.</span><span class="token function">use</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">md</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />			console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'rules'</span><span class="token punctuation">,</span> Object<span class="token punctuation">.</span><span class="token function">keys</span><span class="token punctuation">(</span>md<span class="token punctuation">.</span>renderer<span class="token punctuation">.</span>rules<span class="token punctuation">)</span><span class="token punctuation">)</span><br />			<span class="token keyword">const</span> defaultRender <span class="token operator">=</span> md<span class="token punctuation">.</span>renderer<span class="token punctuation">.</span>rules<span class="token punctuation">.</span>code_inline<span class="token punctuation">;</span><br />			md<span class="token punctuation">.</span>renderer<span class="token punctuation">.</span>rules<span class="token punctuation">.</span><span class="token function-variable function">code_inline</span> <span class="token operator">=</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">tokens<span class="token punctuation">,</span> idx<span class="token punctuation">,</span> options<span class="token punctuation">,</span> env<span class="token punctuation">,</span> self</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />				console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'env '</span><span class="token punctuation">,</span> Object<span class="token punctuation">.</span><span class="token function">keys</span><span class="token punctuation">(</span>env<span class="token punctuation">)</span><span class="token punctuation">,</span> env<span class="token punctuation">.</span>repo<span class="token punctuation">)</span><br />				<span class="token comment">// pass token to default renderer.</span><br />				<span class="token keyword">return</span> <span class="token function">defaultRender</span><span class="token punctuation">(</span>tokens<span class="token punctuation">,</span> idx<span class="token punctuation">,</span> options<span class="token punctuation">,</span> env<span class="token punctuation">,</span> self<span class="token punctuation">)</span><span class="token punctuation">;</span><br />			<span class="token punctuation">}</span><br />		<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p data-wordfix="true" id="code-skip-hello-day-36-3">Perfect! I can see the global vars coming from <a href="https://www.11ty.dev/docs/data-cascade/" target="_blank">the data cascade</a> inside <code>env</code> as passed to the function.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-36/#code-skip-hello-day-36-2" id="skip-to-code-skip-hello-day-36-2" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript"><span class="token punctuation">[</span><br />  <span class="token string">'defaults'</span><span class="token punctuation">,</span>      <span class="token string">'description'</span><span class="token punctuation">,</span><br />  <span class="token string">'layout'</span><span class="token punctuation">,</span>        <span class="token string">'projects'</span><span class="token punctuation">,</span><br />  <span class="token string">'site'</span><span class="token punctuation">,</span>          <span class="token string">'pkg'</span><span class="token punctuation">,</span><br />  <span class="token string">'tags'</span><span class="token punctuation">,</span>          <span class="token string">'date'</span><span class="token punctuation">,</span><br />  <span class="token string">'project'</span><span class="token punctuation">,</span>       <span class="token string">'repo'</span><span class="token punctuation">,</span><br />  <span class="token string">'featuredImage'</span><span class="token punctuation">,</span> <span class="token string">'title'</span><span class="token punctuation">,</span><br />  <span class="token string">'subtitle'</span><span class="token punctuation">,</span>      <span class="token string">'page'</span><span class="token punctuation">,</span><br />  <span class="token string">'collections'</span><br /><span class="token punctuation">]</span></code></pre>
<p id="code-skip-hello-day-36-2">Ok, a little more experimentation and it looks like I can definitely use this approach to capture my commit messages in my posts! Function now looks like this and I am seeing the git commit messages I write to mark my commits in blog posts!</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-36/#code-skip-hello-day-36-1" id="skip-to-code-skip-hello-day-36-1" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript"><span class="token punctuation">.</span><span class="token function">use</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">md</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />			console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'rules'</span><span class="token punctuation">,</span> Object<span class="token punctuation">.</span><span class="token function">keys</span><span class="token punctuation">(</span>md<span class="token punctuation">.</span>renderer<span class="token punctuation">.</span>rules<span class="token punctuation">)</span><span class="token punctuation">)</span><br />			<span class="token keyword">const</span> 	defaultRender <span class="token operator">=</span> md<span class="token punctuation">.</span>renderer<span class="token punctuation">.</span>rules<span class="token punctuation">.</span>code_inline<span class="token punctuation">,</span><br />					testPattern <span class="token operator">=</span> <span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">git commit \-am \"</span><span class="token regex-delimiter">/</span><span class="token regex-flags">i</span></span><br /><br />			md<span class="token punctuation">.</span>renderer<span class="token punctuation">.</span>rules<span class="token punctuation">.</span><span class="token function-variable function">code_inline</span> <span class="token operator">=</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">tokens<span class="token punctuation">,</span> idx<span class="token punctuation">,</span> options<span class="token punctuation">,</span> env<span class="token punctuation">,</span> self</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />				console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'env '</span><span class="token punctuation">,</span> Object<span class="token punctuation">.</span><span class="token function">keys</span><span class="token punctuation">(</span>env<span class="token punctuation">)</span><span class="token punctuation">,</span> env<span class="token punctuation">.</span>repo<span class="token punctuation">)</span><br />				<span class="token keyword">var</span> token <span class="token operator">=</span> tokens<span class="token punctuation">[</span>idx<span class="token punctuation">]</span><span class="token punctuation">,</span><br />				content <span class="token operator">=</span> token<span class="token punctuation">.</span>content<span class="token punctuation">;</span><br />				<span class="token keyword">if</span> <span class="token punctuation">(</span>testPattern<span class="token punctuation">.</span><span class="token function">test</span><span class="token punctuation">(</span>content<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />					console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'git content:'</span><span class="token punctuation">,</span> content<span class="token punctuation">)</span><br />				<span class="token punctuation">}</span><br />				<span class="token comment">// pass token to default renderer.</span><br />				<span class="token keyword">return</span> <span class="token function">defaultRender</span><span class="token punctuation">(</span>tokens<span class="token punctuation">,</span> idx<span class="token punctuation">,</span> options<span class="token punctuation">,</span> env<span class="token punctuation">,</span> self<span class="token punctuation">)</span><span class="token punctuation">;</span><br />			<span class="token punctuation">}</span><br />		<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p id="code-skip-hello-day-36-1">Progress! Gotta end now and go to sleep, but even though I could fit in a little work today, it went a long way!</p>
<p><a target="_blank" href="https://github.com/AramZS/devblog/commit/016d8cf0e549e254fa92a1e373890429b821bbfd" class="git-commit-link"><code>git commit -am &quot;Day 36, quick but useful stuff&quot;</code></a></p>
]]></content:encoded>
	</item>
	
	<item>
		<title>Part 35: GitHub's API - How Does It Work?</title>
		<link>https://fightwithtools.dev/posts/projects/devblog/hello-day-35/?source=rss</link>
		<pubDate>Sat, 13 Nov 2021 02:59:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/projects/devblog/hello-day-35/</guid>
		<description>More devblog</description>
		<content:encoded><![CDATA[<h2 id="project-scope-and-todos" tabindex="-1">Project Scope and ToDos</h2>
<ol>
<li>Static Site Generator that can build the blog and let me host it on Github Pages</li>
<li>I want to write posts in Markdown because I'm lazy, it's easy, and it is how I take notes now.</li>
<li>I don't want to spend a ton of time doing design work. I'm doing complicated designs for other projects, so I want to pull a theme I like that I can rely on someone else to keep up.</li>
<li>Once it gets going, I want template changes to be easy.</li>
<li>It should be as easy as Jekyll, so I need to be able to build it using GitHub Actions, where I can just commit a template change or Markdown file and away it goes. If I can't figure this out than fk it, just use Jekyll.</li>
<li>I require it to be used by a significant percent of my professional peers so I can get easy answers when something goes wrong.</li>
<li>I want source maps. This is a dev log site which means whatever I do with it should be easy for other developers to read.</li>
</ol>
<ul class="task-list">
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Also <a href="https://www.npmjs.com/package/@quasibit/eleventy-plugin-sitemap" target="_blank">the sitemap plugin</a> looks cool. Should grab that later.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> So does the <a href="https://www.npmjs.com/package/eleventy-plugin-reading-time" target="_blank">reading time one</a>.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Also <a href="https://github.com/jdsteinbach/eleventy-plugin-toc/" target="_blank">this TOC plugin</a> mby?</p>
</li>
<li class="task-list-item">
<p data-wordfix="true"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Use <a href="https://www.11ty.dev/docs/data-deep-merge/" target="_blank">Data Deep Merge</a> in this blog.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Decide if I want to render the CSS fancier than just a base file and do per-template splitting.</p>
</li>
</ul>
<s>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Can I use the template inside of dinky that already exists instead of copy/pasting it?</li>
</ul>
</s>
<s>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Is there a way to have permalinks to posts contain metadata without organizing them into subfolders?</li>
</ul>
</s>
<ul class="task-list">
<li class="task-list-item">
<p data-wordfix="true"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> How do I cachebreak files on the basis of new build events? Datetime? <code>site.github.build_revision</code> is <a href="https://github.com/jekyll/github-metadata/blob/master/docs/site.github.md" target="_blank">how Jekyll accomplishes this</a>, but is there a way to push <a href="https://docs.github.com/en/actions/reference/context-and-expression-syntax-for-github-actions#github-context" target="_blank">that</a> <a href="https://stackoverflow.com/questions/54310050/how-to-version-build-artifacts-using-github-actions" target="_blank">into the build process</a> for Eleventy?</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Make link text look less shitty. It looks like it is a whole, lighter, font.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Code blocks do not have good syntax highlighting. I want good syntax highlighting.</p>
</li>
<li class="task-list-item">
<p data-wordfix="true"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Build a Markdown-it plugin to take my typing shortcuts <code>[prob, b/c, ...?]</code> and expand them on build.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> See if we can start Markdown's interpretation of H tags to <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/Heading_Elements#multiple_h1" target="_blank">start at 2, since H1</a> is always pulled from the page title metadata. If it isn't easy, I just have to change my pattern of writing in the MD documents.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Should I <a href="https://www.madebymike.com.au/writing/11ty-filters-data-shortcodes/" target="_blank">explore some shortcodes</a>?</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Order projects listing by last posted blog in that project</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Limit the output of home page post lists to a specific number of posts</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Show the latest post below the site intro on the homepage.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Tags pages with Pagination</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Posts should be able to support a preview header image that can also be shown on post lists.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Create a Markdown-It plugin that reads the project's repo URL off the folder data file and renders commit messages with <a href="https://stackoverflow.com/questions/15919635/on-github-api-what-is-the-best-way-to-get-the-last-commit-message-associated-w" target="_blank">links to the referenced commit</a>. (Is this even possible?) (Is there a way to do it with eleventy instead?)</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Create Next Day/Previous Day links on each post / Next/Previous post on post templates from projects</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Tags should be in the sidebar of articles and link to tag pages</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Create a skiplink for the todo section (or would this be better served with the ToC plugin?) - Yes it would be!</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Add a Things I Learned section to the project pages that are the things I learned from that specific project.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Add a technical reading log to the homepage</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/:empty" target="_blank">Hide</a> empty sections.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Add byline to post pages</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Have table of contents attach to sidebar bottom on mobile</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Support dark mode</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Social Icons</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> SEO/Social/JSON-LD HEAD data</p>
</li>
</ul>
<h2 id="day-35" tabindex="-1">Day 35</h2>
<p>Ok, I got my first plugin for Markdown-It working! This is great! Let's try the GitHub plugin</p>
<p>First let's <a href="https://docs.github.com/rest" target="_blank">try some API requests in the terminal</a>.</p>
<p>Looks like there <a href="https://docs.github.com/en/rest/reference/search#search-commits" target="_blank">is an endpoint for searching commits</a>.</p>
<p>Ok, so a search of <code>https --auth AramZS:[token] https://api.github.com/search/commits?q=repo:AramZS/devblog+day+32</code> results in:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-35/#code-skip-hello-day-35-1" id="skip-to-code-skip-hello-day-35-1" class="skip-link">Skip code block ▼</a></p>
<pre class="language-json"><code class="language-json"><br /><span class="token punctuation">{</span><br />    <span class="token property">"incomplete_results"</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span><br />    <span class="token property">"items"</span><span class="token operator">:</span> <span class="token punctuation">[</span><br />        <span class="token punctuation">{</span><br />            <span class="token property">"author"</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />                <span class="token property">"avatar_url"</span><span class="token operator">:</span> <span class="token string">"https://avatars.githubusercontent.com/u/748069?v=4"</span><span class="token punctuation">,</span><br />                <span class="token property">"events_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/users/AramZS/events{/privacy}"</span><span class="token punctuation">,</span><br />                <span class="token property">"followers_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/users/AramZS/followers"</span><span class="token punctuation">,</span><br />                <span class="token property">"following_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/users/AramZS/following{/other_user}"</span><span class="token punctuation">,</span><br />                <span class="token property">"gists_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/users/AramZS/gists{/gist_id}"</span><span class="token punctuation">,</span><br />                <span class="token property">"gravatar_id"</span><span class="token operator">:</span> <span class="token string">""</span><span class="token punctuation">,</span><br />                <span class="token property">"html_url"</span><span class="token operator">:</span> <span class="token string">"https://github.com/AramZS"</span><span class="token punctuation">,</span><br />                <span class="token property">"id"</span><span class="token operator">:</span> <span class="token number">748069</span><span class="token punctuation">,</span><br />                <span class="token property">"login"</span><span class="token operator">:</span> <span class="token string">"AramZS"</span><span class="token punctuation">,</span><br />                <span class="token property">"node_id"</span><span class="token operator">:</span> <span class="token string">"MDQ6VXNlcjc0ODA2OQ=="</span><span class="token punctuation">,</span><br />                <span class="token property">"organizations_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/users/AramZS/orgs"</span><span class="token punctuation">,</span><br />                <span class="token property">"received_events_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/users/AramZS/received_events"</span><span class="token punctuation">,</span><br />                <span class="token property">"repos_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/users/AramZS/repos"</span><span class="token punctuation">,</span><br />                <span class="token property">"site_admin"</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span><br />                <span class="token property">"starred_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/users/AramZS/starred{/owner}{/repo}"</span><span class="token punctuation">,</span><br />                <span class="token property">"subscriptions_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/users/AramZS/subscriptions"</span><span class="token punctuation">,</span><br />                <span class="token property">"type"</span><span class="token operator">:</span> <span class="token string">"User"</span><span class="token punctuation">,</span><br />                <span class="token property">"url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/users/AramZS"</span><br />            <span class="token punctuation">}</span><span class="token punctuation">,</span><br />            <span class="token property">"comments_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/repos/AramZS/devblog/commits/f738429d2fd507f2076240c68f6704b645cb468d/comments"</span><span class="token punctuation">,</span><br />            <span class="token property">"commit"</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />                <span class="token property">"author"</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />                    <span class="token property">"date"</span><span class="token operator">:</span> <span class="token string">"2021-11-21T23:19:18.000-05:00"</span><span class="token punctuation">,</span><br />                    <span class="token property">"email"</span><span class="token operator">:</span> <span class="token string">"Aram.Zucker-Scharff@washpost.com"</span><span class="token punctuation">,</span><br />                    <span class="token property">"name"</span><span class="token operator">:</span> <span class="token string">"Aram Zucker-Scharff"</span><br />                <span class="token punctuation">}</span><span class="token punctuation">,</span><br />                <span class="token property">"comment_count"</span><span class="token operator">:</span> <span class="token number">0</span><span class="token punctuation">,</span><br />                <span class="token property">"committer"</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />                    <span class="token property">"date"</span><span class="token operator">:</span> <span class="token string">"2021-11-21T23:19:18.000-05:00"</span><span class="token punctuation">,</span><br />                    <span class="token property">"email"</span><span class="token operator">:</span> <span class="token string">"noreply@github.com"</span><span class="token punctuation">,</span><br />                    <span class="token property">"name"</span><span class="token operator">:</span> <span class="token string">"GitHub"</span><br />                <span class="token punctuation">}</span><span class="token punctuation">,</span><br />                <span class="token property">"message"</span><span class="token operator">:</span> <span class="token string">"Merge pull request #6 from AramZS/day-32\n\nDay 32"</span><span class="token punctuation">,</span><br />                <span class="token property">"tree"</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />                    <span class="token property">"sha"</span><span class="token operator">:</span> <span class="token string">"9ddafc9982b34cbab840ba81f0139c21eb43b5aa"</span><span class="token punctuation">,</span><br />                    <span class="token property">"url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/repos/AramZS/devblog/git/trees/9ddafc9982b34cbab840ba81f0139c21eb43b5aa"</span><br />                <span class="token punctuation">}</span><span class="token punctuation">,</span><br />                <span class="token property">"url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/repos/AramZS/devblog/git/commits/f738429d2fd507f2076240c68f6704b645cb468d"</span><br />            <span class="token punctuation">}</span><span class="token punctuation">,</span><br />            <span class="token property">"committer"</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />                <span class="token property">"avatar_url"</span><span class="token operator">:</span> <span class="token string">"https://avatars.githubusercontent.com/u/19864447?v=4"</span><span class="token punctuation">,</span><br />                <span class="token property">"events_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/users/web-flow/events{/privacy}"</span><span class="token punctuation">,</span><br />                <span class="token property">"followers_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/users/web-flow/followers"</span><span class="token punctuation">,</span><br />                <span class="token property">"following_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/users/web-flow/following{/other_user}"</span><span class="token punctuation">,</span><br />                <span class="token property">"gists_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/users/web-flow/gists{/gist_id}"</span><span class="token punctuation">,</span><br />                <span class="token property">"gravatar_id"</span><span class="token operator">:</span> <span class="token string">""</span><span class="token punctuation">,</span><br />                <span class="token property">"html_url"</span><span class="token operator">:</span> <span class="token string">"https://github.com/web-flow"</span><span class="token punctuation">,</span><br />                <span class="token property">"id"</span><span class="token operator">:</span> <span class="token number">19864447</span><span class="token punctuation">,</span><br />                <span class="token property">"login"</span><span class="token operator">:</span> <span class="token string">"web-flow"</span><span class="token punctuation">,</span><br />                <span class="token property">"node_id"</span><span class="token operator">:</span> <span class="token string">"MDQ6VXNlcjE5ODY0NDQ3"</span><span class="token punctuation">,</span><br />                <span class="token property">"organizations_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/users/web-flow/orgs"</span><span class="token punctuation">,</span><br />                <span class="token property">"received_events_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/users/web-flow/received_events"</span><span class="token punctuation">,</span><br />                <span class="token property">"repos_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/users/web-flow/repos"</span><span class="token punctuation">,</span><br />                <span class="token property">"site_admin"</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span><br />                <span class="token property">"starred_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/users/web-flow/starred{/owner}{/repo}"</span><span class="token punctuation">,</span><br />                <span class="token property">"subscriptions_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/users/web-flow/subscriptions"</span><span class="token punctuation">,</span><br />                <span class="token property">"type"</span><span class="token operator">:</span> <span class="token string">"User"</span><span class="token punctuation">,</span><br />                <span class="token property">"url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/users/web-flow"</span><br />            <span class="token punctuation">}</span><span class="token punctuation">,</span><br />            <span class="token property">"html_url"</span><span class="token operator">:</span> <span class="token string">"https://github.com/AramZS/devblog/commit/f738429d2fd507f2076240c68f6704b645cb468d"</span><span class="token punctuation">,</span><br />            <span class="token property">"node_id"</span><span class="token operator">:</span> <span class="token string">"MDY6Q29tbWl0Mzc2NzA2MzI2OmY3Mzg0MjlkMmZkNTA3ZjIwNzYyNDBjNjhmNjcwNGI2NDVjYjQ2OGQ="</span><span class="token punctuation">,</span><br />            <span class="token property">"parents"</span><span class="token operator">:</span> <span class="token punctuation">[</span><br />                <span class="token punctuation">{</span><br />                    <span class="token property">"html_url"</span><span class="token operator">:</span> <span class="token string">"https://github.com/AramZS/devblog/commit/b0f64c92e21f230ee13692a99e347f0eed5678da"</span><span class="token punctuation">,</span><br />                    <span class="token property">"sha"</span><span class="token operator">:</span> <span class="token string">"b0f64c92e21f230ee13692a99e347f0eed5678da"</span><span class="token punctuation">,</span><br />                    <span class="token property">"url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/repos/AramZS/devblog/commits/b0f64c92e21f230ee13692a99e347f0eed5678da"</span><br />                <span class="token punctuation">}</span><span class="token punctuation">,</span><br />                <span class="token punctuation">{</span><br />                    <span class="token property">"html_url"</span><span class="token operator">:</span> <span class="token string">"https://github.com/AramZS/devblog/commit/cf3dc12d4183c10b51426d9bd45867ea37854481"</span><span class="token punctuation">,</span><br />                    <span class="token property">"sha"</span><span class="token operator">:</span> <span class="token string">"cf3dc12d4183c10b51426d9bd45867ea37854481"</span><span class="token punctuation">,</span><br />                    <span class="token property">"url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/repos/AramZS/devblog/commits/cf3dc12d4183c10b51426d9bd45867ea37854481"</span><br />                <span class="token punctuation">}</span><br />            <span class="token punctuation">]</span><span class="token punctuation">,</span><br />            <span class="token property">"repository"</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />                <span class="token property">"archive_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/repos/AramZS/devblog/{archive_format}{/ref}"</span><span class="token punctuation">,</span><br />                <span class="token property">"assignees_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/repos/AramZS/devblog/assignees{/user}"</span><span class="token punctuation">,</span><br />                <span class="token property">"blobs_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/repos/AramZS/devblog/git/blobs{/sha}"</span><span class="token punctuation">,</span><br />                <span class="token property">"branches_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/repos/AramZS/devblog/branches{/branch}"</span><span class="token punctuation">,</span><br />                <span class="token property">"collaborators_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/repos/AramZS/devblog/collaborators{/collaborator}"</span><span class="token punctuation">,</span><br />                <span class="token property">"comments_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/repos/AramZS/devblog/comments{/number}"</span><span class="token punctuation">,</span><br />                <span class="token property">"commits_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/repos/AramZS/devblog/commits{/sha}"</span><span class="token punctuation">,</span><br />                <span class="token property">"compare_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/repos/AramZS/devblog/compare/{base}...{head}"</span><span class="token punctuation">,</span><br />                <span class="token property">"contents_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/repos/AramZS/devblog/contents/{+path}"</span><span class="token punctuation">,</span><br />                <span class="token property">"contributors_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/repos/AramZS/devblog/contributors"</span><span class="token punctuation">,</span><br />                <span class="token property">"deployments_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/repos/AramZS/devblog/deployments"</span><span class="token punctuation">,</span><br />                <span class="token property">"description"</span><span class="token operator">:</span> <span class="token null keyword">null</span><span class="token punctuation">,</span><br />                <span class="token property">"downloads_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/repos/AramZS/devblog/downloads"</span><span class="token punctuation">,</span><br />                <span class="token property">"events_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/repos/AramZS/devblog/events"</span><span class="token punctuation">,</span><br />                <span class="token property">"fork"</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span><br />                <span class="token property">"forks_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/repos/AramZS/devblog/forks"</span><span class="token punctuation">,</span><br />                <span class="token property">"full_name"</span><span class="token operator">:</span> <span class="token string">"AramZS/devblog"</span><span class="token punctuation">,</span><br />                <span class="token property">"git_commits_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/repos/AramZS/devblog/git/commits{/sha}"</span><span class="token punctuation">,</span><br />                <span class="token property">"git_refs_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/repos/AramZS/devblog/git/refs{/sha}"</span><span class="token punctuation">,</span><br />                <span class="token property">"git_tags_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/repos/AramZS/devblog/git/tags{/sha}"</span><span class="token punctuation">,</span><br />                <span class="token property">"hooks_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/repos/AramZS/devblog/hooks"</span><span class="token punctuation">,</span><br />                <span class="token property">"html_url"</span><span class="token operator">:</span> <span class="token string">"https://github.com/AramZS/devblog"</span><span class="token punctuation">,</span><br />                <span class="token property">"id"</span><span class="token operator">:</span> <span class="token number">376706326</span><span class="token punctuation">,</span><br />                <span class="token property">"issue_comment_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/repos/AramZS/devblog/issues/comments{/number}"</span><span class="token punctuation">,</span><br />                <span class="token property">"issue_events_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/repos/AramZS/devblog/issues/events{/number}"</span><span class="token punctuation">,</span><br />                <span class="token property">"issues_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/repos/AramZS/devblog/issues{/number}"</span><span class="token punctuation">,</span><br />                <span class="token property">"keys_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/repos/AramZS/devblog/keys{/key_id}"</span><span class="token punctuation">,</span><br />                <span class="token property">"labels_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/repos/AramZS/devblog/labels{/name}"</span><span class="token punctuation">,</span><br />                <span class="token property">"languages_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/repos/AramZS/devblog/languages"</span><span class="token punctuation">,</span><br />                <span class="token property">"merges_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/repos/AramZS/devblog/merges"</span><span class="token punctuation">,</span><br />                <span class="token property">"milestones_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/repos/AramZS/devblog/milestones{/number}"</span><span class="token punctuation">,</span><br />                <span class="token property">"name"</span><span class="token operator">:</span> <span class="token string">"devblog"</span><span class="token punctuation">,</span><br />                <span class="token property">"node_id"</span><span class="token operator">:</span> <span class="token string">"MDEwOlJlcG9zaXRvcnkzNzY3MDYzMjY="</span><span class="token punctuation">,</span><br />                <span class="token property">"notifications_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/repos/AramZS/devblog/notifications{?since,all,participating}"</span><span class="token punctuation">,</span><br />                <span class="token property">"owner"</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />                    <span class="token property">"avatar_url"</span><span class="token operator">:</span> <span class="token string">"https://avatars.githubusercontent.com/u/748069?v=4"</span><span class="token punctuation">,</span><br />                    <span class="token property">"events_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/users/AramZS/events{/privacy}"</span><span class="token punctuation">,</span><br />                    <span class="token property">"followers_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/users/AramZS/followers"</span><span class="token punctuation">,</span><br />                    <span class="token property">"following_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/users/AramZS/following{/other_user}"</span><span class="token punctuation">,</span><br />                    <span class="token property">"gists_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/users/AramZS/gists{/gist_id}"</span><span class="token punctuation">,</span><br />                    <span class="token property">"gravatar_id"</span><span class="token operator">:</span> <span class="token string">""</span><span class="token punctuation">,</span><br />                    <span class="token property">"html_url"</span><span class="token operator">:</span> <span class="token string">"https://github.com/AramZS"</span><span class="token punctuation">,</span><br />                    <span class="token property">"id"</span><span class="token operator">:</span> <span class="token number">748069</span><span class="token punctuation">,</span><br />                    <span class="token property">"login"</span><span class="token operator">:</span> <span class="token string">"AramZS"</span><span class="token punctuation">,</span><br />                    <span class="token property">"node_id"</span><span class="token operator">:</span> <span class="token string">"MDQ6VXNlcjc0ODA2OQ=="</span><span class="token punctuation">,</span><br />                    <span class="token property">"organizations_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/users/AramZS/orgs"</span><span class="token punctuation">,</span><br />                    <span class="token property">"received_events_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/users/AramZS/received_events"</span><span class="token punctuation">,</span><br />                    <span class="token property">"repos_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/users/AramZS/repos"</span><span class="token punctuation">,</span><br />                    <span class="token property">"site_admin"</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span><br />                    <span class="token property">"starred_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/users/AramZS/starred{/owner}{/repo}"</span><span class="token punctuation">,</span><br />                    <span class="token property">"subscriptions_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/users/AramZS/subscriptions"</span><span class="token punctuation">,</span><br />                    <span class="token property">"type"</span><span class="token operator">:</span> <span class="token string">"User"</span><span class="token punctuation">,</span><br />                    <span class="token property">"url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/users/AramZS"</span><br />                <span class="token punctuation">}</span><span class="token punctuation">,</span><br />                <span class="token property">"private"</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span><br />                <span class="token property">"pulls_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/repos/AramZS/devblog/pulls{/number}"</span><span class="token punctuation">,</span><br />                <span class="token property">"releases_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/repos/AramZS/devblog/releases{/id}"</span><span class="token punctuation">,</span><br />                <span class="token property">"stargazers_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/repos/AramZS/devblog/stargazers"</span><span class="token punctuation">,</span><br />                <span class="token property">"statuses_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/repos/AramZS/devblog/statuses/{sha}"</span><span class="token punctuation">,</span><br />                <span class="token property">"subscribers_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/repos/AramZS/devblog/subscribers"</span><span class="token punctuation">,</span><br />                <span class="token property">"subscription_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/repos/AramZS/devblog/subscription"</span><span class="token punctuation">,</span><br />                <span class="token property">"tags_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/repos/AramZS/devblog/tags"</span><span class="token punctuation">,</span><br />                <span class="token property">"teams_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/repos/AramZS/devblog/teams"</span><span class="token punctuation">,</span><br />                <span class="token property">"trees_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/repos/AramZS/devblog/git/trees{/sha}"</span><span class="token punctuation">,</span><br />                <span class="token property">"url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/repos/AramZS/devblog"</span><br />            <span class="token punctuation">}</span><span class="token punctuation">,</span><br />            <span class="token property">"score"</span><span class="token operator">:</span> <span class="token number">1.0</span><span class="token punctuation">,</span><br />            <span class="token property">"sha"</span><span class="token operator">:</span> <span class="token string">"f738429d2fd507f2076240c68f6704b645cb468d"</span><span class="token punctuation">,</span><br />            <span class="token property">"url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/repos/AramZS/devblog/commits/f738429d2fd507f2076240c68f6704b645cb468d"</span><br />        <span class="token punctuation">}</span><span class="token punctuation">,</span><br />        <span class="token punctuation">{</span><br />            <span class="token property">"author"</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />                <span class="token property">"avatar_url"</span><span class="token operator">:</span> <span class="token string">"https://avatars.githubusercontent.com/u/748069?v=4"</span><span class="token punctuation">,</span><br />                <span class="token property">"events_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/users/AramZS/events{/privacy}"</span><span class="token punctuation">,</span><br />                <span class="token property">"followers_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/users/AramZS/followers"</span><span class="token punctuation">,</span><br />                <span class="token property">"following_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/users/AramZS/following{/other_user}"</span><span class="token punctuation">,</span><br />                <span class="token property">"gists_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/users/AramZS/gists{/gist_id}"</span><span class="token punctuation">,</span><br />                <span class="token property">"gravatar_id"</span><span class="token operator">:</span> <span class="token string">""</span><span class="token punctuation">,</span><br />                <span class="token property">"html_url"</span><span class="token operator">:</span> <span class="token string">"https://github.com/AramZS"</span><span class="token punctuation">,</span><br />                <span class="token property">"id"</span><span class="token operator">:</span> <span class="token number">748069</span><span class="token punctuation">,</span><br />                <span class="token property">"login"</span><span class="token operator">:</span> <span class="token string">"AramZS"</span><span class="token punctuation">,</span><br />                <span class="token property">"node_id"</span><span class="token operator">:</span> <span class="token string">"MDQ6VXNlcjc0ODA2OQ=="</span><span class="token punctuation">,</span><br />                <span class="token property">"organizations_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/users/AramZS/orgs"</span><span class="token punctuation">,</span><br />                <span class="token property">"received_events_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/users/AramZS/received_events"</span><span class="token punctuation">,</span><br />                <span class="token property">"repos_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/users/AramZS/repos"</span><span class="token punctuation">,</span><br />                <span class="token property">"site_admin"</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span><br />                <span class="token property">"starred_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/users/AramZS/starred{/owner}{/repo}"</span><span class="token punctuation">,</span><br />                <span class="token property">"subscriptions_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/users/AramZS/subscriptions"</span><span class="token punctuation">,</span><br />                <span class="token property">"type"</span><span class="token operator">:</span> <span class="token string">"User"</span><span class="token punctuation">,</span><br />                <span class="token property">"url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/users/AramZS"</span><br />            <span class="token punctuation">}</span><span class="token punctuation">,</span><br />            <span class="token property">"comments_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/repos/AramZS/devblog/commits/b0db043f14feb1ef6f9f00cad61e2fedcac6e958/comments"</span><span class="token punctuation">,</span><br />            <span class="token property">"commit"</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />                <span class="token property">"author"</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />                    <span class="token property">"date"</span><span class="token operator">:</span> <span class="token string">"2021-11-21T23:17:06.000-05:00"</span><span class="token punctuation">,</span><br />                    <span class="token property">"email"</span><span class="token operator">:</span> <span class="token string">"aramzs@hacktext.com"</span><span class="token punctuation">,</span><br />                    <span class="token property">"name"</span><span class="token operator">:</span> <span class="token string">"Aram Zucker-Scharff"</span><br />                <span class="token punctuation">}</span><span class="token punctuation">,</span><br />                <span class="token property">"comment_count"</span><span class="token operator">:</span> <span class="token number">0</span><span class="token punctuation">,</span><br />                <span class="token property">"committer"</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />                    <span class="token property">"date"</span><span class="token operator">:</span> <span class="token string">"2021-11-21T23:17:06.000-05:00"</span><span class="token punctuation">,</span><br />                    <span class="token property">"email"</span><span class="token operator">:</span> <span class="token string">"aramzs@hacktext.com"</span><span class="token punctuation">,</span><br />                    <span class="token property">"name"</span><span class="token operator">:</span> <span class="token string">"Aram Zucker-Scharff"</span><br />                <span class="token punctuation">}</span><span class="token punctuation">,</span><br />                <span class="token property">"message"</span><span class="token operator">:</span> <span class="token string">"Finishing off day 32"</span><span class="token punctuation">,</span><br />                <span class="token property">"tree"</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />                    <span class="token property">"sha"</span><span class="token operator">:</span> <span class="token string">"b945b859b8c261d75bd02e107e1f0f3d3769aebe"</span><span class="token punctuation">,</span><br />                    <span class="token property">"url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/repos/AramZS/devblog/git/trees/b945b859b8c261d75bd02e107e1f0f3d3769aebe"</span><br />                <span class="token punctuation">}</span><span class="token punctuation">,</span><br />                <span class="token property">"url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/repos/AramZS/devblog/git/commits/b0db043f14feb1ef6f9f00cad61e2fedcac6e958"</span><br />            <span class="token punctuation">}</span><span class="token punctuation">,</span><br />            <span class="token property">"committer"</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />                <span class="token property">"avatar_url"</span><span class="token operator">:</span> <span class="token string">"https://avatars.githubusercontent.com/u/748069?v=4"</span><span class="token punctuation">,</span><br />                <span class="token property">"events_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/users/AramZS/events{/privacy}"</span><span class="token punctuation">,</span><br />                <span class="token property">"followers_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/users/AramZS/followers"</span><span class="token punctuation">,</span><br />                <span class="token property">"following_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/users/AramZS/following{/other_user}"</span><span class="token punctuation">,</span><br />                <span class="token property">"gists_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/users/AramZS/gists{/gist_id}"</span><span class="token punctuation">,</span><br />                <span class="token property">"gravatar_id"</span><span class="token operator">:</span> <span class="token string">""</span><span class="token punctuation">,</span><br />                <span class="token property">"html_url"</span><span class="token operator">:</span> <span class="token string">"https://github.com/AramZS"</span><span class="token punctuation">,</span><br />                <span class="token property">"id"</span><span class="token operator">:</span> <span class="token number">748069</span><span class="token punctuation">,</span><br />                <span class="token property">"login"</span><span class="token operator">:</span> <span class="token string">"AramZS"</span><span class="token punctuation">,</span><br />                <span class="token property">"node_id"</span><span class="token operator">:</span> <span class="token string">"MDQ6VXNlcjc0ODA2OQ=="</span><span class="token punctuation">,</span><br />                <span class="token property">"organizations_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/users/AramZS/orgs"</span><span class="token punctuation">,</span><br />                <span class="token property">"received_events_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/users/AramZS/received_events"</span><span class="token punctuation">,</span><br />                <span class="token property">"repos_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/users/AramZS/repos"</span><span class="token punctuation">,</span><br />                <span class="token property">"site_admin"</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span><br />                <span class="token property">"starred_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/users/AramZS/starred{/owner}{/repo}"</span><span class="token punctuation">,</span><br />                <span class="token property">"subscriptions_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/users/AramZS/subscriptions"</span><span class="token punctuation">,</span><br />                <span class="token property">"type"</span><span class="token operator">:</span> <span class="token string">"User"</span><span class="token punctuation">,</span><br />                <span class="token property">"url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/users/AramZS"</span><br />            <span class="token punctuation">}</span><span class="token punctuation">,</span><br />            <span class="token property">"html_url"</span><span class="token operator">:</span> <span class="token string">"https://github.com/AramZS/devblog/commit/b0db043f14feb1ef6f9f00cad61e2fedcac6e958"</span><span class="token punctuation">,</span><br />            <span class="token property">"node_id"</span><span class="token operator">:</span> <span class="token string">"MDY6Q29tbWl0Mzc2NzA2MzI2OmIwZGIwNDNmMTRmZWIxZWY2ZjlmMDBjYWQ2MWUyZmVkY2FjNmU5NTg="</span><span class="token punctuation">,</span><br />            <span class="token property">"parents"</span><span class="token operator">:</span> <span class="token punctuation">[</span><br />                <span class="token punctuation">{</span><br />                    <span class="token property">"html_url"</span><span class="token operator">:</span> <span class="token string">"https://github.com/AramZS/devblog/commit/ae757146534498b1eb1429564f38c310a8697440"</span><span class="token punctuation">,</span><br />                    <span class="token property">"sha"</span><span class="token operator">:</span> <span class="token string">"ae757146534498b1eb1429564f38c310a8697440"</span><span class="token punctuation">,</span><br />                    <span class="token property">"url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/repos/AramZS/devblog/commits/ae757146534498b1eb1429564f38c310a8697440"</span><br />                <span class="token punctuation">}</span><br />            <span class="token punctuation">]</span><span class="token punctuation">,</span><br />            <span class="token property">"repository"</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />                <span class="token property">"archive_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/repos/AramZS/devblog/{archive_format}{/ref}"</span><span class="token punctuation">,</span><br />                <span class="token property">"assignees_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/repos/AramZS/devblog/assignees{/user}"</span><span class="token punctuation">,</span><br />                <span class="token property">"blobs_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/repos/AramZS/devblog/git/blobs{/sha}"</span><span class="token punctuation">,</span><br />                <span class="token property">"branches_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/repos/AramZS/devblog/branches{/branch}"</span><span class="token punctuation">,</span><br />                <span class="token property">"collaborators_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/repos/AramZS/devblog/collaborators{/collaborator}"</span><span class="token punctuation">,</span><br />                <span class="token property">"comments_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/repos/AramZS/devblog/comments{/number}"</span><span class="token punctuation">,</span><br />                <span class="token property">"commits_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/repos/AramZS/devblog/commits{/sha}"</span><span class="token punctuation">,</span><br />                <span class="token property">"compare_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/repos/AramZS/devblog/compare/{base}...{head}"</span><span class="token punctuation">,</span><br />                <span class="token property">"contents_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/repos/AramZS/devblog/contents/{+path}"</span><span class="token punctuation">,</span><br />                <span class="token property">"contributors_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/repos/AramZS/devblog/contributors"</span><span class="token punctuation">,</span><br />                <span class="token property">"deployments_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/repos/AramZS/devblog/deployments"</span><span class="token punctuation">,</span><br />                <span class="token property">"description"</span><span class="token operator">:</span> <span class="token null keyword">null</span><span class="token punctuation">,</span><br />                <span class="token property">"downloads_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/repos/AramZS/devblog/downloads"</span><span class="token punctuation">,</span><br />                <span class="token property">"events_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/repos/AramZS/devblog/events"</span><span class="token punctuation">,</span><br />                <span class="token property">"fork"</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span><br />                <span class="token property">"forks_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/repos/AramZS/devblog/forks"</span><span class="token punctuation">,</span><br />                <span class="token property">"full_name"</span><span class="token operator">:</span> <span class="token string">"AramZS/devblog"</span><span class="token punctuation">,</span><br />                <span class="token property">"git_commits_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/repos/AramZS/devblog/git/commits{/sha}"</span><span class="token punctuation">,</span><br />                <span class="token property">"git_refs_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/repos/AramZS/devblog/git/refs{/sha}"</span><span class="token punctuation">,</span><br />                <span class="token property">"git_tags_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/repos/AramZS/devblog/git/tags{/sha}"</span><span class="token punctuation">,</span><br />                <span class="token property">"hooks_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/repos/AramZS/devblog/hooks"</span><span class="token punctuation">,</span><br />                <span class="token property">"html_url"</span><span class="token operator">:</span> <span class="token string">"https://github.com/AramZS/devblog"</span><span class="token punctuation">,</span><br />                <span class="token property">"id"</span><span class="token operator">:</span> <span class="token number">376706326</span><span class="token punctuation">,</span><br />                <span class="token property">"issue_comment_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/repos/AramZS/devblog/issues/comments{/number}"</span><span class="token punctuation">,</span><br />                <span class="token property">"issue_events_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/repos/AramZS/devblog/issues/events{/number}"</span><span class="token punctuation">,</span><br />                <span class="token property">"issues_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/repos/AramZS/devblog/issues{/number}"</span><span class="token punctuation">,</span><br />                <span class="token property">"keys_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/repos/AramZS/devblog/keys{/key_id}"</span><span class="token punctuation">,</span><br />                <span class="token property">"labels_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/repos/AramZS/devblog/labels{/name}"</span><span class="token punctuation">,</span><br />                <span class="token property">"languages_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/repos/AramZS/devblog/languages"</span><span class="token punctuation">,</span><br />                <span class="token property">"merges_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/repos/AramZS/devblog/merges"</span><span class="token punctuation">,</span><br />                <span class="token property">"milestones_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/repos/AramZS/devblog/milestones{/number}"</span><span class="token punctuation">,</span><br />                <span class="token property">"name"</span><span class="token operator">:</span> <span class="token string">"devblog"</span><span class="token punctuation">,</span><br />                <span class="token property">"node_id"</span><span class="token operator">:</span> <span class="token string">"MDEwOlJlcG9zaXRvcnkzNzY3MDYzMjY="</span><span class="token punctuation">,</span><br />                <span class="token property">"notifications_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/repos/AramZS/devblog/notifications{?since,all,participating}"</span><span class="token punctuation">,</span><br />                <span class="token property">"owner"</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />                    <span class="token property">"avatar_url"</span><span class="token operator">:</span> <span class="token string">"https://avatars.githubusercontent.com/u/748069?v=4"</span><span class="token punctuation">,</span><br />                    <span class="token property">"events_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/users/AramZS/events{/privacy}"</span><span class="token punctuation">,</span><br />                    <span class="token property">"followers_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/users/AramZS/followers"</span><span class="token punctuation">,</span><br />                    <span class="token property">"following_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/users/AramZS/following{/other_user}"</span><span class="token punctuation">,</span><br />                    <span class="token property">"gists_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/users/AramZS/gists{/gist_id}"</span><span class="token punctuation">,</span><br />                    <span class="token property">"gravatar_id"</span><span class="token operator">:</span> <span class="token string">""</span><span class="token punctuation">,</span><br />                    <span class="token property">"html_url"</span><span class="token operator">:</span> <span class="token string">"https://github.com/AramZS"</span><span class="token punctuation">,</span><br />                    <span class="token property">"id"</span><span class="token operator">:</span> <span class="token number">748069</span><span class="token punctuation">,</span><br />                    <span class="token property">"login"</span><span class="token operator">:</span> <span class="token string">"AramZS"</span><span class="token punctuation">,</span><br />                    <span class="token property">"node_id"</span><span class="token operator">:</span> <span class="token string">"MDQ6VXNlcjc0ODA2OQ=="</span><span class="token punctuation">,</span><br />                    <span class="token property">"organizations_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/users/AramZS/orgs"</span><span class="token punctuation">,</span><br />                    <span class="token property">"received_events_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/users/AramZS/received_events"</span><span class="token punctuation">,</span><br />                    <span class="token property">"repos_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/users/AramZS/repos"</span><span class="token punctuation">,</span><br />                    <span class="token property">"site_admin"</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span><br />                    <span class="token property">"starred_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/users/AramZS/starred{/owner}{/repo}"</span><span class="token punctuation">,</span><br />                    <span class="token property">"subscriptions_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/users/AramZS/subscriptions"</span><span class="token punctuation">,</span><br />                    <span class="token property">"type"</span><span class="token operator">:</span> <span class="token string">"User"</span><span class="token punctuation">,</span><br />                    <span class="token property">"url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/users/AramZS"</span><br />                <span class="token punctuation">}</span><span class="token punctuation">,</span><br />                <span class="token property">"private"</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span><br />                <span class="token property">"pulls_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/repos/AramZS/devblog/pulls{/number}"</span><span class="token punctuation">,</span><br />                <span class="token property">"releases_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/repos/AramZS/devblog/releases{/id}"</span><span class="token punctuation">,</span><br />                <span class="token property">"stargazers_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/repos/AramZS/devblog/stargazers"</span><span class="token punctuation">,</span><br />                <span class="token property">"statuses_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/repos/AramZS/devblog/statuses/{sha}"</span><span class="token punctuation">,</span><br />                <span class="token property">"subscribers_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/repos/AramZS/devblog/subscribers"</span><span class="token punctuation">,</span><br />                <span class="token property">"subscription_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/repos/AramZS/devblog/subscription"</span><span class="token punctuation">,</span><br />                <span class="token property">"tags_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/repos/AramZS/devblog/tags"</span><span class="token punctuation">,</span><br />                <span class="token property">"teams_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/repos/AramZS/devblog/teams"</span><span class="token punctuation">,</span><br />                <span class="token property">"trees_url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/repos/AramZS/devblog/git/trees{/sha}"</span><span class="token punctuation">,</span><br />                <span class="token property">"url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/repos/AramZS/devblog"</span><br />            <span class="token punctuation">}</span><span class="token punctuation">,</span><br />            <span class="token property">"score"</span><span class="token operator">:</span> <span class="token number">1.0</span><span class="token punctuation">,</span><br />            <span class="token property">"sha"</span><span class="token operator">:</span> <span class="token string">"b0db043f14feb1ef6f9f00cad61e2fedcac6e958"</span><span class="token punctuation">,</span><br />            <span class="token property">"url"</span><span class="token operator">:</span> <span class="token string">"https://api.github.com/repos/AramZS/devblog/commits/b0db043f14feb1ef6f9f00cad61e2fedcac6e958"</span><br />        <span class="token punctuation">}</span><span class="token punctuation">,</span><br />        ...<br />    <span class="token punctuation">]</span><span class="token punctuation">,</span><br />    <span class="token property">"total_count"</span><span class="token operator">:</span> <span class="token number">4</span><br /><span class="token punctuation">}</span></code></pre>
<p id="code-skip-hello-day-35-1">So I can even use a more precise search and get back more useful results, like: <code>https --auth AramZS:[token] https://api.github.com/search/commits?q=repo:AramZS/devblog+Finish+day+34</code> will give me back 2 results which is more useful.</p>
<p>I <a href="https://httpie.io/docs#examples" target="_blank">tried out Httpie on the CLI</a> for this and it worked pretty well.</p>
<p>Good to know how to do this raw, but it might be more useful to use the Github maintained <code>octokit/rest.js</code> tool? Looks like <a href="https://octokit.github.io/rest.js/v18#search-commits" target="_blank">it supports this type of query</a>. There are <a href="https://github.com/pksunkara/octonode" target="_blank">a few</a> <a href="https://github.com/github-tools/github" target="_blank">other options</a> to use as well.</p>
<p>Only a little time to work today, but unblocked this issue by better understanding the GitHub API and I think making this plugin work is possible.</p>
<p><a target="_blank" href="https://github.com/AramZS/devblog/commit/90f3b22388bb98ff4c0ba73fe56eaf8fbc4d1b40" class="git-commit-link"><code>git commit -am &quot;Finish day 35&quot;</code></a></p>
]]></content:encoded>
	</item>
	
	<item>
		<title>Part 34: In Which I Really Dig Into Markdown It</title>
		<link>https://fightwithtools.dev/posts/projects/devblog/hello-day-34/?source=rss</link>
		<pubDate>Sat, 13 Nov 2021 02:59:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/projects/devblog/hello-day-34/</guid>
		<description>More devblog</description>
		<content:encoded><![CDATA[<h2 id="project-scope-and-todos" tabindex="-1">Project Scope and ToDos</h2>
<ol>
<li>Static Site Generator that can build the blog and let me host it on Github Pages</li>
<li>I want to write posts in Markdown because I'm lazy, it's easy, and it is how I take notes now.</li>
<li>I don't want to spend a ton of time doing design work. I'm doing complicated designs for other projects, so I want to pull a theme I like that I can rely on someone else to keep up.</li>
<li>Once it gets going, I want template changes to be easy.</li>
<li>It should be as easy as Jekyll, so I need to be able to build it using GitHub Actions, where I can just commit a template change or Markdown file and away it goes. If I can't figure this out than fk it, just use Jekyll.</li>
<li>I require it to be used by a significant percent of my professional peers so I can get easy answers when something goes wrong.</li>
<li>I want source maps. This is a dev log site which means whatever I do with it should be easy for other developers to read.</li>
</ol>
<ul class="task-list">
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Also <a href="https://www.npmjs.com/package/@quasibit/eleventy-plugin-sitemap" target="_blank">the sitemap plugin</a> looks cool. Should grab that later.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> So does the <a href="https://www.npmjs.com/package/eleventy-plugin-reading-time" target="_blank">reading time one</a>.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Also <a href="https://github.com/jdsteinbach/eleventy-plugin-toc/" target="_blank">this TOC plugin</a> mby?</p>
</li>
<li class="task-list-item">
<p data-wordfix="true"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Use <a href="https://www.11ty.dev/docs/data-deep-merge/" target="_blank">Data Deep Merge</a> in this blog.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Decide if I want to render the CSS fancier than just a base file and do per-template splitting.</p>
</li>
</ul>
<s>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Can I use the template inside of dinky that already exists instead of copy/pasting it?</li>
</ul>
</s>
<s>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Is there a way to have permalinks to posts contain metadata without organizing them into subfolders?</li>
</ul>
</s>
<ul class="task-list">
<li class="task-list-item">
<p data-wordfix="true"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> How do I cachebreak files on the basis of new build events? Datetime? <code>site.github.build_revision</code> is <a href="https://github.com/jekyll/github-metadata/blob/master/docs/site.github.md" target="_blank">how Jekyll accomplishes this</a>, but is there a way to push <a href="https://docs.github.com/en/actions/reference/context-and-expression-syntax-for-github-actions#github-context" target="_blank">that</a> <a href="https://stackoverflow.com/questions/54310050/how-to-version-build-artifacts-using-github-actions" target="_blank">into the build process</a> for Eleventy?</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Make link text look less shitty. It looks like it is a whole, lighter, font.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Code blocks do not have good syntax highlighting. I want good syntax highlighting.</p>
</li>
<li class="task-list-item">
<p data-wordfix="true"><input disabled="true" type="checkbox" class="markdown-todo" /> Build a Markdown-it plugin to take my typing shortcuts <code>[prob, b/c, ...?]</code> and expand them on build.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> See if we can start Markdown's interpretation of H tags to <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/Heading_Elements#multiple_h1" target="_blank">start at 2, since H1</a> is always pulled from the page title metadata. If it isn't easy, I just have to change my pattern of writing in the MD documents.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Should I <a href="https://www.madebymike.com.au/writing/11ty-filters-data-shortcodes/" target="_blank">explore some shortcodes</a>?</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Order projects listing by last posted blog in that project</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Limit the output of home page post lists to a specific number of posts</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Show the latest post below the site intro on the homepage.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Tags pages with Pagination</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Posts should be able to support a preview header image that can also be shown on post lists.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Create a Markdown-It plugin that reads the project's repo URL off the folder data file and renders commit messages with <a href="https://stackoverflow.com/questions/15919635/on-github-api-what-is-the-best-way-to-get-the-last-commit-message-associated-w" target="_blank">links to the referenced commit</a>. (Is this even possible?) (Is there a way to do it with eleventy instead?)</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Create Next Day/Previous Day links on each post / Next/Previous post on post templates from projects</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Tags should be in the sidebar of articles and link to tag pages</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Create a skiplink for the todo section (or would this be better served with the ToC plugin?) - Yes it would be!</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Add a Things I Learned section to the project pages that are the things I learned from that specific project.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Add a technical reading log to the homepage</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/:empty" target="_blank">Hide</a> empty sections.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Add byline to post pages</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Have table of contents attach to sidebar bottom on mobile</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Support dark mode</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Social Icons</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> SEO/Social/JSON-LD HEAD data</p>
</li>
</ul>
<h2 id="day-34" tabindex="-1">Day 34</h2>
<p>Ok, took some real vacation time, so on the flight back and back to work on trying to build my own markdown-it plugin.</p>
<h3 id="modifying-the-markdown-it-plugin" tabindex="-1">Modifying the Markdown-It Plugin</h3>
<p>Ok, dealing with some errors when it does processing. But I made a good choice this time before getting on the flight, I loaded up the documentation page on Markdown-It. The problem is I needed to give my rule a unique (non-overlapping name with the to-do rule).</p>
<p>Changed it to <code>md.core.ruler.after(&quot;inline&quot;, &quot;short-phrase-fixer&quot;, (state) =&gt; {</code> and now the plugin isn't crashing the build process!</p>
<p>But it isn't doing what I want either.</p>
<p>Ok, it's advancing to the point in the while loop where it is executing my function. That's good, it means my check to find valid language to replace <code>isMyWords</code> is working properly I think.</p>
<p>Ah, ok, it looks like I am absolutely required to change the content of both the token and it's first child. Interesting, I'm not sure why Markdown-it works that way, but good to know. Ok, basic functionality is working! Looks like this now:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-34/#code-skip-hello-day-34-10" id="skip-to-code-skip-hello-day-34-10" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript"><br /><span class="token keyword">const</span> <span class="token function-variable function">isInline</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">token</span><span class="token punctuation">)</span> <span class="token operator">=></span> token <span class="token operator">&amp;&amp;</span> token<span class="token punctuation">.</span>type <span class="token operator">===</span> <span class="token string">"inline"</span><span class="token punctuation">;</span><br /><span class="token keyword">const</span> <span class="token function-variable function">isParagraph</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">token</span><span class="token punctuation">)</span> <span class="token operator">=></span> token <span class="token operator">&amp;&amp;</span> token<span class="token punctuation">.</span>type <span class="token operator">===</span> <span class="token string">"paragraph_open"</span><span class="token punctuation">;</span><br /><span class="token keyword">const</span> <span class="token function-variable function">hasMyWords</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">token</span><span class="token punctuation">)</span> <span class="token operator">=></span> token <span class="token operator">&amp;&amp;</span> <span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex"> 11ty | prob </span><span class="token regex-delimiter">/</span></span><span class="token punctuation">.</span><span class="token function">test</span><span class="token punctuation">(</span>token<span class="token punctuation">.</span>content<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br /><span class="token keyword">function</span> <span class="token function">setAttr</span><span class="token punctuation">(</span><span class="token parameter">token<span class="token punctuation">,</span> name<span class="token punctuation">,</span> value</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />	<span class="token keyword">const</span> index <span class="token operator">=</span> token<span class="token punctuation">.</span><span class="token function">attrIndex</span><span class="token punctuation">(</span>name<span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token keyword">const</span> attr <span class="token operator">=</span> <span class="token punctuation">[</span>name<span class="token punctuation">,</span> value<span class="token punctuation">]</span><span class="token punctuation">;</span><br /><br />	<span class="token keyword">if</span> <span class="token punctuation">(</span>index <span class="token operator">&lt;</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />		token<span class="token punctuation">.</span><span class="token function">attrPush</span><span class="token punctuation">(</span>attr<span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span><br />		token<span class="token punctuation">.</span>attrs<span class="token punctuation">[</span>index<span class="token punctuation">]</span> <span class="token operator">=</span> attr<span class="token punctuation">;</span><br />	<span class="token punctuation">}</span><br /><span class="token punctuation">}</span><br /><br /><span class="token keyword">function</span> <span class="token function">isMyWords</span><span class="token punctuation">(</span><span class="token parameter">tokens<span class="token punctuation">,</span> index</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />	<span class="token keyword">return</span> <span class="token punctuation">(</span><br />		<span class="token function">isInline</span><span class="token punctuation">(</span>tokens<span class="token punctuation">[</span>index<span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token operator">&amp;&amp;</span><br />		<span class="token function">hasMyWords</span><span class="token punctuation">(</span>tokens<span class="token punctuation">[</span>index<span class="token punctuation">]</span><span class="token punctuation">)</span><br />	<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span><br /><br /><span class="token keyword">function</span> <span class="token function">fixMyWords</span><span class="token punctuation">(</span><span class="token parameter">token<span class="token punctuation">,</span> TokenConstructor</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />	<span class="token keyword">let</span> wordChoice <span class="token operator">=</span> <span class="token string">""</span><span class="token punctuation">;</span><br />	<span class="token keyword">const</span> betterWord <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">TokenConstructor</span><span class="token punctuation">(</span><span class="token string">"inline"</span><span class="token punctuation">,</span> <span class="token string">""</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex"> 11ty </span><span class="token regex-delimiter">/</span></span><span class="token punctuation">.</span><span class="token function">test</span><span class="token punctuation">(</span>token<span class="token punctuation">.</span>content<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />		betterWord<span class="token punctuation">.</span>content <span class="token operator">=</span> <span class="token string">" Eleventy "</span><span class="token punctuation">;</span><br />		wordChoice <span class="token operator">=</span> <span class="token string">" 11ty "</span><span class="token punctuation">;</span><br />	<span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex"> prob </span><span class="token regex-delimiter">/</span></span><span class="token punctuation">.</span><span class="token function">test</span><span class="token punctuation">(</span>token<span class="token punctuation">.</span>content<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />		betterWord<span class="token punctuation">.</span>content <span class="token operator">=</span> <span class="token string">" probably "</span><span class="token punctuation">;</span><br />		wordChoice <span class="token operator">=</span> <span class="token string">" prob "</span><span class="token punctuation">;</span><br />	<span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span><br />		<span class="token keyword">return</span> <span class="token punctuation">{</span> <span class="token literal-property property">betterWord</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span> <span class="token literal-property property">wordChoice</span><span class="token operator">:</span> <span class="token boolean">false</span> <span class="token punctuation">}</span><span class="token punctuation">;</span><br />	<span class="token punctuation">}</span><br /><br />	<span class="token keyword">return</span> <span class="token punctuation">{</span> betterWord<span class="token punctuation">,</span> wordChoice <span class="token punctuation">}</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span><br /><br /><span class="token keyword">function</span> <span class="token function">fixWordify</span><span class="token punctuation">(</span><span class="token parameter">token<span class="token punctuation">,</span> TokenConstructor</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />	<span class="token keyword">const</span> <span class="token punctuation">{</span> betterWord<span class="token punctuation">,</span> wordChoice <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token function">fixMyWords</span><span class="token punctuation">(</span>token<span class="token punctuation">,</span> TokenConstructor<span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>betterWord<span class="token punctuation">)</span> <span class="token keyword">return</span> <span class="token boolean">false</span><span class="token punctuation">;</span><br />	token<span class="token punctuation">.</span>content <span class="token operator">=</span> token<span class="token punctuation">.</span>content<span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span>wordChoice<span class="token punctuation">,</span> betterWord<span class="token punctuation">.</span>content<span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token keyword">const</span> fixedContent <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">TokenConstructor</span><span class="token punctuation">(</span><span class="token string">"inline"</span><span class="token punctuation">,</span> <span class="token string">""</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />	fixedContent<span class="token punctuation">.</span>content <span class="token operator">=</span> token<span class="token punctuation">.</span>content<span class="token punctuation">;</span><br />	token<span class="token punctuation">.</span>children<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">.</span>content <span class="token operator">=</span> fixedContent<span class="token punctuation">.</span>content<span class="token punctuation">;</span><br />	console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">"token:"</span><span class="token punctuation">,</span> token<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span><br /><br />module<span class="token punctuation">.</span><span class="token function-variable function">exports</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">md</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />	md<span class="token punctuation">.</span>core<span class="token punctuation">.</span>ruler<span class="token punctuation">.</span><span class="token function">after</span><span class="token punctuation">(</span><span class="token string">"inline"</span><span class="token punctuation">,</span> <span class="token string">"short-phrase-fixer"</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token parameter">state</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />		<span class="token keyword">const</span> tokens <span class="token operator">=</span> state<span class="token punctuation">.</span>tokens<span class="token punctuation">;</span><br />		console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><br />			<span class="token string">"Walking through possible words to fix3"</span><span class="token punctuation">,</span><br />			state<span class="token punctuation">.</span>tokens<span class="token punctuation">.</span><span class="token function">filter</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">token</span><span class="token punctuation">)</span> <span class="token operator">=></span> token<span class="token punctuation">.</span>type <span class="token operator">===</span> <span class="token string">"text"</span><span class="token punctuation">)</span><br />		<span class="token punctuation">)</span><span class="token punctuation">;</span><br />		<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">let</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&lt;</span> tokens<span class="token punctuation">.</span>length<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />			<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token punctuation">(</span>tokens<span class="token punctuation">,</span> <span class="token function">isMyWords</span><span class="token punctuation">(</span>tokens<span class="token punctuation">,</span> i<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />				console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">"Trying to fix some words!"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />				<span class="token function">fixWordify</span><span class="token punctuation">(</span>tokens<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">,</span> state<span class="token punctuation">.</span>Token<span class="token punctuation">)</span><span class="token punctuation">;</span><br />				<span class="token function">setAttr</span><span class="token punctuation">(</span>tokens<span class="token punctuation">[</span>i <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token string">"data-wordfix"</span><span class="token punctuation">,</span> <span class="token string">"true"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />			<span class="token punctuation">}</span><br />		<span class="token punctuation">}</span><br />	<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
<p id="code-skip-hello-day-34-10">But what if more than one word that I need to correct is in the paragraph? I'll need to set it up to run more than once on any piece of content, or do a smarter replace process.</p>
<h3 id="better-replacement-of-words" tabindex="-1">Better replacement of words</h3>
<p>So what if I want to use both <code>prob</code> and <code>11ty</code> in a sentence or if I want to use <code>11ty</code> twice? I need to set it up so I can use both.</p>
<p>Ok, so my instinct here is to set up a set of patterns and their replacements than walk through it. Only, I'm getting an error <code>token.content.replaceAll is not a function</code>. Ok, is this applying to everything or is there some weird edge case?</p>
<p>I'm going to try this for the new <code>fixWordify</code> setup.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-34/#code-skip-hello-day-34-9" id="skip-to-code-skip-hello-day-34-9" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> replaceMe <span class="token operator">=</span> <span class="token punctuation">[</span><br />		<span class="token punctuation">{</span> <span class="token literal-property property">pattern</span><span class="token operator">:</span> <span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex"> 11ty </span><span class="token regex-delimiter">/</span></span><span class="token punctuation">,</span> <span class="token literal-property property">replace</span><span class="token operator">:</span> <span class="token string">" Eleventy "</span> <span class="token punctuation">}</span><span class="token punctuation">,</span><br />		<span class="token punctuation">{</span> <span class="token literal-property property">pattern</span><span class="token operator">:</span> <span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex"> prob </span><span class="token regex-delimiter">/</span></span><span class="token punctuation">,</span> <span class="token literal-property property">replace</span><span class="token operator">:</span> <span class="token string">" probably "</span> <span class="token punctuation">}</span><span class="token punctuation">,</span><br />		<span class="token punctuation">{</span> <span class="token literal-property property">pattern</span><span class="token operator">:</span> <span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex"> graf </span><span class="token regex-delimiter">/</span></span><span class="token punctuation">,</span> <span class="token literal-property property">replace</span><span class="token operator">:</span> <span class="token string">" paragraph "</span> <span class="token punctuation">}</span><span class="token punctuation">,</span><br />	<span class="token punctuation">]</span><span class="token punctuation">;</span><br />	<span class="token keyword">try</span> <span class="token punctuation">{</span><br />		replaceMe<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">wordReplace</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />			<span class="token keyword">const</span> betterWord <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">TokenConstructor</span><span class="token punctuation">(</span><span class="token string">"inline"</span><span class="token punctuation">,</span> <span class="token string">""</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />			betterWord<span class="token punctuation">.</span>content <span class="token operator">=</span> token<span class="token punctuation">.</span>content<span class="token punctuation">.</span><span class="token function">replaceAll</span><span class="token punctuation">(</span><br />				wordReplace<span class="token punctuation">.</span>pattern<span class="token punctuation">,</span><br />				wordReplace<span class="token punctuation">.</span>replace<br />			<span class="token punctuation">)</span><span class="token punctuation">;</span><br />			token<span class="token punctuation">.</span>content <span class="token operator">=</span> betterWord<span class="token punctuation">.</span>content<span class="token punctuation">;</span><br />			token<span class="token punctuation">.</span>children<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">.</span>content <span class="token operator">=</span> betterWord<span class="token punctuation">.</span>content<span class="token punctuation">;</span><br />			console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">"token:"</span><span class="token punctuation">,</span> token<span class="token punctuation">)</span><span class="token punctuation">;</span><br />		<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span>e<span class="token punctuation">)</span> <span class="token punctuation">{</span><br />		console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">"Could not replace content in token: "</span><span class="token punctuation">,</span> token<span class="token punctuation">)</span><span class="token punctuation">;</span><br />		console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>e<span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token punctuation">}</span></code></pre>
<p id="code-skip-hello-day-34-9">Ok, now build continues, but notably the replacements don't seem to be happening. So it looks like it is breaking every time. Some of the tokens are indeed very complex like:</p>
<h4 id="a-more-complex-markdown-it-token" tabindex="-1">A More Complex Markdown-It Token</h4>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-34/#code-skip-hello-day-34-8" id="skip-to-code-skip-hello-day-34-8" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript">Token <span class="token punctuation">{</span><br />  <span class="token literal-property property">type</span><span class="token operator">:</span> <span class="token string">'inline'</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">tag</span><span class="token operator">:</span> <span class="token string">''</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">attrs</span><span class="token operator">:</span> <span class="token keyword">null</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">map</span><span class="token operator">:</span> <span class="token punctuation">[</span> <span class="token number">82</span><span class="token punctuation">,</span> <span class="token number">83</span> <span class="token punctuation">]</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">nesting</span><span class="token operator">:</span> <span class="token number">0</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">level</span><span class="token operator">:</span> <span class="token number">1</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">children</span><span class="token operator">:</span> <span class="token punctuation">[</span><br />    Token <span class="token punctuation">{</span><br />      <span class="token literal-property property">type</span><span class="token operator">:</span> <span class="token string">'text'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">tag</span><span class="token operator">:</span> <span class="token string">''</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">attrs</span><span class="token operator">:</span> <span class="token keyword">null</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">map</span><span class="token operator">:</span> <span class="token keyword">null</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">nesting</span><span class="token operator">:</span> <span class="token number">0</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">level</span><span class="token operator">:</span> <span class="token number">0</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">children</span><span class="token operator">:</span> <span class="token keyword">null</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">content</span><span class="token operator">:</span> <span class="token string">"First of all, I want a chunk of that page that shows my various Work in Progress posts. I've tagged the posts themselves correctly "</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">markup</span><span class="token operator">:</span> <span class="token string">''</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">info</span><span class="token operator">:</span> <span class="token string">''</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">meta</span><span class="token operator">:</span> <span class="token keyword">null</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">block</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">hidden</span><span class="token operator">:</span> <span class="token boolean">false</span><br />    <span class="token punctuation">}</span><span class="token punctuation">,</span><br />    Token <span class="token punctuation">{</span><br />      <span class="token literal-property property">type</span><span class="token operator">:</span> <span class="token string">'link_open'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">tag</span><span class="token operator">:</span> <span class="token string">'a'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">attrs</span><span class="token operator">:</span> <span class="token punctuation">[</span>Array<span class="token punctuation">]</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">map</span><span class="token operator">:</span> <span class="token keyword">null</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">nesting</span><span class="token operator">:</span> <span class="token number">1</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">level</span><span class="token operator">:</span> <span class="token number">0</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">children</span><span class="token operator">:</span> <span class="token keyword">null</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">content</span><span class="token operator">:</span> <span class="token string">''</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">markup</span><span class="token operator">:</span> <span class="token string">''</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">info</span><span class="token operator">:</span> <span class="token string">''</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">meta</span><span class="token operator">:</span> <span class="token keyword">null</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">block</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">hidden</span><span class="token operator">:</span> <span class="token boolean">false</span><br />    <span class="token punctuation">}</span><span class="token punctuation">,</span><br />    Token <span class="token punctuation">{</span><br />      <span class="token literal-property property">type</span><span class="token operator">:</span> <span class="token string">'text'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">tag</span><span class="token operator">:</span> <span class="token string">''</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">attrs</span><span class="token operator">:</span> <span class="token keyword">null</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">map</span><span class="token operator">:</span> <span class="token keyword">null</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">nesting</span><span class="token operator">:</span> <span class="token number">0</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">level</span><span class="token operator">:</span> <span class="token number">1</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">children</span><span class="token operator">:</span> <span class="token keyword">null</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">content</span><span class="token operator">:</span> <span class="token string">'to create an 11ty collection'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">markup</span><span class="token operator">:</span> <span class="token string">''</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">info</span><span class="token operator">:</span> <span class="token string">''</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">meta</span><span class="token operator">:</span> <span class="token keyword">null</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">block</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">hidden</span><span class="token operator">:</span> <span class="token boolean">false</span><br />    <span class="token punctuation">}</span><span class="token punctuation">,</span><br />    Token <span class="token punctuation">{</span><br />      <span class="token literal-property property">type</span><span class="token operator">:</span> <span class="token string">'link_close'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">tag</span><span class="token operator">:</span> <span class="token string">'a'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">attrs</span><span class="token operator">:</span> <span class="token keyword">null</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">map</span><span class="token operator">:</span> <span class="token keyword">null</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">nesting</span><span class="token operator">:</span> <span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">level</span><span class="token operator">:</span> <span class="token number">0</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">children</span><span class="token operator">:</span> <span class="token keyword">null</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">content</span><span class="token operator">:</span> <span class="token string">''</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">markup</span><span class="token operator">:</span> <span class="token string">''</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">info</span><span class="token operator">:</span> <span class="token string">''</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">meta</span><span class="token operator">:</span> <span class="token keyword">null</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">block</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">hidden</span><span class="token operator">:</span> <span class="token boolean">false</span><br />    <span class="token punctuation">}</span><span class="token punctuation">,</span><br />    Token <span class="token punctuation">{</span><br />      <span class="token literal-property property">type</span><span class="token operator">:</span> <span class="token string">'text'</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">tag</span><span class="token operator">:</span> <span class="token string">''</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">attrs</span><span class="token operator">:</span> <span class="token keyword">null</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">map</span><span class="token operator">:</span> <span class="token keyword">null</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">nesting</span><span class="token operator">:</span> <span class="token number">0</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">level</span><span class="token operator">:</span> <span class="token number">0</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">children</span><span class="token operator">:</span> <span class="token keyword">null</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">content</span><span class="token operator">:</span> <span class="token string">", but I need to figure out how to call it. And I may want to display it elsewhere, so I'm going to create a component I can easily include that walks through the WiP tag."</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">markup</span><span class="token operator">:</span> <span class="token string">''</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">info</span><span class="token operator">:</span> <span class="token string">''</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">meta</span><span class="token operator">:</span> <span class="token keyword">null</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">block</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span><br />      <span class="token literal-property property">hidden</span><span class="token operator">:</span> <span class="token boolean">false</span><br />    <span class="token punctuation">}</span><br />  <span class="token punctuation">]</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">content</span><span class="token operator">:</span> <span class="token string">"First of all, I want a chunk of that page that shows my various Work in Progress posts. I've tagged the posts themselves correctly [to create an 11ty collection](https://www.11ty.dev/docs/collections/), but I need to figure out how to call it. And I may want to display it elsewhere, so I'm going to create a component I can easily include that walks through the WiP tag."</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">markup</span><span class="token operator">:</span> <span class="token string">''</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">info</span><span class="token operator">:</span> <span class="token string">''</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">meta</span><span class="token operator">:</span> <span class="token keyword">null</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">block</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">hidden</span><span class="token operator">:</span> <span class="token boolean">false</span><br /><span class="token punctuation">}</span></code></pre>
<p id="code-skip-hello-day-34-8">But some are simple. And they all have content I can replace.</p>
<p>Ok, let's add more detail to the log.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-34/#code-skip-hello-day-34-7" id="skip-to-code-skip-hello-day-34-7" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript">		console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><br />			<span class="token string">"Could not replace content in token: "</span><span class="token punctuation">,</span><br />			token<span class="token punctuation">.</span>content<span class="token punctuation">,</span><br />			token<span class="token punctuation">.</span>children<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">.</span>content<span class="token punctuation">,</span><br />			token<br />		<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p id="code-skip-hello-day-34-7">I'm still not seeing what could go wrong. These things are strings and should have <code>replaceAll</code>? I double checked and indeed, <code>replace</code> works just fine. I guess we can just use <code>replace</code> if I have the right configuration for the regex, ending it with <code>/gi</code>.</p>
<p>Ok, that's working! Now let's remove my potential future human error opportunity by keeping the patterns I'm walking through in a single place:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-34/#code-skip-hello-day-34-6" id="skip-to-code-skip-hello-day-34-6" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> <span class="token function-variable function">myWords</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />	<span class="token keyword">return</span> <span class="token punctuation">[</span><br />		<span class="token punctuation">{</span> <span class="token literal-property property">pattern</span><span class="token operator">:</span> <span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex"> 11ty </span><span class="token regex-delimiter">/</span><span class="token regex-flags">gi</span></span><span class="token punctuation">,</span> <span class="token literal-property property">replace</span><span class="token operator">:</span> <span class="token string">" Eleventy "</span> <span class="token punctuation">}</span><span class="token punctuation">,</span><br />		<span class="token punctuation">{</span> <span class="token literal-property property">pattern</span><span class="token operator">:</span> <span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex"> prob </span><span class="token regex-delimiter">/</span><span class="token regex-flags">gi</span></span><span class="token punctuation">,</span> <span class="token literal-property property">replace</span><span class="token operator">:</span> <span class="token string">" probably "</span> <span class="token punctuation">}</span><span class="token punctuation">,</span><br />		<span class="token punctuation">{</span> <span class="token literal-property property">pattern</span><span class="token operator">:</span> <span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex"> graf </span><span class="token regex-delimiter">/</span><span class="token regex-flags">gi</span></span><span class="token punctuation">,</span> <span class="token literal-property property">replace</span><span class="token operator">:</span> <span class="token string">" paragraph "</span> <span class="token punctuation">}</span><span class="token punctuation">,</span><br />	<span class="token punctuation">]</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
<p id="code-skip-hello-day-34-6">and now my check is a little more complex:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-34/#code-skip-hello-day-34-5" id="skip-to-code-skip-hello-day-34-5" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> <span class="token function-variable function">hasMyWords</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">token</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />	<span class="token keyword">if</span> <span class="token punctuation">(</span>token<span class="token punctuation">)</span> <span class="token punctuation">{</span><br />		<span class="token comment">// myWords().forEach((word) => {</span><br />		<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">let</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&lt;</span> <span class="token function">myWords</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span>length<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />			<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">myWords</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">.</span>pattern<span class="token punctuation">.</span><span class="token function">test</span><span class="token punctuation">(</span>token<span class="token punctuation">.</span>content<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />				console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">"Word Replacement Time"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />				<span class="token keyword">return</span> <span class="token boolean">true</span><span class="token punctuation">;</span><br />			<span class="token punctuation">}</span><br />		<span class="token punctuation">}</span><br />	<span class="token punctuation">}</span><br />	<span class="token keyword">return</span> <span class="token boolean">false</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
<p id="code-skip-hello-day-34-5">Ok. Looking good. But it turns out this method doesn't handle the more complicated objects like the one above, instead of expecting only one child, we'll need to walk through all the children and do their replacements individually.</p>
<h3 id="handle-each-token-child" tabindex="-1">Handle each token child</h3>
<p>Ok, let's turn the <code>token.content</code> process into its own function I can use during the interation of token children:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-34/#code-skip-hello-day-34-4" id="skip-to-code-skip-hello-day-34-4" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">function</span> <span class="token function">fixMyWords</span><span class="token punctuation">(</span><span class="token parameter">wordReplace<span class="token punctuation">,</span> token<span class="token punctuation">,</span> TokenConstructor</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />	<span class="token keyword">const</span> betterWord <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">TokenConstructor</span><span class="token punctuation">(</span><span class="token string">"inline"</span><span class="token punctuation">,</span> <span class="token string">""</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token keyword">const</span> replaced <span class="token operator">=</span> token<span class="token punctuation">.</span>content<span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span><br />		wordReplace<span class="token punctuation">.</span>pattern<span class="token punctuation">,</span><br />		wordReplace<span class="token punctuation">.</span>replace<br />	<span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token keyword">if</span> <span class="token punctuation">(</span>replaced<span class="token punctuation">)</span> <span class="token punctuation">{</span><br />		betterWord<span class="token punctuation">.</span>content <span class="token operator">=</span> replaced<span class="token punctuation">;</span><br />		token<span class="token punctuation">.</span>content <span class="token operator">=</span> betterWord<span class="token punctuation">.</span>content<span class="token punctuation">;</span><br />	<span class="token punctuation">}</span><br /><span class="token punctuation">}</span></code></pre>
<p id="code-skip-hello-day-34-4">Now we can use a simpler version of <code>replaceMe</code> that works with walking over the children!</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-34/#code-skip-hello-day-34-3" id="skip-to-code-skip-hello-day-34-3" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript">replaceMe<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">wordReplace</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />	<span class="token function">fixMyWords</span><span class="token punctuation">(</span>wordReplace<span class="token punctuation">,</span> token<span class="token punctuation">,</span> TokenConstructor<span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">let</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&lt;</span> token<span class="token punctuation">.</span>children<span class="token punctuation">.</span>length<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />		<span class="token function">fixMyWords</span><span class="token punctuation">(</span>wordReplace<span class="token punctuation">,</span> token<span class="token punctuation">.</span>children<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">,</span> TokenConstructor<span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token punctuation">}</span><br /><span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre>
<p id="code-skip-hello-day-34-3">That works!</p>
<p>Last thing I want to do... make sure this works if one of my replacement words is at the end of a sentence or has a comma after it and still needs to be replaced. I forgot about this case.</p>
<p><a target="_blank" href="https://github.com/AramZS/devblog/commit/e71045edccd9dcbeabb4828137b287a855a37a78" class="git-commit-link"><code>git commit -am &quot;Get replacement working with complex tokens&quot;</code></a></p>
<h3 id="replacing-the-word-with-punctuation" tabindex="-1">Replacing the word with punctuation</h3>
<p>This one should be pretty easy, I just need to add a look ahead for a variety of eligible punctuation. <code>(?=[\?\.\,\s\! ])</code> should do it.</p>
<p>Now the <code>myWords</code> function looks like this:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-34/#code-skip-hello-day-34-2" id="skip-to-code-skip-hello-day-34-2" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> <span class="token function-variable function">myWords</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />	<span class="token keyword">return</span> <span class="token punctuation">[</span><br />		<span class="token punctuation">{</span> <span class="token literal-property property">pattern</span><span class="token operator">:</span> <span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex"> 11ty(?=[\?\.\,\s\! ])</span><span class="token regex-delimiter">/</span><span class="token regex-flags">gi</span></span><span class="token punctuation">,</span> <span class="token literal-property property">replace</span><span class="token operator">:</span> <span class="token string">" Eleventy"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span><br />		<span class="token punctuation">{</span> <span class="token literal-property property">pattern</span><span class="token operator">:</span> <span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex"> prob(?=[\?\.\,\s\! ])</span><span class="token regex-delimiter">/</span><span class="token regex-flags">gi</span></span><span class="token punctuation">,</span> <span class="token literal-property property">replace</span><span class="token operator">:</span> <span class="token string">" probably"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span><br />		<span class="token punctuation">{</span> <span class="token literal-property property">pattern</span><span class="token operator">:</span> <span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex"> graf(?=[\?\.\,\s\! ])</span><span class="token regex-delimiter">/</span><span class="token regex-flags">gi</span></span><span class="token punctuation">,</span> <span class="token literal-property property">replace</span><span class="token operator">:</span> <span class="token string">" paragraph"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span><br />	<span class="token punctuation">]</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
<p id="code-skip-hello-day-34-2">I specifically don't want to include quotes in this But what about parenthesis? It looks like <code>Markdown-It</code> does indeed break out the chunks of text in such a way that I don't have to worry about breaking Markdown links. Should be easy enough. Just need a lookbehind. Also, I can add in new lines or tabs as characters as well.</p>
<p>Now it looks like this:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-34/#code-skip-hello-day-34-1" id="skip-to-code-skip-hello-day-34-1" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> <span class="token function-variable function">myWords</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />	<span class="token keyword">return</span> <span class="token punctuation">[</span><br />		<span class="token punctuation">{</span><br />			<span class="token literal-property property">pattern</span><span class="token operator">:</span> <span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">(?&lt;=[\t\s\S\( ])11ty(?=[\?\.\,\s\r\n\!\) ])</span><span class="token regex-delimiter">/</span><span class="token regex-flags">gi</span></span><span class="token punctuation">,</span><br />			<span class="token literal-property property">replace</span><span class="token operator">:</span> <span class="token string">"Eleventy"</span><span class="token punctuation">,</span><br />		<span class="token punctuation">}</span><span class="token punctuation">,</span><br />		<span class="token punctuation">{</span><br />			<span class="token literal-property property">pattern</span><span class="token operator">:</span> <span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">(?&lt;=[\t\s\( ])prob(?=[\?\.\,\s\r\n\!\) ])</span><span class="token regex-delimiter">/</span><span class="token regex-flags">gi</span></span><span class="token punctuation">,</span><br />			<span class="token literal-property property">replace</span><span class="token operator">:</span> <span class="token string">"probably"</span><span class="token punctuation">,</span><br />		<span class="token punctuation">}</span><span class="token punctuation">,</span><br />		<span class="token punctuation">{</span><br />			<span class="token literal-property property">pattern</span><span class="token operator">:</span> <span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">(?&lt;=[\t\s\( ])graf(?=[\?\.\,\s\r\n\!\) ])</span><span class="token regex-delimiter">/</span><span class="token regex-flags">gi</span></span><span class="token punctuation">,</span><br />			<span class="token literal-property property">replace</span><span class="token operator">:</span> <span class="token string">"paragraph"</span><span class="token punctuation">,</span><br />		<span class="token punctuation">}</span><span class="token punctuation">,</span><br />	<span class="token punctuation">]</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
<p id="code-skip-hello-day-34-1">Looking good! I can test and add more words later, landing now.</p>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Build a Markdown-it plugin to take my typing shortcuts <code>[prob, b/c, ...?]</code> and expand them on build.</li>
</ul>
<p><a target="_blank" href="https://github.com/AramZS/devblog/commit/08a817d45c3cd5d9e888b640326159c8f3023c4f" class="git-commit-link"><code>git commit -am &quot;Finish day 34&quot;</code></a></p>
<h2 id="a-few-notes-on-touch-up" tabindex="-1">A few notes on touch up</h2>
<p>Just noting on here that I touched up the above Regex which had a few bad errors I didn't want anyone to repeat. Most importantly, I removed my use of <code>\S</code>.</p>
<p><a target="_blank" href="https://github.com/AramZS/devblog/commit/a901930b83fe4006c4f5759b0041f9192312585d" class="git-commit-link"><code>git commit -am &quot;Touch up day 34 stuff&quot;</code></a></p>
]]></content:encoded>
	</item>
	
	<item>
		<title>Part 33: Markdown It Playtime and CSS Touchups</title>
		<link>https://fightwithtools.dev/posts/projects/devblog/hello-day-33/?source=rss</link>
		<pubDate>Sat, 13 Nov 2021 02:59:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/projects/devblog/hello-day-33/</guid>
		<description>More devblog</description>
		<content:encoded><![CDATA[<h2 id="project-scope-and-todos" tabindex="-1">Project Scope and ToDos</h2>
<ol>
<li>Static Site Generator that can build the blog and let me host it on Github Pages</li>
<li>I want to write posts in Markdown because I'm lazy, it's easy, and it is how I take notes now.</li>
<li>I don't want to spend a ton of time doing design work. I'm doing complicated designs for other projects, so I want to pull a theme I like that I can rely on someone else to keep up.</li>
<li>Once it gets going, I want template changes to be easy.</li>
<li>It should be as easy as Jekyll, so I need to be able to build it using GitHub Actions, where I can just commit a template change or Markdown file and away it goes. If I can't figure this out than fk it, just use Jekyll.</li>
<li>I require it to be used by a significant percent of my professional peers so I can get easy answers when something goes wrong.</li>
<li>I want source maps. This is a dev log site which means whatever I do with it should be easy for other developers to read.</li>
</ol>
<ul class="task-list">
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Also <a href="https://www.npmjs.com/package/@quasibit/eleventy-plugin-sitemap" target="_blank">the sitemap plugin</a> looks cool. Should grab that later.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> So does the <a href="https://www.npmjs.com/package/eleventy-plugin-reading-time" target="_blank">reading time one</a>.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Also <a href="https://github.com/jdsteinbach/eleventy-plugin-toc/" target="_blank">this TOC plugin</a> mby?</p>
</li>
<li class="task-list-item">
<p data-wordfix="true"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Use <a href="https://www.11ty.dev/docs/data-deep-merge/" target="_blank">Data Deep Merge</a> in this blog.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Decide if I want to render the CSS fancier than just a base file and do per-template splitting.</p>
</li>
</ul>
<s>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Can I use the template inside of dinky that already exists instead of copy/pasting it?</li>
</ul>
</s>
<s>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Is there a way to have permalinks to posts contain metadata without organizing them into subfolders?</li>
</ul>
</s>
<ul class="task-list">
<li class="task-list-item">
<p data-wordfix="true"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> How do I cachebreak files on the basis of new build events? Datetime? <code>site.github.build_revision</code> is <a href="https://github.com/jekyll/github-metadata/blob/master/docs/site.github.md" target="_blank">how Jekyll accomplishes this</a>, but is there a way to push <a href="https://docs.github.com/en/actions/reference/context-and-expression-syntax-for-github-actions#github-context" target="_blank">that</a> <a href="https://stackoverflow.com/questions/54310050/how-to-version-build-artifacts-using-github-actions" target="_blank">into the build process</a> for Eleventy?</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Make link text look less shitty. It looks like it is a whole, lighter, font.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Code blocks do not have good syntax highlighting. I want good syntax highlighting.</p>
</li>
<li class="task-list-item">
<p data-wordfix="true"><input disabled="true" type="checkbox" class="markdown-todo" /> Build a Markdown-it plugin to take my typing shortcuts <code>[prob, b/c, ...?]</code> and expand them on build.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> See if we can start Markdown's interpretation of H tags to <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/Heading_Elements#multiple_h1" target="_blank">start at 2, since H1</a> is always pulled from the page title metadata. If it isn't easy, I just have to change my pattern of writing in the MD documents.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Should I <a href="https://www.madebymike.com.au/writing/11ty-filters-data-shortcodes/" target="_blank">explore some shortcodes</a>?</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Order projects listing by last posted blog in that project</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Limit the output of home page post lists to a specific number of posts</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Show the latest post below the site intro on the homepage.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Tags pages with Pagination</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Posts should be able to support a preview header image that can also be shown on post lists.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Create a Markdown-It plugin that reads the project's repo URL off the folder data file and renders commit messages with <a href="https://stackoverflow.com/questions/15919635/on-github-api-what-is-the-best-way-to-get-the-last-commit-message-associated-w" target="_blank">links to the referenced commit</a>. (Is this even possible?) (Is there a way to do it with eleventy instead?)</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Create Next Day/Previous Day links on each post / Next/Previous post on post templates from projects</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Tags should be in the sidebar of articles and link to tag pages</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Create a skiplink for the todo section (or would this be better served with the ToC plugin?) - Yes it would be!</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Add a Things I Learned section to the project pages that are the things I learned from that specific project.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Add a technical reading log to the homepage</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/:empty" target="_blank">Hide</a> empty sections.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Add byline to post pages</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Have table of contents attach to sidebar bottom on mobile</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Support dark mode</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Social Icons</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> SEO/Social/JSON-LD HEAD data</p>
</li>
</ul>
<h2 id="day-33" tabindex="-1">Day 33</h2>
<p>Ok, got some plane time today. Let's see how far I can get without connecting to the internet.</p>
<h3 id="syntax-highlighting-for-njk-snippets." tabindex="-1">Syntax highlighting for NJK snippets.</h3>
<p>I think I want to try to take on some of the hacking I need to do to the markdown parser. This is a good time to work at it a little and see what I can get it to do.</p>
<p>First, I've noticed that there isn't really a syntax highlight for Nunjucks in the Prism system I'm using for code hints. I've been building the code blocks using Liquid instead since they are basically the same. But it would be nice to use the correct naming convention. I think I should be able to? I copied the extension for how Prism handles Markdown from the Eleventy site. Can I do something similar here? Let's try.</p>
<h4 id="extending-liquid" tabindex="-1">Extending Liquid</h4>
<p>New statement adding in Prism for code highlighting like this.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-33/#code-skip-hello-day-33-8" id="skip-to-code-skip-hello-day-33-8" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript">	eleventyConfig<span class="token punctuation">.</span><span class="token function">addPlugin</span><span class="token punctuation">(</span>syntaxHighlight<span class="token punctuation">,</span> <span class="token punctuation">{</span><br />		<span class="token literal-property property">templateFormats</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">"md"</span><span class="token punctuation">,</span> <span class="token string">"njk"</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br />		<span class="token function-variable function">init</span><span class="token operator">:</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> Prism <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />			Prism<span class="token punctuation">.</span>languages<span class="token punctuation">.</span>markdown <span class="token operator">=</span> Prism<span class="token punctuation">.</span>languages<span class="token punctuation">.</span><span class="token function">extend</span><span class="token punctuation">(</span><span class="token string">"markup"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span><br />				<span class="token literal-property property">frontmatter</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />					<span class="token literal-property property">pattern</span><span class="token operator">:</span> <span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">^---[\s\S]*?^---$</span><span class="token regex-delimiter">/</span><span class="token regex-flags">m</span></span><span class="token punctuation">,</span><br />					<span class="token literal-property property">greedy</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span><br />					<span class="token literal-property property">inside</span><span class="token operator">:</span> Prism<span class="token punctuation">.</span>languages<span class="token punctuation">.</span>yaml<span class="token punctuation">,</span><br />				<span class="token punctuation">}</span><span class="token punctuation">,</span><br />			<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />			console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>Prism<span class="token punctuation">.</span>languages<span class="token punctuation">)</span><span class="token punctuation">;</span><br />			Prism<span class="token punctuation">.</span>languages<span class="token punctuation">.</span>njk <span class="token operator">=</span> Prism<span class="token punctuation">.</span>languages<span class="token punctuation">.</span><span class="token function">extend</span><span class="token punctuation">(</span><span class="token string">"liquid"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />		<span class="token punctuation">}</span><span class="token punctuation">,</span><br />	<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p id="code-skip-hello-day-33-8">Ok, it didn't throw an error. Let's see what we can do? I added the console.log because I'm curious about what other languages are in there and interestingly it appears that maybe I don't need to have this language extension? I see a bunch of good looking rules in there under <code>md</code>. Something to try later.</p>
<p>Hmm I changed the log to only throw up the keys and the list is more limited than I thought.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-33/#code-skip-hello-day-33-7" id="skip-to-code-skip-hello-day-33-7" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript"><span class="token punctuation">[</span><br />  <span class="token string">'extend'</span><span class="token punctuation">,</span> <span class="token string">'insertBefore'</span><span class="token punctuation">,</span><br />  <span class="token string">'DFS'</span><span class="token punctuation">,</span>    <span class="token string">'markup'</span><span class="token punctuation">,</span><br />  <span class="token string">'html'</span><span class="token punctuation">,</span>   <span class="token string">'mathml'</span><span class="token punctuation">,</span><br />  <span class="token string">'svg'</span><span class="token punctuation">,</span>    <span class="token string">'xml'</span><span class="token punctuation">,</span><br />  <span class="token string">'ssml'</span><span class="token punctuation">,</span>   <span class="token string">'atom'</span><span class="token punctuation">,</span><br />  <span class="token string">'rss'</span><span class="token punctuation">,</span>    <span class="token string">'css'</span><span class="token punctuation">,</span><br />  <span class="token string">'clike'</span><span class="token punctuation">,</span>  <span class="token string">'javascript'</span><span class="token punctuation">,</span><br />  <span class="token string">'js'</span><span class="token punctuation">,</span>     <span class="token string">'yaml'</span><span class="token punctuation">,</span><br />  <span class="token string">'yml'</span><span class="token punctuation">,</span>    <span class="token string">'markdown'</span><br /><span class="token punctuation">]</span></code></pre>
<p id="code-skip-hello-day-33-7">So I guess using <code>liquid</code> was doing me no favors either. Annoying. I guess HTML is likely the way I want to go then?</p>
<h4 id="extending-html" tabindex="-1">Extending HTML</h4>
<p>Hmmm extending HTML for liquid/njk is doing me no favors. It's too bad that the handlebars-style syntax is not more JS like because I could likely use a pattern to make it easier to read. Worth a try at least?</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-33/#code-skip-hello-day-33-6" id="skip-to-code-skip-hello-day-33-6" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript">			Prism<span class="token punctuation">.</span>languages<span class="token punctuation">.</span>liquid <span class="token operator">=</span> Prism<span class="token punctuation">.</span>languages<span class="token punctuation">.</span><span class="token function">extend</span><span class="token punctuation">(</span><span class="token string">"html"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span><br />				<span class="token literal-property property">templateTag</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />					<span class="token literal-property property">pattern</span><span class="token operator">:</span> <span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">(?&lt;=\{\%).*?(?=\%\})</span><span class="token regex-delimiter">/</span><span class="token regex-flags">g</span></span><span class="token punctuation">,</span><br />					<span class="token literal-property property">greedy</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span><br />					<span class="token literal-property property">inside</span><span class="token operator">:</span> Prism<span class="token punctuation">.</span>languages<span class="token punctuation">.</span>javascript<span class="token punctuation">,</span><br />				<span class="token punctuation">}</span><span class="token punctuation">,</span><br />			<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />			Prism<span class="token punctuation">.</span>languages<span class="token punctuation">.</span>njk <span class="token operator">=</span> Prism<span class="token punctuation">.</span>languages<span class="token punctuation">.</span><span class="token function">extend</span><span class="token punctuation">(</span><span class="token string">"liquid"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p id="code-skip-hello-day-33-6">Ok this is looking much better, though I'd like to have some color on the opening and closing brackets.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-33/#code-skip-hello-day-33-5" id="skip-to-code-skip-hello-day-33-5" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript">			Prism<span class="token punctuation">.</span>languages<span class="token punctuation">.</span>liquid <span class="token operator">=</span> Prism<span class="token punctuation">.</span>languages<span class="token punctuation">.</span><span class="token function">extend</span><span class="token punctuation">(</span><span class="token string">"html"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span><br />				<span class="token literal-property property">templateTag</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />					<span class="token literal-property property">pattern</span><span class="token operator">:</span> <span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">(?&lt;=\{\%).*?(?=\%\})</span><span class="token regex-delimiter">/</span><span class="token regex-flags">g</span></span><span class="token punctuation">,</span><br />					<span class="token literal-property property">greedy</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span><br />					<span class="token literal-property property">inside</span><span class="token operator">:</span> Prism<span class="token punctuation">.</span>languages<span class="token punctuation">.</span>javascript<span class="token punctuation">,</span><br />				<span class="token punctuation">}</span><span class="token punctuation">,</span><br />				<span class="token literal-property property">templateTagBoundary</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />					<span class="token literal-property property">pattern</span><span class="token operator">:</span> <span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">\{\%}?|\%\}?</span><span class="token regex-delimiter">/</span><span class="token regex-flags">g</span></span><span class="token punctuation">,</span><br />					<span class="token literal-property property">greedy</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span><br />					<span class="token literal-property property">alias</span><span class="token operator">:</span> <span class="token string">"template-tag-boundary"</span><span class="token punctuation">,</span><br />				<span class="token punctuation">}</span><span class="token punctuation">,</span><br />			<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<h4 id="css-touchup-for-new-code-blocks" tabindex="-1">CSS Touchup for new Code Blocks</h4>
<p id="code-skip-hello-day-33-5">Ok by adding the pattern to capture the tag boundaries I've now wrapped every template tag opener and closer in <code>&lt;span&gt;</code> tags with the class set to <code>token templateTagBoundary template-tag-boundary</code>. Perfect. So now I just have to add the style I want. And you know what, while I'm in there I might touch up a few more styles.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-33/#code-skip-hello-day-33-4" id="skip-to-code-skip-hello-day-33-4" class="skip-link">Skip code block ▼</a></p>
<pre class="language-sass"><code class="language-sass"><span class="token selector">.template-tag-boundary {</span><br /><span class="token property-line">	<span class="token property">color</span><span class="token punctuation">:</span> #ec4984;</span><br /><span class="token selector">}</span><br /><br /><span class="token selector">.tag > .tag > .punctuation</span><span class="token punctuation">,</span><br /><span class="token selector">.tag > .punctuation:last-of-type {</span><br /><span class="token property-line">	<span class="token property">color</span><span class="token punctuation">:</span> #1cf08d;</span><br /><span class="token selector">}</span></code></pre>
<p id="code-skip-hello-day-33-4">Ok, adding this to my syntax highlighting sheet means things are starting to look good. Great this is really great. I think I'm pretty satisfied with the code styling for now. Regex is always a mind-bender but I'm definitely getting better at it. I'd like to make the code blocks a little more readable. Let's start by giving them 100% width to fill to the width of the parent container.</p>
<p>Oh, this <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/overscroll-behavior.html" target="_blank">overscroll behavior</a> looks useful. Maybe I'll add that, even if it isn't widely supported. Using <code>overscroll-behavior-x: contain</code> will hopefully at least prevent some of the browsers from bouncing when the user overscrolls on the <code>pre</code> elements on mobile.</p>
<p>I'm also going to shrink the size a bit, make it so that more fits into the pre box on smaller screens.</p>
<p>All together I think that should help make the code samples a little more readable on mobile.</p>
<p><a target="_blank" href="https://github.com/AramZS/devblog/commit/12cae322c05692f40a201fbe4e7ffb3f064a6277" class="git-commit-link"><code>git commit -am &quot;Touching up syntax highlighting&quot;</code></a></p>
<h3 id="touching-up-table-of-contents" tabindex="-1">Touching up Table of Contents</h3>
<p>Hmmm, while I was in here touching up the CSS I was not happy with some of the behavior of the table of contents. It really needs a <em>lot</em> of vertical space. But why not support big screens when they are available? A few small touch ups and I can make my site a little easier to navigate on larger screens.</p>
<p>Let's add a size to my variables Sass for the minimum width I'll need to fit everything in: <code>$ultra-large: 1336px</code> and now I'll want to cover ultra long TOCs, just in case:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-33/#code-skip-hello-day-33-3" id="skip-to-code-skip-hello-day-33-3" class="skip-link">Skip code block ▼</a></p>
<pre class="language-sass"><code class="language-sass"><span class="token selector">#toc-container__inner</span><br /><span class="token atrule-line">    <span class="token atrule">@media</span> (min-width: variables.$large-mobile) and (min-height: 962px)</span><br /><span class="token property-line">        <span class="token property">overflow-y</span><span class="token punctuation">:</span> auto</span><br /><span class="token property-line">        <span class="token property">max-height</span><span class="token punctuation">:</span> 225px</span><br /><span class="token atrule-line">    <span class="token atrule">@media</span> (min-width: variables.$ultra-large)</span><br /><span class="token property-line">        <span class="token property">overflow-y</span><span class="token punctuation">:</span> auto</span><br /><span class="token property-line">        <span class="token property">max-height</span><span class="token punctuation">:</span> 80<span class="token operator">%</span></span></code></pre>
<p id="code-skip-hello-day-33-3">And then I can fix the unit itself to the side of the content.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-33/#code-skip-hello-day-33-2" id="skip-to-code-skip-hello-day-33-2" class="skip-link">Skip code block ▼</a></p>
<pre class="language-sass"><code class="language-sass"><span class="token atrule-line"><span class="token atrule">@media</span> (min-width: variables.$ultra-large)</span><br /><span class="token property-line">    <span class="token property">position</span><span class="token punctuation">:</span> fixed</span><br /><span class="token property-line">    <span class="token property">top</span><span class="token punctuation">:</span> 10px</span><br /><span class="token property-line">    <span class="token property">left</span><span class="token punctuation">:</span> 1005px</span><br /><span class="token property-line">    <span class="token property">width</span><span class="token punctuation">:</span> 295px</span></code></pre>
<p id="code-skip-hello-day-33-2">Perfect and I put it below the left sidebar, so it'll prefer this new layout if the screen is large enough, even if there is enough height available on the screen.</p>
<p><a target="_blank" href="https://github.com/AramZS/devblog/commit/9b4cf1ddf51990e57461923aa104b766a224845a" class="git-commit-link"><code>git commit -am &quot;Fix up TOC for ultra wide screens&quot;</code></a></p>
<h3 id="continuing-to-muck-with-markdown-it" tabindex="-1">Continuing to muck with Markdown It</h3>
<p>Ok, now that I've got a lot of big stuff out of the way I'd really like to see if I can load in my own Markdown-It plugin. I've still not connected to the internet, so let's examine one of the simple plugins I've got in my <code>node_modules</code> to see if I can learn something from that. I'll try <code>markdown-it-todo</code> as it seems closest to some of the stuff I want to do.</p>
<p>Ok, promising choice! The code totals 68 lines.</p>
<p data-wordfix="true">I'm going to start real simple. I want to turn <code>11ty</code> into <code>Eleventy</code>. I can see I was working on this before. So let's put Eleventy into this blog post.</p>
<p>I'm actually currious, before I dive too deep into it, why the <code>markdown-it-regexp</code> library wasn't working when I tried it before. It looks like it is making some weird assumptions about what my regex should be, so I'm going to copy it local and see what happens if I change it a bit.</p>
<p>Ok, I fiddled with it and you know what? There is a lot of broken stuff. I'm not sure how it ever worked. I don't even see how it hooks into Markdown-it? Baffling. I'm going to drop it for real now I think it is too broken to save.</p>
<p>Ok, I'm sort of working blind from the example of the todo plugin but I've tried both that and a version of my previous work for creating <code>_blank</code> on links and neither are working.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-33/#code-skip-hello-day-33-1" id="skip-to-code-skip-hello-day-33-1" class="skip-link">Skip code block ▼</a></p>
<pre class="language-js"><code class="language-js"><span class="token string">"use strict"</span><span class="token punctuation">;</span><br /><br /><span class="token comment">/**<br />const Plugin = require("../markdown-it-regexp");<br /><br />module.exports = Plugin(/s11tys/g, (match, utils) => {<br />	console.log("Markdown It shorthand match", match);<br />	return String(` Eleventy `);<br />});<br /> */</span><br /><br /><span class="token keyword">const</span> <span class="token function-variable function">isInline</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">token</span><span class="token punctuation">)</span> <span class="token operator">=></span> token <span class="token operator">&amp;&amp;</span> token<span class="token punctuation">.</span>type <span class="token operator">===</span> <span class="token string">"inline"</span><span class="token punctuation">;</span><br /><span class="token keyword">const</span> <span class="token function-variable function">isParagraph</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">token</span><span class="token punctuation">)</span> <span class="token operator">=></span> token <span class="token operator">&amp;&amp;</span> token<span class="token punctuation">.</span>type <span class="token operator">===</span> <span class="token string">"paragraph_open"</span><span class="token punctuation">;</span><br /><span class="token keyword">const</span> <span class="token function-variable function">hasMyWords</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">token</span><span class="token punctuation">)</span> <span class="token operator">=></span><br />	token <span class="token operator">&amp;&amp;</span> <span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">^\[( 11ty | prob )]</span><span class="token regex-delimiter">/</span></span><span class="token punctuation">.</span><span class="token function">test</span><span class="token punctuation">(</span>token<span class="token punctuation">.</span>content<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br /><span class="token keyword">function</span> <span class="token function">setAttr</span><span class="token punctuation">(</span><span class="token parameter">token<span class="token punctuation">,</span> name<span class="token punctuation">,</span> value</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />	<span class="token keyword">const</span> index <span class="token operator">=</span> token<span class="token punctuation">.</span><span class="token function">attrIndex</span><span class="token punctuation">(</span>name<span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token keyword">const</span> attr <span class="token operator">=</span> <span class="token punctuation">[</span>name<span class="token punctuation">,</span> value<span class="token punctuation">]</span><span class="token punctuation">;</span><br /><br />	<span class="token keyword">if</span> <span class="token punctuation">(</span>index <span class="token operator">&lt;</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />		token<span class="token punctuation">.</span><span class="token function">attrPush</span><span class="token punctuation">(</span>attr<span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span><br />		token<span class="token punctuation">.</span>attrs<span class="token punctuation">[</span>index<span class="token punctuation">]</span> <span class="token operator">=</span> attr<span class="token punctuation">;</span><br />	<span class="token punctuation">}</span><br /><span class="token punctuation">}</span><br /><br /><span class="token keyword">function</span> <span class="token function">isMyWords</span><span class="token punctuation">(</span><span class="token parameter">tokens<span class="token punctuation">,</span> index</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />	<span class="token keyword">return</span> <span class="token punctuation">(</span><br />		<span class="token function">isInline</span><span class="token punctuation">(</span>tokens<span class="token punctuation">[</span>index<span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token operator">&amp;&amp;</span><br />		<span class="token comment">// isParagraph(tokens[index - 1]) &amp;&amp;</span><br />		<span class="token function">hasMyWords</span><span class="token punctuation">(</span>tokens<span class="token punctuation">[</span>index<span class="token punctuation">]</span><span class="token punctuation">)</span><br />	<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span><br /><br /><span class="token keyword">function</span> <span class="token function">fixMyWords</span><span class="token punctuation">(</span><span class="token parameter">token<span class="token punctuation">,</span> TokenConstructor</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />	<span class="token keyword">let</span> wordChoice <span class="token operator">=</span> <span class="token string">""</span><span class="token punctuation">;</span><br />	<span class="token keyword">const</span> betterWord <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">TokenConstructor</span><span class="token punctuation">(</span><span class="token string">"inline"</span><span class="token punctuation">,</span> <span class="token string">""</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex"> 11ty </span><span class="token regex-delimiter">/</span></span><span class="token punctuation">.</span><span class="token function">test</span><span class="token punctuation">(</span>token<span class="token punctuation">.</span>content<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />		betterWord<span class="token punctuation">.</span>content <span class="token operator">=</span> <span class="token string">" Eleventy "</span><span class="token punctuation">;</span><br />		wordChoice <span class="token operator">=</span> <span class="token string">" 11ty "</span><span class="token punctuation">;</span><br />	<span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex"> prob </span><span class="token regex-delimiter">/</span></span><span class="token punctuation">.</span><span class="token function">test</span><span class="token punctuation">(</span>token<span class="token punctuation">.</span>content<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />		betterWord<span class="token punctuation">.</span>content <span class="token operator">=</span> <span class="token string">" probably "</span><span class="token punctuation">;</span><br />		wordChoice <span class="token operator">=</span> <span class="token string">" prob "</span><span class="token punctuation">;</span><br />	<span class="token punctuation">}</span><br /><br />	<span class="token keyword">return</span> <span class="token punctuation">{</span> betterWord<span class="token punctuation">,</span> wordChoice <span class="token punctuation">}</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span><br /><br /><span class="token keyword">function</span> <span class="token function">fixWordify</span><span class="token punctuation">(</span><span class="token parameter">token<span class="token punctuation">,</span> TokenConstructor</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />	<span class="token keyword">const</span> <span class="token punctuation">{</span> betterWord<span class="token punctuation">,</span> wordChoice <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token function">fixMyWords</span><span class="token punctuation">(</span>token<span class="token punctuation">,</span> TokenConstructor<span class="token punctuation">)</span><span class="token punctuation">;</span><br />	token<span class="token punctuation">.</span>children<span class="token punctuation">.</span><span class="token function">unshift</span><span class="token punctuation">(</span>betterWord<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br />	<span class="token keyword">const</span> sliceIndex <span class="token operator">=</span> wordChoice<span class="token punctuation">.</span>length<span class="token punctuation">;</span><br />	token<span class="token punctuation">.</span>content <span class="token operator">=</span> token<span class="token punctuation">.</span>content<span class="token punctuation">.</span><span class="token function">slice</span><span class="token punctuation">(</span>sliceIndex<span class="token punctuation">)</span><span class="token punctuation">;</span><br />	token<span class="token punctuation">.</span>children<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">.</span>content <span class="token operator">=</span> token<span class="token punctuation">.</span>children<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">.</span>content<span class="token punctuation">.</span><span class="token function">slice</span><span class="token punctuation">(</span>sliceIndex<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span><br /><br />module<span class="token punctuation">.</span><span class="token function-variable function">exports</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">md</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />	md<span class="token punctuation">.</span>core<span class="token punctuation">.</span>ruler<span class="token punctuation">.</span><span class="token function">after</span><span class="token punctuation">(</span><span class="token string">"inline"</span><span class="token punctuation">,</span> <span class="token string">"evernote-todo"</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token parameter">state</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />		<span class="token keyword">const</span> tokens <span class="token operator">=</span> state<span class="token punctuation">.</span>tokens<span class="token punctuation">;</span><br />		console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">"Walking through possible words to fix2"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />		<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">let</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&lt;</span> tokens<span class="token punctuation">.</span>length<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />			<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">isMyWords</span><span class="token punctuation">(</span>tokens<span class="token punctuation">,</span> i<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />				console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">"Trying to fix some words!"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />				<span class="token function">fixMyWords</span><span class="token punctuation">(</span>tokens<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">,</span> state<span class="token punctuation">.</span>Token<span class="token punctuation">)</span><span class="token punctuation">;</span><br />				<span class="token function">setAttr</span><span class="token punctuation">(</span>tokens<span class="token punctuation">[</span>i <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token string">"data-wordfix"</span><span class="token punctuation">,</span> <span class="token string">"true"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />			<span class="token punctuation">}</span><br />		<span class="token punctuation">}</span><br />	<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span><span class="token punctuation">;</span><br /><br /><span class="token comment">/**<br />module.exports = (markdownSetup) => {<br />	var defaultRender =<br />		markdownSetup.renderer.rules.fix_my_words ||<br />		function (tokens, idx, options, env, self) {<br />			return self.renderToken(tokens, idx, options);<br />		};<br />	markdownSetup.renderer.rules.fix_my_words = function (<br />		tokens,<br />		idx,<br />		options,<br />		env,<br />		self<br />	) {<br />		for (let i = 0; i &lt; tokens.length; i++) {<br />			if (isMyWords(tokens, i)) {<br />				console.log("Trying to fix some words!");<br />				fixWordify(tokens[i], tokens);<br />				setAttr(tokens[i - 1], "data-wordfix", "true");<br />			}<br />		}<br /><br />		// pass token to default renderer.<br />		return defaultRender(tokens, idx, options, env, self);<br />	};<br />};<br />*/</span></code></pre>
<p id="code-skip-hello-day-33-1">I'm not even sure it is scanning the right stuff?! Time to do some logging.</p>
<p data-wordfix="true">It's especially annoying to test because I can't use Eleventy watch to reload the plugin and have it work consistently.</p>
<p>Ok so... <code>inline</code> is not the token type I need to target, it's just showing my little one-line code samples</p>
<p>Ok. It doesn't seem to be <code>inline</code> but I'm not sure what <code>paragraph_open</code> is and removing it has the plugin adding the <code> &quot;data-wordfix&quot;</code> property to the <code>p</code> tags properly. So progress!</p>
<p>Oops, I need to use <code>fixWordify</code>!</p>
<p>Ok, the todo plugin is just cutting the first few characters off the string. That's fine for it I guess, but I'm operating on the middle of the string. It looks like I may need to (from the code they have) change the content of both the <code>token.content</code> value and the <code>token.children[1].content</code> value? (Presumably because it <code>unshift</code>s the new token in to the beginning of that array, for some reason?) Well let's take it once at a time.</p>
<p>Hmmm, still no good. But I think I'm getting closer. Ok backs straight, tables in the upright position time.</p>
<p><a target="_blank" href="https://github.com/AramZS/devblog/commit/f7df50a19efdb36b4c15098670c08967f041dd78" class="git-commit-link"><code>git commit -am &quot;Save day 33&quot;</code></a></p>
]]></content:encoded>
	</item>
	
	<item>
		<title>Part 32: Project Pages and loops</title>
		<link>https://fightwithtools.dev/posts/projects/devblog/hello-day-32/?source=rss</link>
		<pubDate>Sat, 13 Nov 2021 02:59:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/projects/devblog/hello-day-32/</guid>
		<description>More devblog</description>
		<content:encoded><![CDATA[<h2 id="project-scope-and-todos" tabindex="-1">Project Scope and ToDos</h2>
<ol>
<li>Static Site Generator that can build the blog and let me host it on Github Pages</li>
<li>I want to write posts in Markdown because I'm lazy, it's easy, and it is how I take notes now.</li>
<li>I don't want to spend a ton of time doing design work. I'm doing complicated designs for other projects, so I want to pull a theme I like that I can rely on someone else to keep up.</li>
<li>Once it gets going, I want template changes to be easy.</li>
<li>It should be as easy as Jekyll, so I need to be able to build it using GitHub Actions, where I can just commit a template change or Markdown file and away it goes. If I can't figure this out than fk it, just use Jekyll.</li>
<li>I require it to be used by a significant percent of my professional peers so I can get easy answers when something goes wrong.</li>
<li>I want source maps. This is a dev log site which means whatever I do with it should be easy for other developers to read.</li>
</ol>
<ul class="task-list">
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Also <a href="https://www.npmjs.com/package/@quasibit/eleventy-plugin-sitemap" target="_blank">the sitemap plugin</a> looks cool. Should grab that later.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> So does the <a href="https://www.npmjs.com/package/eleventy-plugin-reading-time" target="_blank">reading time one</a>.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Also <a href="https://github.com/jdsteinbach/eleventy-plugin-toc/" target="_blank">this TOC plugin</a> mby?</p>
</li>
<li class="task-list-item">
<p data-wordfix="true"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Use <a href="https://www.11ty.dev/docs/data-deep-merge/" target="_blank">Data Deep Merge</a> in this blog.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Decide if I want to render the CSS fancier than just a base file and do per-template splitting.</p>
</li>
</ul>
<s>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Can I use the template inside of dinky that already exists instead of copy/pasting it?</li>
</ul>
</s>
<s>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Is there a way to have permalinks to posts contain metadata without organizing them into subfolders?</li>
</ul>
</s>
<ul class="task-list">
<li class="task-list-item">
<p data-wordfix="true"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> How do I cachebreak files on the basis of new build events? Datetime? <code>site.github.build_revision</code> is <a href="https://github.com/jekyll/github-metadata/blob/master/docs/site.github.md" target="_blank">how Jekyll accomplishes this</a>, but is there a way to push <a href="https://docs.github.com/en/actions/reference/context-and-expression-syntax-for-github-actions#github-context" target="_blank">that</a> <a href="https://stackoverflow.com/questions/54310050/how-to-version-build-artifacts-using-github-actions" target="_blank">into the build process</a> for Eleventy?</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Make link text look less shitty. It looks like it is a whole, lighter, font.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Code blocks do not have good syntax highlighting. I want good syntax highlighting.</p>
</li>
<li class="task-list-item">
<p data-wordfix="true"><input disabled="true" type="checkbox" class="markdown-todo" /> Build a Markdown-it plugin to take my typing shortcuts <code>[prob, b/c, ...?]</code> and expand them on build.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> See if we can start Markdown's interpretation of H tags to <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/Heading_Elements#multiple_h1" target="_blank">start at 2, since H1</a> is always pulled from the page title metadata. If it isn't easy, I just have to change my pattern of writing in the MD documents.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Should I <a href="https://www.madebymike.com.au/writing/11ty-filters-data-shortcodes/" target="_blank">explore some shortcodes</a>?</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Order projects listing by last posted blog in that project</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Limit the output of home page post lists to a specific number of posts</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Show the latest post below the site intro on the homepage.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Tags pages with Pagination</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Posts should be able to support a preview header image that can also be shown on post lists.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Create a Markdown-It plugin that reads the project's repo URL off the folder data file and renders commit messages with <a href="https://stackoverflow.com/questions/15919635/on-github-api-what-is-the-best-way-to-get-the-last-commit-message-associated-w" target="_blank">links to the referenced commit</a>. (Is this even possible?) (Is there a way to do it with eleventy instead?)</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Create Next Day/Previous Day links on each post / Next/Previous post on post templates from projects</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Tags should be in the sidebar of articles and link to tag pages</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Create a skiplink for the todo section (or would this be better served with the ToC plugin?) - Yes it would be!</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Add a Things I Learned section to the project pages that are the things I learned from that specific project.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Add a technical reading log to the homepage</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/:empty" target="_blank">Hide</a> empty sections.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Add byline to post pages</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Have table of contents attach to sidebar bottom on mobile</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Support dark mode</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Social Icons</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> SEO/Social/JSON-LD HEAD data</p>
</li>
</ul>
<h2 id="day-32" tabindex="-1">Day 32</h2>
<h3 id="projects-page" tabindex="-1">Projects Page</h3>
<p>I realized that at some point I'm going to have too many projects to fit on the home page, so I <a href="https://github.com/AramZS/devblog/issues/4" target="_blank">need to limit the number that show up and set up a page to list the overall projects</a>.</p>
<p>I want it to sit at <code>/projects</code> so I'll create a MD file to handle that and a template to handle this specific page type.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-32/#code-skip-hello-day-32-3" id="skip-to-code-skip-hello-day-32-3" class="skip-link">Skip code block ▼</a></p>
<pre class="language-yaml"><code class="language-yaml"><span class="token punctuation">---</span><br /><span class="token key atrule">layout</span><span class="token punctuation">:</span> project<span class="token punctuation">-</span>list<br /><span class="token key atrule">pagination</span><span class="token punctuation">:</span><br />    <span class="token key atrule">data</span><span class="token punctuation">:</span> projects<br />    <span class="token key atrule">size</span><span class="token punctuation">:</span> <span class="token number">1</span><br />    <span class="token key atrule">alias</span><span class="token punctuation">:</span> project<br /><span class="token key atrule">permalink</span><span class="token punctuation">:</span> <span class="token string">"projects/"</span><br /><span class="token key atrule">eleventyComputed</span><span class="token punctuation">:</span><br />  <span class="token key atrule">title</span><span class="token punctuation">:</span> <span class="token string">"Project List"</span><br />  <span class="token key atrule">description</span><span class="token punctuation">:</span> <span class="token string">"A list of projects that Aram Zucker-Scharff has documented working on."</span><br /><span class="token punctuation">---</span></code></pre>
<p id="code-skip-hello-day-32-3">I'll start with the project page as the template. Then I can take the loop through the projects object from the front page.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-32/#code-skip-hello-day-32-2" id="skip-to-code-skip-hello-day-32-2" class="skip-link">Skip code block ▼</a></p>
<pre class="language-liquid"><code class="language-liquid">				{%<span class="token templateTag"> <span class="token keyword">for</span> project <span class="token keyword">in</span> projects </span>%}<br />					<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>li</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>capitalize-first<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><br />						<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>{{project.url}}<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>{{project.title}}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>a</span><span class="token punctuation">></span></span> | <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span><span class="token punctuation">></span></span>Days worked: {{project.count}}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">></span></span> | <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span><span class="token punctuation">></span></span>Status: {{project.complete}}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">></span></span> <span class="token comment">&lt;!-- last updated:  {{project.lastUpdatedPost}} --></span><br />					<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>li</span><span class="token punctuation">></span></span><br />				{%<span class="token templateTag"> endfor </span>%}</code></pre>
<p id="code-skip-hello-day-32-2">Ok this is good. To make this easy to debug I should put the link on the front page. So to do that I need to do two things, break the project <code>for</code> loop, and add a link to the new projects page.</p>
<p>Hmm, <a href="https://github.com/mozilla/nunjucks/issues/296" target="_blank">it doesn't look like there is actually a <code>break</code> in Nunjucks</a>. Perhaps I should try altering the array?</p>
<p>Can I use an if check like <code> if loop.index &lt; 6</code> in the for statement? No that doesn't work. Looks like the <code>if</code> check <a href="https://stackoverflow.com/questions/22150273/how-can-i-break-a-for-loop-in-jinja2" target="_blank">is only for properties of the looped object</a>.</p>
<p>Ah, no, that's not it at all. That doesn't work. Ah, ok, the best thing to do here is to slice the array before looping it. Instead of a <code>break</code> for this situation, we use slice.</p>
<p><code>for project in projects | slice(5)</code></p>
<p>Yup, that worked!</p>
<p>And I'll remove the dots on the li elements.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-32/#code-skip-hello-day-32-1" id="skip-to-code-skip-hello-day-32-1" class="skip-link">Skip code block ▼</a></p>
<pre class="language-css"><code class="language-css">    #all-projects<br />        li<br />            <span class="token property">list-style</span><span class="token punctuation">:</span> none</code></pre>
<p id="code-skip-hello-day-32-1">Ok, did a little touching up of the formatting, and now we've got that page. Good to go.</p>
<h3 id="preview-images-on-lists" tabindex="-1">Preview Images on Lists</h3>
<p>Ok, next thing I wanted to check off is including the image on some of the post preview pages. Let's start with the tag pages.</p>
<p>First I'll set up a stand-alone Sass file for the post preview component. Then I'll add a containing class to the post-summary component itself.</p>
<p>Then I'm going to pull the post image HTML out of <code>post.njk</code> and into its own file in the <code>partials</code> folder. This way I can reuse the basic HTML structure of the image across the site.</p>
<p>Ok, had to make sure my styles are in place but it looks good. I may want to modify the styles a little bit, it isn't perfect and I may want to play with it a bit.</p>
<p>Now I want to add it to the front page as well. But I'll save that until the next day of working on this project.</p>
<p><a target="_blank" href="https://github.com/AramZS/devblog/commit/b0db043f14feb1ef6f9f00cad61e2fedcac6e958" class="git-commit-link"><code>git commit -am &quot;Finishing off day 32&quot;</code></a></p>
]]></content:encoded>
	</item>
	
	<item>
		<title>Part 31: Pagination</title>
		<link>https://fightwithtools.dev/posts/projects/devblog/hello-day-31/?source=rss</link>
		<pubDate>Sat, 13 Nov 2021 02:59:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/projects/devblog/hello-day-31/</guid>
		<description>More devblog</description>
		<content:encoded><![CDATA[<h2 id="project-scope-and-todos" tabindex="-1">Project Scope and ToDos</h2>
<ol>
<li>Static Site Generator that can build the blog and let me host it on Github Pages</li>
<li>I want to write posts in Markdown because I'm lazy, it's easy, and it is how I take notes now.</li>
<li>I don't want to spend a ton of time doing design work. I'm doing complicated designs for other projects, so I want to pull a theme I like that I can rely on someone else to keep up.</li>
<li>Once it gets going, I want template changes to be easy.</li>
<li>It should be as easy as Jekyll, so I need to be able to build it using GitHub Actions, where I can just commit a template change or Markdown file and away it goes. If I can't figure this out than fk it, just use Jekyll.</li>
<li>I require it to be used by a significant percent of my professional peers so I can get easy answers when something goes wrong.</li>
<li>I want source maps. This is a dev log site which means whatever I do with it should be easy for other developers to read.</li>
</ol>
<ul class="task-list">
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Also <a href="https://www.npmjs.com/package/@quasibit/eleventy-plugin-sitemap" target="_blank">the sitemap plugin</a> looks cool. Should grab that later.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> So does the <a href="https://www.npmjs.com/package/eleventy-plugin-reading-time" target="_blank">reading time one</a>.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Also <a href="https://github.com/jdsteinbach/eleventy-plugin-toc/" target="_blank">this TOC plugin</a> mby?</p>
</li>
<li class="task-list-item">
<p data-wordfix="true"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Use <a href="https://www.11ty.dev/docs/data-deep-merge/" target="_blank">Data Deep Merge</a> in this blog.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Decide if I want to render the CSS fancier than just a base file and do per-template splitting.</p>
</li>
</ul>
<s>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Can I use the template inside of dinky that already exists instead of copy/pasting it?</li>
</ul>
</s>
<s>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Is there a way to have permalinks to posts contain metadata without organizing them into subfolders?</li>
</ul>
</s>
<ul class="task-list">
<li class="task-list-item">
<p data-wordfix="true"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> How do I cachebreak files on the basis of new build events? Datetime? <code>site.github.build_revision</code> is <a href="https://github.com/jekyll/github-metadata/blob/master/docs/site.github.md" target="_blank">how Jekyll accomplishes this</a>, but is there a way to push <a href="https://docs.github.com/en/actions/reference/context-and-expression-syntax-for-github-actions#github-context" target="_blank">that</a> <a href="https://stackoverflow.com/questions/54310050/how-to-version-build-artifacts-using-github-actions" target="_blank">into the build process</a> for Eleventy?</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Make link text look less shitty. It looks like it is a whole, lighter, font.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Code blocks do not have good syntax highlighting. I want good syntax highlighting.</p>
</li>
<li class="task-list-item">
<p data-wordfix="true"><input disabled="true" type="checkbox" class="markdown-todo" /> Build a Markdown-it plugin to take my typing shortcuts <code>[prob, b/c, ...?]</code> and expand them on build.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> See if we can start Markdown's interpretation of H tags to <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/Heading_Elements#multiple_h1" target="_blank">start at 2, since H1</a> is always pulled from the page title metadata. If it isn't easy, I just have to change my pattern of writing in the MD documents.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Should I <a href="https://www.madebymike.com.au/writing/11ty-filters-data-shortcodes/" target="_blank">explore some shortcodes</a>?</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Order projects listing by last posted blog in that project</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Limit the output of home page post lists to a specific number of posts</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Show the latest post below the site intro on the homepage.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Tags pages with Pagination</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Posts should be able to support a preview header image that can also be shown on post lists.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Create a Markdown-It plugin that reads the project's repo URL off the folder data file and renders commit messages with <a href="https://stackoverflow.com/questions/15919635/on-github-api-what-is-the-best-way-to-get-the-last-commit-message-associated-w" target="_blank">links to the referenced commit</a>. (Is this even possible?) (Is there a way to do it with eleventy instead?)</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Create Next Day/Previous Day links on each post / Next/Previous post on post templates from projects</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Tags should be in the sidebar of articles and link to tag pages</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Create a skiplink for the todo section (or would this be better served with the ToC plugin?) - Yes it would be!</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Add a Things I Learned section to the project pages that are the things I learned from that specific project.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Add a technical reading log to the homepage</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/:empty" target="_blank">Hide</a> empty sections.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Add byline to post pages</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Have table of contents attach to sidebar bottom on mobile</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Support dark mode</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Social Icons</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> SEO/Social/JSON-LD HEAD data</p>
</li>
</ul>
<h2 id="day-31" tabindex="-1">Day 31</h2>
<p>Looking good!</p>
<h3 id="setting-up-previous-and-next-project-post-pages." tabindex="-1">Setting up previous and next project post pages.</h3>
<p data-wordfix="true">Ok, today we're going to try next and previous pages. Apparently there are <a href="https://www.11ty.dev/docs/filters/collection-items/" target="_blank">universal filters built in to Eleventy that we can use to find previous and next posts</a>. Let's give it a try.</p>
<p>Ok, the default set up is for a general posts collection, but what I need is the project collection. But first I'm going to make sure it works in the standard configuration. I can pull the styling in from the work I did on tag pages.</p>
<p><a target="_blank" href="https://github.com/AramZS/devblog/commit/46e7421d752e035f307b0280fb695790160c1f2f" class="git-commit-link"><code>git commit -am &quot;Basic post pagination&quot;</code></a></p>
<p>Ok, figuring out the collection time.</p>
<p>Judging from my work back on days 10 and 11 I don't think there's a really good way to do so just within the Nunjucks template. I guess I'll need a custom shortcode. I can use the <code>projectList</code> shortcode again and see if I can't pull some useful code out of the <code>getPreviousCollectionItem</code> function <a href="https://github.com/11ty/eleventy/blob/36713b3af81b08530fac532ceef24f5dde8acb36/src/defaultConfig.js#L25" target="_blank">built into 11ty</a>.</p>
<p data-wordfix="true">Ok, so I want to use the same function that is being referred to in Eleventy. I'll pull it in</p>
<p><code>const getCollectionItem = require(&quot;@11ty/eleventy/src/Filters/GetCollectionItem&quot;);</code></p>
<p data-wordfix="true">Ok, unlike before, this should be a filter if I want to duplicate the functionality in Eleventy core.</p>
<h4 id="create-the-filter-tag" tabindex="-1">Create the Filter tag</h4>
<p>I gotta remember that the <code>page</code> object is very specific. I had to log it to remember how the object worked.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-31/#code-skip-hello-day-31-8" id="skip-to-code-skip-hello-day-31-8" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript"><span class="token punctuation">{</span><br />  <span class="token literal-property property">date</span><span class="token operator">:</span> <span class="token number">2021</span><span class="token operator">-</span><span class="token number">06</span><span class="token operator">-</span>16T03<span class="token operator">:</span><span class="token number">59</span><span class="token operator">:</span><span class="token number">43</span><span class="token punctuation">.</span>100Z<span class="token punctuation">,</span><br />  <span class="token literal-property property">inputPath</span><span class="token operator">:</span> <span class="token string">'./src/posts/projects/devblog/hello-day-4.md'</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">fileSlug</span><span class="token operator">:</span> <span class="token string">'hello-day-4'</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">filePathStem</span><span class="token operator">:</span> <span class="token string">'/posts/projects/devblog/hello-day-4'</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">url</span><span class="token operator">:</span> <span class="token string">'/posts/projects/devblog/hello-day-4/'</span><span class="token punctuation">,</span><br />  <span class="token literal-property property">outputPath</span><span class="token operator">:</span> <span class="token string">'docs/posts/projects/devblog/hello-day-4/index.html'</span><br /><span class="token punctuation">}</span></code></pre>
<p id="code-skip-hello-day-31-8">So no project property. The project proprty of the post is escaped into its own variable in the page template</p>
<p>So now the template calls the filter like:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-31/#code-skip-hello-day-31-7" id="skip-to-code-skip-hello-day-31-7" class="skip-link">Skip code block ▼</a></p>
<pre class="language-liquid"><code class="language-liquid">	{%<span class="token templateTag"> <span class="token keyword">set</span> previousPost <span class="token operator">=</span> collections<span class="token punctuation">.</span>posts <span class="token operator">|</span> <span class="token function">getPreviousProjectItem</span><span class="token punctuation">(</span>page<span class="token punctuation">,</span> project<span class="token punctuation">)</span> </span>%}<br />	{%<span class="token templateTag"> <span class="token keyword">set</span> nextPost <span class="token operator">=</span> collections<span class="token punctuation">.</span>posts <span class="token operator">|</span> <span class="token function">getNextProjectItem</span><span class="token punctuation">(</span>page<span class="token punctuation">,</span> project<span class="token punctuation">)</span> </span>%}</code></pre>
<p id="code-skip-hello-day-31-7">Ok so now I have passed into the function the posts collection, the page object and the project name. Now to set up a function to walk through the posts collection and find the right post that is a project post and this project's post in particular.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-31/#code-skip-hello-day-31-6" id="skip-to-code-skip-hello-day-31-6" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript">eleventyConfig<span class="token punctuation">.</span><span class="token function">addFilter</span><span class="token punctuation">(</span><br />		<span class="token string">"getPreviousProjectItem"</span><span class="token punctuation">,</span><br />		<span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">collection<span class="token punctuation">,</span> page<span class="token punctuation">,</span> project</span><span class="token punctuation">)</span><span class="token punctuation">{</span><br />			<span class="token keyword">let</span> index <span class="token operator">=</span> <span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">;</span><br />			<span class="token keyword">let</span> found <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">;</span><br />			<span class="token keyword">if</span> <span class="token punctuation">(</span>project<span class="token punctuation">)</span><span class="token punctuation">{</span><br />				<span class="token keyword">let</span> lastPost<span class="token punctuation">;</span><br />				<span class="token keyword">while</span> <span class="token punctuation">(</span>found <span class="token operator">===</span> <span class="token boolean">false</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />					lastPost <span class="token operator">=</span> <span class="token function">getCollectionItem</span><span class="token punctuation">(</span>collection<span class="token punctuation">,</span> page<span class="token punctuation">,</span> index<span class="token punctuation">)</span><br />					<span class="token keyword">if</span> <span class="token punctuation">(</span>lastPost<span class="token punctuation">.</span>data<span class="token punctuation">.</span><span class="token function">hasOwnProperty</span><span class="token punctuation">(</span><span class="token string">"project"</span><span class="token punctuation">)</span> <span class="token operator">&amp;&amp;</span> lastPost<span class="token punctuation">.</span>data<span class="token punctuation">.</span>project <span class="token operator">==</span> project<span class="token punctuation">)</span><span class="token punctuation">{</span><br />						found <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">;</span><br />					<span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span><br />						index <span class="token operator">=</span> index<span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">;</span><br />					<span class="token punctuation">}</span><br />				<span class="token punctuation">}</span><br />				<span class="token keyword">return</span> lastPost<span class="token punctuation">;</span><br />			<span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span><br />				<span class="token keyword">return</span> <span class="token boolean">false</span><span class="token punctuation">;</span><br />			<span class="token punctuation">}</span><br /><br />		<span class="token punctuation">}</span><br />	<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p id="code-skip-hello-day-31-6">Ok, I want to simplify it. But also, I am seeing one issue. Gotta check that the post exists, otherwise the first and last page will crash. Ok, let's fix that first.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-31/#code-skip-hello-day-31-5" id="skip-to-code-skip-hello-day-31-5" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript">	eleventyConfig<span class="token punctuation">.</span><span class="token function">addFilter</span><span class="token punctuation">(</span><br />		<span class="token string">"getNextProjectItem"</span><span class="token punctuation">,</span><br />		<span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">collection<span class="token punctuation">,</span> page<span class="token punctuation">,</span> project</span><span class="token punctuation">)</span><span class="token punctuation">{</span><br />			<span class="token keyword">let</span> index <span class="token operator">=</span> <span class="token number">1</span><span class="token punctuation">;</span><br />			<span class="token keyword">let</span> found <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">;</span><br />			<span class="token keyword">if</span> <span class="token punctuation">(</span>project<span class="token punctuation">)</span><span class="token punctuation">{</span><br />				<span class="token keyword">let</span> lastPost<span class="token punctuation">;</span><br />				<span class="token keyword">while</span> <span class="token punctuation">(</span>found <span class="token operator">===</span> <span class="token boolean">false</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />					lastPost <span class="token operator">=</span> <span class="token function">getCollectionItem</span><span class="token punctuation">(</span>collection<span class="token punctuation">,</span> page<span class="token punctuation">,</span> index<span class="token punctuation">)</span><br />					<span class="token keyword">if</span> <span class="token punctuation">(</span>lastPost <span class="token operator">&amp;&amp;</span> lastPost<span class="token punctuation">.</span>data<span class="token punctuation">.</span><span class="token function">hasOwnProperty</span><span class="token punctuation">(</span><span class="token string">"project"</span><span class="token punctuation">)</span> <span class="token operator">&amp;&amp;</span> lastPost<span class="token punctuation">.</span>data<span class="token punctuation">.</span>project <span class="token operator">==</span> project<span class="token punctuation">)</span><span class="token punctuation">{</span><br />						found <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">;</span><br />					<span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span><br />						<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>lastPost<span class="token punctuation">)</span><span class="token punctuation">{</span><br />							<span class="token keyword">return</span> <span class="token boolean">false</span><span class="token punctuation">;</span><br />						<span class="token punctuation">}</span><br />						index <span class="token operator">=</span> index<span class="token operator">+</span><span class="token number">1</span><span class="token punctuation">;</span><br />					<span class="token punctuation">}</span><br />				<span class="token punctuation">}</span><br />				<span class="token keyword">return</span> lastPost<span class="token punctuation">;</span><br />			<span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span><br />				<span class="token keyword">return</span> <span class="token boolean">false</span><span class="token punctuation">;</span><br />			<span class="token punctuation">}</span><br />		<span class="token punctuation">}</span><br />	<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<h4 id="simplify-the-while-loop" tabindex="-1">Simplify the While loop</h4>
<p id="code-skip-hello-day-31-5">Ok, let's pull out the function, make it repeatable.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-31/#code-skip-hello-day-31-4" id="skip-to-code-skip-hello-day-31-4" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript">	<span class="token keyword">function</span> <span class="token function">getNProjectItem</span><span class="token punctuation">(</span><span class="token parameter">collection<span class="token punctuation">,</span> page<span class="token punctuation">,</span> projectName<span class="token punctuation">,</span> index<span class="token punctuation">,</span> operation</span><span class="token punctuation">)</span><span class="token punctuation">{</span><br />		<span class="token keyword">let</span> found <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">;</span><br />		<span class="token keyword">if</span> <span class="token punctuation">(</span>projectName<span class="token punctuation">)</span><span class="token punctuation">{</span><br />			<span class="token keyword">let</span> lastPost<span class="token punctuation">;</span><br />			<span class="token keyword">while</span> <span class="token punctuation">(</span>found <span class="token operator">===</span> <span class="token boolean">false</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />				lastPost <span class="token operator">=</span> <span class="token function">getCollectionItem</span><span class="token punctuation">(</span>collection<span class="token punctuation">,</span> page<span class="token punctuation">,</span> index<span class="token punctuation">)</span><br />				<span class="token keyword">if</span> <span class="token punctuation">(</span>lastPost <span class="token operator">&amp;&amp;</span> lastPost<span class="token punctuation">.</span>data<span class="token punctuation">.</span><span class="token function">hasOwnProperty</span><span class="token punctuation">(</span><span class="token string">"project"</span><span class="token punctuation">)</span> <span class="token operator">&amp;&amp;</span> lastPost<span class="token punctuation">.</span>data<span class="token punctuation">.</span>project <span class="token operator">==</span> projectName<span class="token punctuation">)</span><span class="token punctuation">{</span><br />					found <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">;</span><br />				<span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span><br />					<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>lastPost<span class="token punctuation">)</span><span class="token punctuation">{</span><br />						<span class="token keyword">return</span> <span class="token boolean">false</span><span class="token punctuation">;</span><br />					<span class="token punctuation">}</span><br />					index <span class="token operator">=</span> <span class="token function">operation</span><span class="token punctuation">(</span>index<span class="token punctuation">)</span><span class="token punctuation">;</span><br />				<span class="token punctuation">}</span><br />			<span class="token punctuation">}</span><br />			<span class="token keyword">return</span> lastPost<span class="token punctuation">;</span><br />		<span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span><br />			<span class="token keyword">return</span> <span class="token boolean">false</span><span class="token punctuation">;</span><br />		<span class="token punctuation">}</span><br />	<span class="token punctuation">}</span></code></pre>
<p id="code-skip-hello-day-31-4">Now my filter call looks like this.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-31/#code-skip-hello-day-31-3" id="skip-to-code-skip-hello-day-31-3" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript">	eleventyConfig<span class="token punctuation">.</span><span class="token function">addFilter</span><span class="token punctuation">(</span><br />		<span class="token string">"getPreviousProjectItem"</span><span class="token punctuation">,</span><br />		<span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">collection<span class="token punctuation">,</span> page<span class="token punctuation">,</span> project</span><span class="token punctuation">)</span><span class="token punctuation">{</span><br />			<span class="token keyword">let</span> index <span class="token operator">=</span> <span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">;</span><br />			<span class="token keyword">return</span> <span class="token function">getNProjectItem</span><span class="token punctuation">(</span>collection<span class="token punctuation">,</span> page<span class="token punctuation">,</span> project<span class="token punctuation">,</span> index<span class="token punctuation">,</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">i</span><span class="token punctuation">)</span><span class="token punctuation">{</span><span class="token keyword">return</span> i<span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
<p id="code-skip-hello-day-31-3">Ok, there's one other thing I need. I need to exclude the &quot;Things I Learned&quot; posts.</p>
<p>I have the check for them now, the <code>wrapup</code> property.</p>
<p>That means the check now looks like this:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-31/#code-skip-hello-day-31-2" id="skip-to-code-skip-hello-day-31-2" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">if</span> <span class="token punctuation">(</span><br />	lastPost <span class="token operator">&amp;&amp;</span><br />	lastPost<span class="token punctuation">.</span>data<span class="token punctuation">.</span><span class="token function">hasOwnProperty</span><span class="token punctuation">(</span><span class="token string">"project"</span><span class="token punctuation">)</span> <span class="token operator">&amp;&amp;</span><br />	lastPost<span class="token punctuation">.</span>data<span class="token punctuation">.</span>project <span class="token operator">==</span> projectName <span class="token operator">&amp;&amp;</span><br />	<span class="token operator">!</span>lastPost<span class="token punctuation">.</span>data<span class="token punctuation">.</span><span class="token function">hasOwnProperty</span><span class="token punctuation">(</span><span class="token string">'wrapup'</span><span class="token punctuation">)</span><br /><span class="token punctuation">)</span><span class="token punctuation">{</span></code></pre>
<p id="code-skip-hello-day-31-2">Ok it's looking good!</p>
<p><a target="_blank" href="https://github.com/AramZS/devblog/commit/0c62e6ab21d2556e2bcd3df554e3342ad5dfc7e9" class="git-commit-link"><code>git commit -am &quot;Setting up in-post pagination for projects&quot;</code></a></p>
<p>Ok, clean up time. Oh and I should make sure this is only for project work days, so an <code>if</code> check for that in the template.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-31/#code-skip-hello-day-31-1" id="skip-to-code-skip-hello-day-31-1" class="skip-link">Skip code block ▼</a></p>
<pre class="language-liquid"><code class="language-liquid">    {%<span class="token templateTag"> <span class="token keyword">if</span> project and not wrapup </span>%}<br />        {%<span class="token templateTag"> <span class="token keyword">set</span> previousPost <span class="token operator">=</span> collections<span class="token punctuation">.</span>posts <span class="token operator">|</span> <span class="token function">getPreviousProjectItem</span><span class="token punctuation">(</span>page<span class="token punctuation">,</span> project<span class="token punctuation">)</span> </span>%}<br />        {%<span class="token templateTag"> <span class="token keyword">set</span> nextPost <span class="token operator">=</span> collections<span class="token punctuation">.</span>posts <span class="token operator">|</span> <span class="token function">getNextProjectItem</span><span class="token punctuation">(</span>page<span class="token punctuation">,</span> project<span class="token punctuation">)</span> </span>%}<br />        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>pagination<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><br />            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>{% if previousPost %}{{ previousPost.url }}{% else %}javascript:void(0){% endif %}<span class="token punctuation">"</span></span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>pagination-link {% if previousPost %}cursor-pointer {% else %} cursor-default disabled-link{% endif %}<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Previous Project Days<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>a</span><span class="token punctuation">></span></span><br /><br />            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>{% if nextPost %}{{ nextPost.url }}{% else %}javascript:void(0){% endif %}<span class="token punctuation">"</span></span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>pagination-link {% if nextPost %}cursor-pointer {% else %} disabled-link cursor-default{% endif %}<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Next Project Day<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>a</span><span class="token punctuation">></span></span><br />        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span><br />    {%<span class="token templateTag"> endif </span>%}</code></pre>
<p id="code-skip-hello-day-31-1">Ok, looking good. One more thing to check off the list!</p>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Create Next Day/Previous Day links on each post / Next/Previous post on post templates from projects</li>
</ul>
<p><a target="_blank" href="https://github.com/AramZS/devblog/commit/b0f64c92e21f230ee13692a99e347f0eed5678da" class="git-commit-link"><code>git commit -am &quot;Finish off day 31&quot;</code></a></p>
]]></content:encoded>
	</item>
	
	<item>
		<title>Part 30: Learning how to do Things I Learned</title>
		<link>https://fightwithtools.dev/posts/projects/devblog/hello-day-30/?source=rss</link>
		<pubDate>Sat, 13 Nov 2021 02:59:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/projects/devblog/hello-day-30/</guid>
		<description>More devblog</description>
		<content:encoded><![CDATA[<h2 id="project-scope-and-todos" tabindex="-1">Project Scope and ToDos</h2>
<ol>
<li>Static Site Generator that can build the blog and let me host it on Github Pages</li>
<li>I want to write posts in Markdown because I'm lazy, it's easy, and it is how I take notes now.</li>
<li>I don't want to spend a ton of time doing design work. I'm doing complicated designs for other projects, so I want to pull a theme I like that I can rely on someone else to keep up.</li>
<li>Once it gets going, I want template changes to be easy.</li>
<li>It should be as easy as Jekyll, so I need to be able to build it using GitHub Actions, where I can just commit a template change or Markdown file and away it goes. If I can't figure this out than fk it, just use Jekyll.</li>
<li>I require it to be used by a significant percent of my professional peers so I can get easy answers when something goes wrong.</li>
<li>I want source maps. This is a dev log site which means whatever I do with it should be easy for other developers to read.</li>
</ol>
<ul class="task-list">
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Also <a href="https://www.npmjs.com/package/@quasibit/eleventy-plugin-sitemap" target="_blank">the sitemap plugin</a> looks cool. Should grab that later.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> So does the <a href="https://www.npmjs.com/package/eleventy-plugin-reading-time" target="_blank">reading time one</a>.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Also <a href="https://github.com/jdsteinbach/eleventy-plugin-toc/" target="_blank">this TOC plugin</a> mby?</p>
</li>
<li class="task-list-item">
<p data-wordfix="true"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Use <a href="https://www.11ty.dev/docs/data-deep-merge/" target="_blank">Data Deep Merge</a> in this blog.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Decide if I want to render the CSS fancier than just a base file and do per-template splitting.</p>
</li>
</ul>
<s>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Can I use the template inside of dinky that already exists instead of copy/pasting it?</li>
</ul>
</s>
<s>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Is there a way to have permalinks to posts contain metadata without organizing them into subfolders?</li>
</ul>
</s>
<ul class="task-list">
<li class="task-list-item">
<p data-wordfix="true"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> How do I cachebreak files on the basis of new build events? Datetime? <code>site.github.build_revision</code> is <a href="https://github.com/jekyll/github-metadata/blob/master/docs/site.github.md" target="_blank">how Jekyll accomplishes this</a>, but is there a way to push <a href="https://docs.github.com/en/actions/reference/context-and-expression-syntax-for-github-actions#github-context" target="_blank">that</a> <a href="https://stackoverflow.com/questions/54310050/how-to-version-build-artifacts-using-github-actions" target="_blank">into the build process</a> for Eleventy?</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Make link text look less shitty. It looks like it is a whole, lighter, font.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Code blocks do not have good syntax highlighting. I want good syntax highlighting.</p>
</li>
<li class="task-list-item">
<p data-wordfix="true"><input disabled="true" type="checkbox" class="markdown-todo" /> Build a Markdown-it plugin to take my typing shortcuts <code>[prob, b/c, ...?]</code> and expand them on build.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> See if we can start Markdown's interpretation of H tags to <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/Heading_Elements#multiple_h1" target="_blank">start at 2, since H1</a> is always pulled from the page title metadata. If it isn't easy, I just have to change my pattern of writing in the MD documents.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Should I <a href="https://www.madebymike.com.au/writing/11ty-filters-data-shortcodes/" target="_blank">explore some shortcodes</a>?</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Order projects listing by last posted blog in that project</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Limit the output of home page post lists to a specific number of posts</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Show the latest post below the site intro on the homepage.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Tags pages with Pagination</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Posts should be able to support a preview header image that can also be shown on post lists.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Create a Markdown-It plugin that reads the project's repo URL off the folder data file and renders commit messages with <a href="https://stackoverflow.com/questions/15919635/on-github-api-what-is-the-best-way-to-get-the-last-commit-message-associated-w" target="_blank">links to the referenced commit</a>. (Is this even possible?) (Is there a way to do it with eleventy instead?)</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Create Next Day/Previous Day links on each post / Next/Previous post on post templates from projects</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Tags should be in the sidebar of articles and link to tag pages</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Create a skiplink for the todo section (or would this be better served with the ToC plugin?) - Yes it would be!</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Add a Things I Learned section to the project pages that are the things I learned from that specific project.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Add a technical reading log to the homepage</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/:empty" target="_blank">Hide</a> empty sections.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Add byline to post pages</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Have table of contents attach to sidebar bottom on mobile</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Support dark mode</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Social Icons</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> SEO/Social/JSON-LD HEAD data</p>
</li>
</ul>
<h2 id="day-30" tabindex="-1">Day 30</h2>
<p>Ok, day 30. Pretty big benchmark and it looks like I'm getting close to being done.</p>
<p>Let's check a small one off the list first and hide the empties.</p>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/:empty" target="_blank">Hide</a> empty sections.</li>
</ul>
<h3 id="adding-things-i-learned-to-the-project-page" tabindex="-1">Adding Things I Learned to the Project Page</h3>
<p>I am going to want to create some boxes if I want to set up Things I Learned on the project pages. That's going to mean collapsing some boxes too.</p>
<p>Ok, I'm on a new computer and for some reason the Sass file for the project template is not rebuilding. What's going on here?</p>
<p>Oh, something weird must be going on because for some reason on this computer (which is an old laptop I've tried to reclaim some usefulness via setting it up with Ubuntu) is not passing the <code>process.env.DOMAIN</code> variable. Oops... forgot to set up my <code>.env</code> file with <code>IS_LOCAL=true</code>. Ok, everything is working now!</p>
<p>Ok, everything is loading now and I did some styling with Flexbox for a fast and easy two column layout.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-30/#code-skip-hello-day-30-1" id="skip-to-code-skip-hello-day-30-1" class="skip-link">Skip code block ▼</a></p>
<pre class="language-scss"><code class="language-scss"> #postcontent<br />        .content-lists-container<br />            <span class="token property">display</span><span class="token punctuation">:</span> flex<br />            <span class="token property">justify-content</span><span class="token punctuation">:</span> center<br />            @media print<span class="token punctuation">,</span> screen <span class="token operator">and</span> <span class="token punctuation">(</span><span class="token property">max-width</span><span class="token punctuation">:</span> 630px<span class="token punctuation">)</span><br />                <span class="token property">display</span><span class="token punctuation">:</span> block<br />            .content-list<br />                <span class="token property">padding</span><span class="token punctuation">:</span> 0 10px<br />                <span class="token property">min-width</span><span class="token punctuation">:</span> 38%<br />                &amp;<span class="token punctuation">:</span><span class="token function">nth-child</span><span class="token punctuation">(</span>2<span class="token punctuation">)</span><br />                    <span class="token property">margin-left</span><span class="token punctuation">:</span> 10px<br />                    <span class="token property">padding-left</span><span class="token punctuation">:</span> 10px<br />                    <span class="token property">border-left</span><span class="token punctuation">:</span> 1px solid black<br />                @media print<span class="token punctuation">,</span> screen <span class="token operator">and</span> <span class="token punctuation">(</span><span class="token property">max-width</span><span class="token punctuation">:</span> 630px<span class="token punctuation">)</span><br />                    <span class="token property">padding</span><span class="token punctuation">:</span> 0<br />                    &amp;<span class="token punctuation">:</span><span class="token function">nth-child</span><span class="token punctuation">(</span>2<span class="token punctuation">)</span><br />                        <span class="token property">border-left</span><span class="token punctuation">:</span> 0<br />                        <span class="token property">margin-left</span><span class="token punctuation">:</span> 0<br />                        <span class="token property">padding</span><span class="token punctuation">:</span> 0</code></pre>
<p id="code-skip-hello-day-30-1">Looks good!</p>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Add a Things I Learned section to the project pages that are the things I learned from that specific project.</li>
</ul>
<p><a target="_blank" href="https://github.com/AramZS/devblog/commit/722f40c430343e84f32aec91ce665d99c3a4feaf" class="git-commit-link"><code>git commit -am &quot;Style work for  day 30&quot;</code></a></p>
<p>I put in a dummy post for things I learned just to make sure everything worked and it did. Don't forget, I need a <code>h2</code> level header in every post. I'll remove it now.</p>
<p><a target="_blank" href="https://github.com/AramZS/devblog/commit/feaa407464ed13b5c26288008386e953de0d2db7" class="git-commit-link"><code>git commit -am &quot;Finish off day 30&quot;</code></a></p>
]]></content:encoded>
	</item>
	
	<item>
		<title>Part 29: Schema.org and Authorship</title>
		<link>https://fightwithtools.dev/posts/projects/devblog/hello-day-29/?source=rss</link>
		<pubDate>Sat, 13 Nov 2021 02:59:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/projects/devblog/hello-day-29/</guid>
		<description>More devblog</description>
		<content:encoded><![CDATA[<h2 id="project-scope-and-todos" tabindex="-1">Project Scope and ToDos</h2>
<ol>
<li>Static Site Generator that can build the blog and let me host it on Github Pages</li>
<li>I want to write posts in Markdown because I'm lazy, it's easy, and it is how I take notes now.</li>
<li>I don't want to spend a ton of time doing design work. I'm doing complicated designs for other projects, so I want to pull a theme I like that I can rely on someone else to keep up.</li>
<li>Once it gets going, I want template changes to be easy.</li>
<li>It should be as easy as Jekyll, so I need to be able to build it using GitHub Actions, where I can just commit a template change or Markdown file and away it goes. If I can't figure this out than fk it, just use Jekyll.</li>
<li>I require it to be used by a significant percent of my professional peers so I can get easy answers when something goes wrong.</li>
<li>I want source maps. This is a dev log site which means whatever I do with it should be easy for other developers to read.</li>
</ol>
<ul class="task-list">
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Also <a href="https://www.npmjs.com/package/@quasibit/eleventy-plugin-sitemap" target="_blank">the sitemap plugin</a> looks cool. Should grab that later.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> So does the <a href="https://www.npmjs.com/package/eleventy-plugin-reading-time" target="_blank">reading time one</a>.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Also <a href="https://github.com/jdsteinbach/eleventy-plugin-toc/" target="_blank">this TOC plugin</a> mby?</p>
</li>
<li class="task-list-item">
<p data-wordfix="true"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Use <a href="https://www.11ty.dev/docs/data-deep-merge/" target="_blank">Data Deep Merge</a> in this blog.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Decide if I want to render the CSS fancier than just a base file and do per-template splitting.</p>
</li>
</ul>
<s>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Can I use the template inside of dinky that already exists instead of copy/pasting it?</li>
</ul>
</s>
<s>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Is there a way to have permalinks to posts contain metadata without organizing them into subfolders?</li>
</ul>
</s>
<ul class="task-list">
<li class="task-list-item">
<p data-wordfix="true"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> How do I cachebreak files on the basis of new build events? Datetime? <code>site.github.build_revision</code> is <a href="https://github.com/jekyll/github-metadata/blob/master/docs/site.github.md" target="_blank">how Jekyll accomplishes this</a>, but is there a way to push <a href="https://docs.github.com/en/actions/reference/context-and-expression-syntax-for-github-actions#github-context" target="_blank">that</a> <a href="https://stackoverflow.com/questions/54310050/how-to-version-build-artifacts-using-github-actions" target="_blank">into the build process</a> for Eleventy?</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Make link text look less shitty. It looks like it is a whole, lighter, font.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Code blocks do not have good syntax highlighting. I want good syntax highlighting.</p>
</li>
<li class="task-list-item">
<p data-wordfix="true"><input disabled="true" type="checkbox" class="markdown-todo" /> Build a Markdown-it plugin to take my typing shortcuts <code>[prob, b/c, ...?]</code> and expand them on build.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> See if we can start Markdown's interpretation of H tags to <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/Heading_Elements#multiple_h1" target="_blank">start at 2, since H1</a> is always pulled from the page title metadata. If it isn't easy, I just have to change my pattern of writing in the MD documents.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Should I <a href="https://www.madebymike.com.au/writing/11ty-filters-data-shortcodes/" target="_blank">explore some shortcodes</a>?</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Order projects listing by last posted blog in that project</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Limit the output of home page post lists to a specific number of posts</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Show the latest post below the site intro on the homepage.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Tags pages with Pagination</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Posts should be able to support a preview header image that can also be shown on post lists.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Create a Markdown-It plugin that reads the project's repo URL off the folder data file and renders commit messages with <a href="https://stackoverflow.com/questions/15919635/on-github-api-what-is-the-best-way-to-get-the-last-commit-message-associated-w" target="_blank">links to the referenced commit</a>. (Is this even possible?) (Is there a way to do it with eleventy instead?)</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Create Next Day/Previous Day links on each post / Next/Previous post on post templates from projects</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Tags should be in the sidebar of articles and link to tag pages</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Create a skiplink for the todo section (or would this be better served with the ToC plugin?) - Yes it would be!</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Add a Things I Learned section to the project pages that are the things I learned from that specific project.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Add a technical reading log to the homepage</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/:empty" target="_blank">Hide</a> empty sections.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Add byline to post pages</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Have table of contents attach to sidebar bottom on mobile</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Support dark mode</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Social Icons</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> SEO/Social/JSON-LD HEAD data</p>
</li>
</ul>
<h2 id="day-29" tabindex="-1">Day 29</h2>
<p>Ok, all the SEO/SEM stuff is good. It's been a while so let's knock out an easy one and add my byline to post pages.</p>
<p>I'll pull the byline header from the index page and turn it into a partial. But I don't want people to click off the site to my ID page like they are now. I should use <a href="https://schema.org/Person" target="_blank">the Microdata for the Person object</a> to link my identity page on Github to my byline on this site.</p>
<p>Hopefully I'll get this right. It looks like way to handle it is with a container of <code>itemprop</code> with the Person type.</p>
<p><code>&lt;h5 itemprop=&quot;author&quot; itemscope itemtype=&quot;https://schema.org/Person&quot;&gt;</code></p>
<p>I want to keep the link to my ID and it <a href="https://schema.org/Person#eg-0189" target="_blank">looks like the way to do that</a> is using a self-closing <code>link</code> tag.</p>
<p><code>&lt;link itemprop=&quot;sameAs&quot; href=&quot;http://aramzs.github.io/aramzs/&quot; /&gt;</code></p>
<p>But if I want it to properly designate this as 'author' it can't stand on it's own. It'll need to be in a larger schema object. I guess that means giving my blog posts the <a href="http://schema.org/" target="_blank">Schema.org</a> markup for a <a href="https://schema.org/CreativeWork" target="_blank">Creative Work</a>. Might not be worth it but I wonder... can I have a block that is just properties for a tag?</p>
<p>Looks like yes:</p>
<p><code>&lt;body {% block bodytags %}{% endblock %}&gt;</code></p>
<p>And then I can fill that in with:</p>
<p><code>{% block bodytags %}itemscope itemtype=&quot;https://schema.org/CreativeWork&quot;{% endblock %}</code></p>
<p>End then I can add a little custom styling to make it smaller for the article context where it is less relevant. I'll move the style up to my <code>user.sass</code> file and then add a post specific rule to change the size.</p>
<p>Looks good and <a href="https://validator.schema.org/" target="_blank">looks like it validates</a>!</p>
<p>Ok, didn't have much time today, so just a short dip of the toe.</p>
<p><a target="_blank" href="https://github.com/AramZS/devblog/commit/e9199fb6a99425e68ca654632a4f590ae384aee8" class="git-commit-link"><code>git commit -am &quot;Set up byline on posts&quot;</code></a></p>
]]></content:encoded>
	</item>
	
	<item>
		<title>Part 28: Featured Images</title>
		<link>https://fightwithtools.dev/posts/projects/devblog/hello-day-28/?source=rss</link>
		<pubDate>Fri, 08 Oct 2021 02:59:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/projects/devblog/hello-day-28/</guid>
		<description>More devblog</description>
		<content:encoded><![CDATA[<h2 id="project-scope-and-todos" tabindex="-1">Project Scope and ToDos</h2>
<ol>
<li>Static Site Generator that can build the blog and let me host it on Github Pages</li>
<li>I want to write posts in Markdown because I'm lazy, it's easy, and it is how I take notes now.</li>
<li>I don't want to spend a ton of time doing design work. I'm doing complicated designs for other projects, so I want to pull a theme I like that I can rely on someone else to keep up.</li>
<li>Once it gets going, I want template changes to be easy.</li>
<li>It should be as easy as Jekyll, so I need to be able to build it using GitHub Actions, where I can just commit a template change or Markdown file and away it goes. If I can't figure this out than fk it, just use Jekyll.</li>
<li>I require it to be used by a significant percent of my professional peers so I can get easy answers when something goes wrong.</li>
<li>I want source maps. This is a dev log site which means whatever I do with it should be easy for other developers to read.</li>
</ol>
<ul class="task-list">
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Also <a href="https://www.npmjs.com/package/@quasibit/eleventy-plugin-sitemap" target="_blank">the sitemap plugin</a> looks cool. Should grab that later.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> So does the <a href="https://www.npmjs.com/package/eleventy-plugin-reading-time" target="_blank">reading time one</a>.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Also <a href="https://github.com/jdsteinbach/eleventy-plugin-toc/" target="_blank">this TOC plugin</a> mby?</p>
</li>
<li class="task-list-item">
<p data-wordfix="true"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Use <a href="https://www.11ty.dev/docs/data-deep-merge/" target="_blank">Data Deep Merge</a> in this blog.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Decide if I want to render the CSS fancier than just a base file and do per-template splitting.</p>
</li>
</ul>
<s>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Can I use the template inside of dinky that already exists instead of copy/pasting it?</li>
</ul>
</s>
<s>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Is there a way to have permalinks to posts contain metadata without organizing them into subfolders?</li>
</ul>
</s>
<ul class="task-list">
<li class="task-list-item">
<p data-wordfix="true"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> How do I cachebreak files on the basis of new build events? Datetime? <code>site.github.build_revision</code> is <a href="https://github.com/jekyll/github-metadata/blob/master/docs/site.github.md" target="_blank">how Jekyll accomplishes this</a>, but is there a way to push <a href="https://docs.github.com/en/actions/reference/context-and-expression-syntax-for-github-actions#github-context" target="_blank">that</a> <a href="https://stackoverflow.com/questions/54310050/how-to-version-build-artifacts-using-github-actions" target="_blank">into the build process</a> for Eleventy?</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Make link text look less shitty. It looks like it is a whole, lighter, font.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Code blocks do not have good syntax highlighting. I want good syntax highlighting.</p>
</li>
<li class="task-list-item">
<p data-wordfix="true"><input disabled="true" type="checkbox" class="markdown-todo" /> Build a Markdown-it plugin to take my typing shortcuts <code>[prob, b/c, ...?]</code> and expand them on build.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> See if we can start Markdown's interpretation of H tags to <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/Heading_Elements#multiple_h1" target="_blank">start at 2, since H1</a> is always pulled from the page title metadata. If it isn't easy, I just have to change my pattern of writing in the MD documents.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Should I <a href="https://www.madebymike.com.au/writing/11ty-filters-data-shortcodes/" target="_blank">explore some shortcodes</a>?</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Order projects listing by last posted blog in that project</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Limit the output of home page post lists to a specific number of posts</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Show the latest post below the site intro on the homepage.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Tags pages with Pagination</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Posts should be able to support a preview header image that can also be shown on post lists.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Create a Markdown-It plugin that reads the project's repo URL off the folder data file and renders commit messages with <a href="https://stackoverflow.com/questions/15919635/on-github-api-what-is-the-best-way-to-get-the-last-commit-message-associated-w" target="_blank">links to the referenced commit</a>. (Is this even possible?) (Is there a way to do it with eleventy instead?)</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Create Next Day/Previous Day links on each post / Next/Previous post on post templates from projects</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Tags should be in the sidebar of articles and link to tag pages</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Create a skiplink for the todo section (or would this be better served with the ToC plugin?) - Yes it would be!</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Add a Things I Learned section to the project pages that are the things I learned from that specific project.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Add a technical reading log to the homepage</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/:empty" target="_blank">Hide</a> empty sections.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Add byline to post pages</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Have table of contents attach to sidebar bottom on mobile</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Support dark mode</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Social Icons</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> SEO/Social/JSON-LD HEAD data</p>
</li>
</ul>
<h2 id="day-28" tabindex="-1">Day 28</h2>
<p>Ok, we're blocked from finishing the various social and search tags by the lack of feature images in the blog. So that's next.</p>
<h3 id="featured-images" tabindex="-1">Featured Images</h3>
<p>So I want to have intellegent defaults here as well. I can have defaults at the project level, the site level and the individual post level. For the Devblog project I'll add to the <code>devblog.json</code> file <code>&quot;featuredImage&quot;: &quot;radial_crosshair.jpg&quot;</code>. All my images will be in <code>../img/</code> so to keep it DRY let's leave that out of the filepaths.</p>
<p>I'll set the same property at the site level, taking my default image from my GitHub blog.</p>
<p>Ok, for the individual blog posts I guess I'll need a little more detail. Since I'll often be taking photos from Creative Commons I need to have a place to put credit. Ok, so I've got a few things to add to the YAML metadata.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-28/#code-skip-hello-day-28-3" id="skip-to-code-skip-hello-day-28-3" class="skip-link">Skip code block ▼</a></p>
<pre class="language-yaml"><code class="language-yaml"><span class="token key atrule">featuredImage</span><span class="token punctuation">:</span> <span class="token string">"close-up-keys.jpg"</span><br /><span class="token key atrule">featuredImageCredit</span><span class="token punctuation">:</span> <span class="token string">"'TYPE' by SarahDeer is licensed with CC BY 2.0"</span><br /><span class="token key atrule">featuredImageLink</span><span class="token punctuation">:</span> <span class="token string">"https://www.flickr.com/photos/40393390@N00/2386752252"</span><br /><span class="token key atrule">featuredImageAlt</span><span class="token punctuation">:</span> <span class="token string">"Close up photo of keys."</span></code></pre>
<p id="code-skip-hello-day-28-3">I can add the following block to my <code>social-header.njk</code> file now:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-28/#code-skip-hello-day-28-2" id="skip-to-code-skip-hello-day-28-2" class="skip-link">Skip code block ▼</a></p>
<pre class="language-liquid"><code class="language-liquid">{%<span class="token templateTag"> <span class="token keyword">if</span> featuredImage </span>%}<br /><br /><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>meta</span> <span class="token attr-name">property</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>og:image<span class="token punctuation">"</span></span> <span class="token attr-name">content</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>{{site.site_url}}/img/{{featuredImage}}<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span><br /><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>meta</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>twitter:image<span class="token punctuation">"</span></span> <span class="token attr-name">content</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>{{site.site_url}}/img/{{featuredImage}}<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span><br /><br />{%<span class="token templateTag"> endif </span>%}</code></pre>
<p id="code-skip-hello-day-28-2"><a target="_blank" href="https://github.com/AramZS/devblog/commit/0dd045779d40d7e34b5461b6cc8547f33c1d9bc9" class="git-commit-link"><code>git commit -am &quot;Day 28 half way done.&quot;</code></a></p>
<p data-wordfix="true"><a href="https://aramzs.github.io/jekyll/social-media/2015/11/11/be-social-with-jekyll.html" target="_blank">In my Jekyll site</a> I had to code a page-level value with a site-level fallback. <a href="https://www.11ty.dev/docs/data-deep-merge/" target="_blank">11ty's deep data merge process</a> allows me to just rely on the cascade of settings and JSON files to properly select a default.</p>
<p>Ok, that's the social tags! I'll set an else condition to make sure that there is always an og:type (default to <code>content=&quot;website&quot;</code>) and we're good to go.</p>
<p>Oh, I want to add the post image to the template too, but only when it is one set at the post level. Being a good web citizen, I should always have alt text on my image, so I'm going to only include it in the post template when I have alt text, that's an easy way to assure not every post has the default image.</p>
<p>I dunno what the right tag is for this? Sometimes I use <code>aside</code> but I think I'm supposed to use <code>figure</code> right? I'll use that here.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-28/#code-skip-hello-day-28-1" id="skip-to-code-skip-hello-day-28-1" class="skip-link">Skip code block ▼</a></p>
<pre class="language-liquid"><code class="language-liquid">    {%<span class="token templateTag"> <span class="token keyword">if</span> featuredImageAlt </span>%}<br />    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>figure</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>figure preview-image<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><br />        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>img</span> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>{{site.site_url}}/img/{{featuredImage}}<span class="token punctuation">"</span></span> <span class="token attr-name">alt</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>{{featuredImageAlt}}<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><br />        {%<span class="token templateTag"> <span class="token keyword">if</span> featuredImageCaption or featuredImageCredit </span>%}<br />        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>figcaption</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>figcaption<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><br />            {%<span class="token templateTag"> <span class="token keyword">if</span> featuredImageCaption  </span>%}{{featuredImageCaption}}{%<span class="token templateTag"> endif </span>%}{%<span class="token templateTag"> <span class="token keyword">if</span> featuredImageCredit  </span>%} | <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>em</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>{{ featuredImageLink }}<span class="token punctuation">"</span></span> <span class="token attr-name">target</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>_blank<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>{{featuredImageCredit}}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>a</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>em</span><span class="token punctuation">></span></span> | {%<span class="token templateTag"> endif </span>%}<br />        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>figcaption</span><span class="token punctuation">></span></span><br />        {%<span class="token templateTag"> endif </span>%}<br />    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>figure</span><span class="token punctuation">></span></span><br />    {%<span class="token templateTag"> endif </span>%}</code></pre>
<p id="code-skip-hello-day-28-1">Ok, basic image stuff works!</p>
<p><a target="_blank" href="https://github.com/AramZS/devblog/commit/0f04a9efac2aad66546be0131707a6ae2a4d9060" class="git-commit-link"><code>git commit -am &quot;Last commit from day 28&quot;</code></a></p>
]]></content:encoded>
	</item>
	
	<item>
		<title>Part 27: CSS and Social Tags</title>
		<link>https://fightwithtools.dev/posts/projects/devblog/hello-day-27/?source=rss</link>
		<pubDate>Tue, 05 Oct 2021 02:59:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/projects/devblog/hello-day-27/</guid>
		<description>More devblog</description>
		<content:encoded><![CDATA[<h2 id="project-scope-and-todos" tabindex="-1">Project Scope and ToDos</h2>
<ol>
<li>Static Site Generator that can build the blog and let me host it on Github Pages</li>
<li>I want to write posts in Markdown because I'm lazy, it's easy, and it is how I take notes now.</li>
<li>I don't want to spend a ton of time doing design work. I'm doing complicated designs for other projects, so I want to pull a theme I like that I can rely on someone else to keep up.</li>
<li>Once it gets going, I want template changes to be easy.</li>
<li>It should be as easy as Jekyll, so I need to be able to build it using GitHub Actions, where I can just commit a template change or Markdown file and away it goes. If I can't figure this out than fk it, just use Jekyll.</li>
<li>I require it to be used by a significant percent of my professional peers so I can get easy answers when something goes wrong.</li>
<li>I want source maps. This is a dev log site which means whatever I do with it should be easy for other developers to read.</li>
</ol>
<ul class="task-list">
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Also <a href="https://www.npmjs.com/package/@quasibit/eleventy-plugin-sitemap" target="_blank">the sitemap plugin</a> looks cool. Should grab that later.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> So does the <a href="https://www.npmjs.com/package/eleventy-plugin-reading-time" target="_blank">reading time one</a>.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Also <a href="https://github.com/jdsteinbach/eleventy-plugin-toc/" target="_blank">this TOC plugin</a> mby?</p>
</li>
<li class="task-list-item">
<p data-wordfix="true"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Use <a href="https://www.11ty.dev/docs/data-deep-merge/" target="_blank">Data Deep Merge</a> in this blog.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Decide if I want to render the CSS fancier than just a base file and do per-template splitting.</p>
</li>
</ul>
<s>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Can I use the template inside of dinky that already exists instead of copy/pasting it?</li>
</ul>
</s>
<s>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Is there a way to have permalinks to posts contain metadata without organizing them into subfolders?</li>
</ul>
</s>
<ul class="task-list">
<li class="task-list-item">
<p data-wordfix="true"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> How do I cachebreak files on the basis of new build events? Datetime? <code>site.github.build_revision</code> is <a href="https://github.com/jekyll/github-metadata/blob/master/docs/site.github.md" target="_blank">how Jekyll accomplishes this</a>, but is there a way to push <a href="https://docs.github.com/en/actions/reference/context-and-expression-syntax-for-github-actions#github-context" target="_blank">that</a> <a href="https://stackoverflow.com/questions/54310050/how-to-version-build-artifacts-using-github-actions" target="_blank">into the build process</a> for Eleventy?</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Make link text look less shitty. It looks like it is a whole, lighter, font.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Code blocks do not have good syntax highlighting. I want good syntax highlighting.</p>
</li>
<li class="task-list-item">
<p data-wordfix="true"><input disabled="true" type="checkbox" class="markdown-todo" /> Build a Markdown-it plugin to take my typing shortcuts <code>[prob, b/c, ...?]</code> and expand them on build.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> See if we can start Markdown's interpretation of H tags to <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/Heading_Elements#multiple_h1" target="_blank">start at 2, since H1</a> is always pulled from the page title metadata. If it isn't easy, I just have to change my pattern of writing in the MD documents.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Should I <a href="https://www.madebymike.com.au/writing/11ty-filters-data-shortcodes/" target="_blank">explore some shortcodes</a>?</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Order projects listing by last posted blog in that project</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Limit the output of home page post lists to a specific number of posts</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Show the latest post below the site intro on the homepage.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Tags pages with Pagination</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Posts should be able to support a preview header image that can also be shown on post lists.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Create a Markdown-It plugin that reads the project's repo URL off the folder data file and renders commit messages with <a href="https://stackoverflow.com/questions/15919635/on-github-api-what-is-the-best-way-to-get-the-last-commit-message-associated-w" target="_blank">links to the referenced commit</a>. (Is this even possible?) (Is there a way to do it with eleventy instead?)</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Create Next Day/Previous Day links on each post / Next/Previous post on post templates from projects</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Tags should be in the sidebar of articles and link to tag pages</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Create a skiplink for the todo section (or would this be better served with the ToC plugin?) - Yes it would be!</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Add a Things I Learned section to the project pages that are the things I learned from that specific project.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Add a technical reading log to the homepage</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/:empty" target="_blank">Hide</a> empty sections.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Add byline to post pages</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Have table of contents attach to sidebar bottom on mobile</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Support dark mode</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Social Icons</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> SEO/Social/JSON-LD HEAD data</p>
</li>
</ul>
<h2 id="day-27" tabindex="-1">Day 27</h2>
<h3 id="footer-size" tabindex="-1">Footer size</h3>
<p>I want to add a link to the repo for the blog. Hmm, the footer's <code>small</code> element is getting its style overwritten. I'll decrease the size, but it looks like the line-height isn't applying the way I'd like. Didn't this happen before? Oh yeah, on <a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-27/hello-day-22.md" target="_blank">Day 22</a>. It had something to do with the <code>display</code> type in the CSS right? Yup. Ok, so let's just switch to <code>display: block</code>.</p>
<h3 id="social-icons" tabindex="-1">Social Icons</h3>
<p>Ok, let's create some social icons! I've pulled down some of the icons I want to use in SVG format and to create clear reusable modules here I've given each social icon its own NJK file and creating a <code>social-block</code> NJK file.</p>
<p>Good stuff, now I just have to size and align the social media icon containers, that will size the SVGs inside.</p>
<p>I'll use <code>text-align: center</code> on the containing block to get the icons centered underneath my byline on the homepage.</p>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Social Icons</li>
</ul>
<p><a target="_blank" href="https://github.com/AramZS/devblog/commit/9b2fee8b143cb6463ff4bcedaa8ddea68e06b9ee" class="git-commit-link"><code>git commit -am &quot;Fix footer and set homepage social icons&quot;</code></a></p>
<h3 id="socialseo-block" tabindex="-1">Social/SEO Block</h3>
<p>Ok, let's set up some social header data. Let's refer back to <a href="https://aramzs.github.io/jekyll/social-media/2015/11/11/be-social-with-jekyll.html" target="_blank">my post on social meta tags for Jekyll</a>, as I suspect it will be useful to reuse here.</p>
<p>First I'll set up a partial file <code>social-header.njk</code>. Like with my Jekyll site I have a <code>site</code> object that contains basic information I can keep in the mix as a default.</p>
<p>I'll need to add a <code>description</code> to my site object, but that's easy enough.</p>
<p>Oh and I need to have my <code>og:url</code> work without an extra trailing slash, so I'll add an if statement - <code>{{site.site_url}}{% if page.url %}/{{ page.url }}{% endif %}</code></p>
<p>Huh... I still have a trailing slash.</p>
<p>Oh interesting, the homepage <code>page.url</code> is just <code>/</code> so I don't need an if statement I guess?</p>
<p>Yup, that works!</p>
<p>But I don't have a truncate function here, so I'll have to <a href="https://mozilla.github.io/nunjucks/api#custom-filters" target="_blank">make my own filter</a> to handle truncating a string.</p>
<p>Oh wait, no, <a href="https://mozilla.github.io/nunjucks/templating.html#truncate" target="_blank">there is a preexisting filter</a>.</p>
<p>Ok the filters I was using in Jekyll don't port over exactly. It looks like I can replace <code>strip_html | strip_newlines</code> with <code>| striptags(false)</code>.</p>
<p>Apparently I can't put line breaks into the templates the same way I can with Jekyll, so I'll have to collapse the various line-breaks and make it slightly less readable.</p>
<p>Ok, easy enough, I got everything figured out. Let's get the rest of the tags in.</p>
<p>Oh, right, I can't use <code>excerpt</code>, I'm using the more... uhh... descriptive 'description' property. Let's switch that. And I can't forget to strip out <code>page.</code> for individual posts.</p>
<p>Hmmm... <a href="https://github.com/11ty/eleventy/issues/869" target="_blank">no built-in last-modified</a>, so I guess I'll handle it the same way, it will be in place when I manually add it to the post metadata, otherwise it will get skipped.</p>
<p>I'll switch my <code>section</code> to be the <code>project</code> property in my posts. Cool, make sure to add an if check and we're good there.</p>
<p>The rest of my old post deals with featured images, which I haven't figured out yet, so I figure I'll handle that next time.</p>
<p><a target="_blank" href="https://github.com/AramZS/devblog/commit/61c18e87a89a5aea0c48a22a71d18301c9a2710c" class="git-commit-link"><code>git commit -am &quot;Set up initial social sharing tags&quot;</code></a></p>
]]></content:encoded>
	</item>
	
	<item>
		<title>Part 26: Metadata and Short Browsers</title>
		<link>https://fightwithtools.dev/posts/projects/devblog/hello-day-26/?source=rss</link>
		<pubDate>Tue, 28 Sep 2021 02:59:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/projects/devblog/hello-day-26/</guid>
		<description>More devblog</description>
		<content:encoded><![CDATA[<h2 id="project-scope-and-todos" tabindex="-1">Project Scope and ToDos</h2>
<ol>
<li>Static Site Generator that can build the blog and let me host it on Github Pages</li>
<li>I want to write posts in Markdown because I'm lazy, it's easy, and it is how I take notes now.</li>
<li>I don't want to spend a ton of time doing design work. I'm doing complicated designs for other projects, so I want to pull a theme I like that I can rely on someone else to keep up.</li>
<li>Once it gets going, I want template changes to be easy.</li>
<li>It should be as easy as Jekyll, so I need to be able to build it using GitHub Actions, where I can just commit a template change or Markdown file and away it goes. If I can't figure this out than fk it, just use Jekyll.</li>
<li>I require it to be used by a significant percent of my professional peers so I can get easy answers when something goes wrong.</li>
<li>I want source maps. This is a dev log site which means whatever I do with it should be easy for other developers to read.</li>
</ol>
<ul class="task-list">
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Also <a href="https://www.npmjs.com/package/@quasibit/eleventy-plugin-sitemap" target="_blank">the sitemap plugin</a> looks cool. Should grab that later.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> So does the <a href="https://www.npmjs.com/package/eleventy-plugin-reading-time" target="_blank">reading time one</a>.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Also <a href="https://github.com/jdsteinbach/eleventy-plugin-toc/" target="_blank">this TOC plugin</a> mby?</p>
</li>
<li class="task-list-item">
<p data-wordfix="true"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Use <a href="https://www.11ty.dev/docs/data-deep-merge/" target="_blank">Data Deep Merge</a> in this blog.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Decide if I want to render the CSS fancier than just a base file and do per-template splitting.</p>
</li>
</ul>
<s>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Can I use the template inside of dinky that already exists instead of copy/pasting it?</li>
</ul>
</s>
<s>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Is there a way to have permalinks to posts contain metadata without organizing them into subfolders?</li>
</ul>
</s>
<ul class="task-list">
<li class="task-list-item">
<p data-wordfix="true"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> How do I cachebreak files on the basis of new build events? Datetime? <code>site.github.build_revision</code> is <a href="https://github.com/jekyll/github-metadata/blob/master/docs/site.github.md" target="_blank">how Jekyll accomplishes this</a>, but is there a way to push <a href="https://docs.github.com/en/actions/reference/context-and-expression-syntax-for-github-actions#github-context" target="_blank">that</a> <a href="https://stackoverflow.com/questions/54310050/how-to-version-build-artifacts-using-github-actions" target="_blank">into the build process</a> for Eleventy?</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Make link text look less shitty. It looks like it is a whole, lighter, font.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Code blocks do not have good syntax highlighting. I want good syntax highlighting.</p>
</li>
<li class="task-list-item">
<p data-wordfix="true"><input disabled="true" type="checkbox" class="markdown-todo" /> Build a Markdown-it plugin to take my typing shortcuts <code>[prob, b/c, ...?]</code> and expand them on build.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> See if we can start Markdown's interpretation of H tags to <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/Heading_Elements#multiple_h1" target="_blank">start at 2, since H1</a> is always pulled from the page title metadata. If it isn't easy, I just have to change my pattern of writing in the MD documents.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Should I <a href="https://www.madebymike.com.au/writing/11ty-filters-data-shortcodes/" target="_blank">explore some shortcodes</a>?</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Order projects listing by last posted blog in that project</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Limit the output of home page post lists to a specific number of posts</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Show the latest post below the site intro on the homepage.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Tags pages with Pagination</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Posts should be able to support a preview header image that can also be shown on post lists.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Create a Markdown-It plugin that reads the project's repo URL off the folder data file and renders commit messages with <a href="https://stackoverflow.com/questions/15919635/on-github-api-what-is-the-best-way-to-get-the-last-commit-message-associated-w" target="_blank">links to the referenced commit</a>. (Is this even possible?) (Is there a way to do it with eleventy instead?)</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Create Next Day/Previous Day links on each post / Next/Previous post on post templates from projects</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Tags should be in the sidebar of articles and link to tag pages</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Create a skiplink for the todo section (or would this be better served with the ToC plugin?) - Yes it would be!</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Add a Things I Learned section to the project pages that are the things I learned from that specific project.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Add a technical reading log to the homepage</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/:empty" target="_blank">Hide</a> empty sections.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Add byline to post pages</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Have table of contents attach to sidebar bottom on mobile</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Support dark mode</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Social Icons</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> SEO/Social/JSON-LD HEAD data</p>
</li>
</ul>
<h2 id="day-26" tabindex="-1">Day 26</h2>
<p>Wait... what am I using the <code>subtitle</code> metadata for? Maybe that should go under the title on post pages? Yeah let's do that.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-26/#code-skip-hello-day-26-4" id="skip-to-code-skip-hello-day-26-4" class="skip-link">Skip code block ▼</a></p>
<pre class="language-liquid"><code class="language-liquid">                        {%<span class="token templateTag"> <span class="token keyword">if</span> <span class="token string">'/posts'</span> not <span class="token keyword">in</span> page<span class="token punctuation">.</span>url </span>%}<br />                        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>header<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>{{ description }}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">></span></span><br />                        {%<span class="token templateTag"> endif </span>%}<br />                        {%<span class="token templateTag"> <span class="token keyword">if</span> <span class="token string">'/posts'</span> <span class="token keyword">in</span> page<span class="token punctuation">.</span>url and subtitle </span>%}<br />                        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>header<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>{{ subtitle }}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">></span></span><br />                        {%<span class="token templateTag"> endif </span>%}</code></pre>
<h3 id="short-browsers" tabindex="-1">Short Browsers</h3>
<p id="code-skip-hello-day-26-4">Also, there's a chance the user can really make the browser short if they do it may cause the footer elements to overlap, so let's try and get rid of that.</p>
<p>Using <code>@media (min-width: variables.$large-mobile) and [height argument]</code> I'll hide specific fixed elements in my makeshift sidebar based on window height. By using <code>and (max-height: 850px)</code> I can restrict fixed elements to appear only when there is room for them.</p>
<p>I'll hide the table of contents when the window is 850px or smaller with <code>@media (min-width: variables.$large-mobile) and (max-height: 850px)</code> and hide the taglist and footer at shorter heights so if the window is very short, we'll only have the title.</p>
<p>Actually... I'd prefer not to totally hide the Table of Contents, but have it return to place above the content if the browser is too short. While I'll keep the CSS Media Query <code>and</code> rule for the tags and footer as is, I can switch the <code>#toc-container</code> rule to be <code> and (min-height: 962px)</code></p>
<p>But wait... the element is not going to scroll when it gets too high. Hmmm. Let's try a containing element... hmm no that's not it by itself. Oh, let's set a max-height on the content itself. Hmm, it makes it a little narrow. Let's try and attach that scrollbar somewhere else.</p>
<p>Ok, I'll use the container div I set up when I was playing with getting <code>max-height</code> working and set my overflow CSS on that. Oh yeah, that looks much better.</p>
<p><code>git commit -m &quot;Fix height and positioning for short browser windows&quot;</code></p>
<h3 id="autolinks-for-git-commits" tabindex="-1">Autolinks for Git Commits?</h3>
<p>Ok, I <a href="https://stackoverflow.com/questions/15919635/on-github-api-what-is-the-best-way-to-get-the-last-commit-message-associated-w" target="_blank">found some interesting ideas for traversing the Github API</a> to get the actual commit links that I can auto apply to links here. Finding the strings will be it's own interesting task but for now I am experimenting with the API with the following requests:</p>
<ul>
<li><a href="https://api.github.com/repos/AramZS/devblog/git/refs/heads/main" target="_blank">Get the repo HEAD on the <code>main</code> branch</a>.</li>
<li><a href="https://api.github.com/repos/AramZS/devblog/git/commits/22240416f821b3aafe4e47f3d95fc23ec3021d58" target="_blank">Get commit by hash at HEAD</a></li>
<li><a href="https://api.github.com/repos/AramZS/devblog/git/commits/3907d1444d79208d41995dfc41db5e85d7de94f3" target="_blank">Get commit by parent hash of HEAD commit</a></li>
<li><a href="https://api.github.com/repos/AramZS/devblog/git/trees/3cd2735001a8c60d995d49391f9b45b6ce530e6d" target="_blank">Get commit tree</a></li>
<li><a href="https://api.github.com/repos/AramZS/devblog/events" target="_blank">Look at commits by push event</a></li>
<li><a href="https://github.com/AramZS/devblog/commits/main.atom" target="_blank">Get latest commits via Atom feed</a></li>
</ul>
<p>None are exactly right, but I might be able to walk backwards through parent commits if I start at the HEAD. I think I'll also want to cache commits so I don't have to walk the tree of commits on every build.</p>
<p><code>git commit -m &quot;Add repo URL for future API calls.&quot;</code></p>
<h3 id="blogroll-and-links" tabindex="-1">Blogroll and Links</h3>
<p>Ok, I know I said I'd lock scope, but this one last expansion! I want to have useful links on the homepage and a blogroll as well. Easy enough to do right? This is the last extra feature, I promise! I'm going to add them as non-post collections in their own folders at <code>src/links</code> and <code>src/blogroll</code>. I'll follow the same pattern I did with posts and projects and create a base <code>json</code> file with default values including the initial collection &quot;tag&quot; and the template I want to use (which won't be the standard one). As an example, I'll put a file at <code>src/blogroll/blogroll.json</code> that has these valeus:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-26/#code-skip-hello-day-26-3" id="skip-to-code-skip-hello-day-26-3" class="skip-link">Skip code block ▼</a></p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span><br />	<span class="token property">"layout"</span><span class="token operator">:</span> <span class="token string">"fwd.njk"</span><span class="token punctuation">,</span><br />	<span class="token property">"description"</span><span class="token operator">:</span> <span class="token string">"Aram is regularly reading"</span><span class="token punctuation">,</span><br />	<span class="token property">"tags"</span><span class="token operator">:</span> <span class="token punctuation">[</span> <span class="token string">"blogroll"</span> <span class="token punctuation">]</span><span class="token punctuation">,</span><br />	<span class="token property">"date"</span><span class="token operator">:</span> <span class="token string">"Last Modified"</span><br /><span class="token punctuation">}</span></code></pre>
<p id="code-skip-hello-day-26-3">Good stuff! Now I need a template that can handle forwarding users to the correct off-site location. There's some fun and fancy ways to do this with Netlify I know, but I'm not using Netlify. So basic is the goal.</p>
<p>I'm going to use <code>isBasedOn</code> as the YAML metadata for the origin URL. This is broadly applicable if I write posts that are not intended to forward, so it means less metadata fields to get confused over and syncs with the <a href="http://schema.org/" target="_blank">Schema.org</a> property, which I like to use for this sort of thing. For the page itself, I'm going to steal an iteration of the template from <a href="http://bit.ly/" target="_blank">Bit.ly</a> and make some modifications. I'll give it a title, a canonical link, and a JSON-LD block. Finally, the key to all this is a META refresh tag with the refresh time sent to <code>0</code> so it forwards immediately.</p>
<p>Here's the final template (for now).</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-26/#code-skip-hello-day-26-2" id="skip-to-code-skip-hello-day-26-2" class="skip-link">Skip code block ▼</a></p>
<pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>html</span><span class="token punctuation">></span></span><br />    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>head</span><span class="token punctuation">></span></span><br />        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>meta</span> <span class="token attr-name">charset</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>UTF-8<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><br />        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>meta</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>viewport<span class="token punctuation">"</span></span> <span class="token attr-name">content</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>width=device-width, initial-scale=1.0<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><br />        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>link</span> <span class="token attr-name">rel</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>canonical<span class="token punctuation">"</span></span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>{{ isBasedOn }}<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span><br />        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>meta</span> <span class="token attr-name">http-equiv</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Link<span class="token punctuation">"</span></span> <span class="token attr-name">rel</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>canonical<span class="token punctuation">"</span></span> <span class="token attr-name">content</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>{{ isBasedOn }}<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span><br />        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>meta</span> <span class="token attr-name">http-equiv</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>refresh<span class="token punctuation">"</span></span> <span class="token attr-name">content</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>0; URL='{{ isBasedOn }}'<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span><br />        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>title</span><span class="token punctuation">></span></span>Fight With Tools Redirect: {{title}}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>title</span><span class="token punctuation">></span></span><br />		<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>script</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>application/ld+json<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token script"><span class="token language-javascript"><br />        <span class="token punctuation">{</span><br />            <span class="token string-property property">"@context"</span><span class="token operator">:</span> <span class="token string">"http://schema.org"</span><span class="token punctuation">,</span><br />            <span class="token string-property property">"@type"</span><span class="token operator">:</span> <span class="token string">"BlogPosting"</span><span class="token punctuation">,</span><br />            <span class="token string-property property">"headline"</span><span class="token operator">:</span> <span class="token string">"{{title}}"</span><span class="token punctuation">,</span><br />            <span class="token string-property property">"description"</span><span class="token operator">:</span> <span class="token string">"{{description}}"</span><span class="token punctuation">,</span><br />            <span class="token string-property property">"mainEntityOfPage"</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />                <span class="token string-property property">"@type"</span><span class="token operator">:</span> <span class="token string">"WebPage"</span><span class="token punctuation">,</span><br />                <span class="token string-property property">"@id"</span><span class="token operator">:</span> <span class="token string">"{{ isBasedOn }}"</span><br />            <span class="token punctuation">}</span><span class="token punctuation">,</span><br />            <span class="token string-property property">"isBasedOn"</span><span class="token operator">:</span> <span class="token string">"{{ isBasedOn }}"</span><span class="token punctuation">,</span><br />            <span class="token string-property property">"isPartOf"</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />                <span class="token string-property property">"@type"</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">"CreativeWork"</span><span class="token punctuation">,</span> <span class="token string">"Product"</span><span class="token punctuation">,</span> <span class="token string">"Blog"</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br />                <span class="token string-property property">"name"</span><span class="token operator">:</span> <span class="token string">"Fight With Tools.dev"</span><span class="token punctuation">,</span><br />                <span class="token string-property property">"productID"</span><span class="token operator">:</span> <span class="token string">"fightwithtools.dev"</span><br />            <span class="token punctuation">}</span><br />        <span class="token punctuation">}</span><br />    </span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>script</span><span class="token punctuation">></span></span><br />    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>head</span><span class="token punctuation">></span></span><br />    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>body</span><span class="token punctuation">></span></span><br />        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>{{isBasedOn}}<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>moved here<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>a</span><span class="token punctuation">></span></span><br />    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>body</span><span class="token punctuation">></span></span><br /><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>html</span><span class="token punctuation">></span></span></code></pre>
<p id="code-skip-hello-day-26-2">And here's a YAML statement in <code>src/blogroll/hacktext.md</code>.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-26/#code-skip-hello-day-26-1" id="skip-to-code-skip-hello-day-26-1" class="skip-link">Skip code block ▼</a></p>
<pre class="language-yaml"><code class="language-yaml"><span class="token key atrule">title</span><span class="token punctuation">:</span> <span class="token string">"Hack Text"</span><br /><span class="token key atrule">description</span><span class="token punctuation">:</span> <span class="token string">"Thinking about Narrative"</span><br /><span class="token key atrule">date</span><span class="token punctuation">:</span> <span class="token datetime number">2021-09-27 22:59:43.10 -4</span><br /><span class="token key atrule">isBasedOn</span><span class="token punctuation">:</span> <span class="token string">"https://hacktext.com"</span><br /><span class="token key atrule">tags</span><span class="token punctuation">:</span><br />  <span class="token punctuation">-</span> Personal Blog</code></pre>
<p id="code-skip-hello-day-26-1">Looks like it works! I think for a fast put-together, this works just fine and lets me do what I want! Good stuff. If I'm going to open a scope, I might as well close it on the same day. But no more of that, let's focus on closing the last remaining todos for next days.</p>
<p><a target="_blank" href="https://github.com/AramZS/devblog/commit/29ae79850439397742e0b7147a0fd9b5683058a4" class="git-commit-link"><code>git commit -am &quot;Set up blogroll and links and write up day 26&quot;</code></a></p>
<p>Oops forgot to add the <code>raw</code> tags to escape my code.</p>
<p><code>git commit -am &quot;Add escaping tags to day 26</code></p>
<p>Touching up this post and realized, I didn't expand the scope, the reading log was already in there, lol.</p>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Add a technical reading log to the homepage</li>
</ul>
<p><code>git commit -m &quot;Touching up day 26 post&quot;</code></p>
]]></content:encoded>
	</item>
	
	<item>
		<title>Part 25: Tweaking TOC Styles</title>
		<link>https://fightwithtools.dev/posts/projects/devblog/hello-day-25/?source=rss</link>
		<pubDate>Mon, 27 Sep 2021 02:59:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/projects/devblog/hello-day-25/</guid>
		<description>More devblog</description>
		<content:encoded><![CDATA[<h2 id="project-scope-and-todos" tabindex="-1">Project Scope and ToDos</h2>
<ol>
<li>Static Site Generator that can build the blog and let me host it on Github Pages</li>
<li>I want to write posts in Markdown because I'm lazy, it's easy, and it is how I take notes now.</li>
<li>I don't want to spend a ton of time doing design work. I'm doing complicated designs for other projects, so I want to pull a theme I like that I can rely on someone else to keep up.</li>
<li>Once it gets going, I want template changes to be easy.</li>
<li>It should be as easy as Jekyll, so I need to be able to build it using GitHub Actions, where I can just commit a template change or Markdown file and away it goes. If I can't figure this out than fk it, just use Jekyll.</li>
<li>I require it to be used by a significant percent of my professional peers so I can get easy answers when something goes wrong.</li>
<li>I want source maps. This is a dev log site which means whatever I do with it should be easy for other developers to read.</li>
</ol>
<ul class="task-list">
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Also <a href="https://www.npmjs.com/package/@quasibit/eleventy-plugin-sitemap" target="_blank">the sitemap plugin</a> looks cool. Should grab that later.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> So does the <a href="https://www.npmjs.com/package/eleventy-plugin-reading-time" target="_blank">reading time one</a>.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Also <a href="https://github.com/jdsteinbach/eleventy-plugin-toc/" target="_blank">this TOC plugin</a> mby?</p>
</li>
<li class="task-list-item">
<p data-wordfix="true"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Use <a href="https://www.11ty.dev/docs/data-deep-merge/" target="_blank">Data Deep Merge</a> in this blog.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Decide if I want to render the CSS fancier than just a base file and do per-template splitting.</p>
</li>
</ul>
<s>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Can I use the template inside of dinky that already exists instead of copy/pasting it?</li>
</ul>
</s>
<s>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Is there a way to have permalinks to posts contain metadata without organizing them into subfolders?</li>
</ul>
</s>
<ul class="task-list">
<li class="task-list-item">
<p data-wordfix="true"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> How do I cachebreak files on the basis of new build events? Datetime? <code>site.github.build_revision</code> is <a href="https://github.com/jekyll/github-metadata/blob/master/docs/site.github.md" target="_blank">how Jekyll accomplishes this</a>, but is there a way to push <a href="https://docs.github.com/en/actions/reference/context-and-expression-syntax-for-github-actions#github-context" target="_blank">that</a> <a href="https://stackoverflow.com/questions/54310050/how-to-version-build-artifacts-using-github-actions" target="_blank">into the build process</a> for Eleventy?</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Make link text look less shitty. It looks like it is a whole, lighter, font.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Code blocks do not have good syntax highlighting. I want good syntax highlighting.</p>
</li>
<li class="task-list-item">
<p data-wordfix="true"><input disabled="true" type="checkbox" class="markdown-todo" /> Build a Markdown-it plugin to take my typing shortcuts <code>[prob, b/c, ...?]</code> and expand them on build.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> See if we can start Markdown's interpretation of H tags to <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/Heading_Elements#multiple_h1" target="_blank">start at 2, since H1</a> is always pulled from the page title metadata. If it isn't easy, I just have to change my pattern of writing in the MD documents.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Should I <a href="https://www.madebymike.com.au/writing/11ty-filters-data-shortcodes/" target="_blank">explore some shortcodes</a>?</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Order projects listing by last posted blog in that project</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Limit the output of home page post lists to a specific number of posts</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Show the latest post below the site intro on the homepage.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Tags pages with Pagination</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Posts should be able to support a preview header image that can also be shown on post lists.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Create a Markdown-It plugin that reads the project's repo URL off the folder data file and renders commit messages with <a href="https://stackoverflow.com/questions/15919635/on-github-api-what-is-the-best-way-to-get-the-last-commit-message-associated-w" target="_blank">links to the referenced commit</a>. (Is this even possible?) (Is there a way to do it with eleventy instead?)</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Create Next Day/Previous Day links on each post / Next/Previous post on post templates from projects</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Tags should be in the sidebar of articles and link to tag pages</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Create a skiplink for the todo section (or would this be better served with the ToC plugin?) - Yes it would be!</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Add a Things I Learned section to the project pages that are the things I learned from that specific project.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Add a technical reading log to the homepage</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/:empty" target="_blank">Hide</a> empty sections.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Add byline to post pages</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Have table of contents attach to sidebar bottom on mobile</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Support dark mode</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Social Icons</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> SEO/Social/JSON-LD HEAD data</p>
</li>
</ul>
<h2 id="day-25" tabindex="-1">Day 25</h2>
<p>Ok, wow, looking back on my last &quot;day's&quot; notes and it has been a while. Almost a month. I got very busy!</p>
<p>I did a quick review of some of my tasks and checked them off. Getting closer to catching up with my ever-broadining scope!</p>
<p>After some examination of what is in the project thus far and what I've added and completed... I think this is the time to declare a lock on this project. I've added two more items to complete and the 7 primary features I required from this project are done. Now, once I check off all the items of the remaining To Dos I think it'll be time to shift my focus back to Backreads... or to another project.</p>
<p>Ok! That's settled then!</p>
<p>The tag pages do appear to have working pagination with my last changes, though they need some design work, so it seems like now is a good time to do some CSS work!</p>
<p>I'll pull most of the preexisting classes that were on the elements from the theme I took the HTML from and add one of my own for disabled links, that'll be good to reuse. I'll also need to make sure to add an override for the hover state.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-25/#code-skip-hello-day-25-1" id="skip-to-code-skip-hello-day-25-1" class="skip-link">Skip code block ▼</a></p>
<pre class="language-sass"><code class="language-sass"><span class="token selector">.disabled-link</span><br /><span class="token property-line">    <span class="token property">color</span><span class="token punctuation">:</span> grey</span><br /><span class="token property-line">    <span class="token property">text-decoration</span><span class="token punctuation">:</span> none</span><br /><span class="token property-line">    <span class="token property">&amp;</span><span class="token punctuation">:</span><span class="token property">hover</span></span><br /><span class="token property-line">        <span class="token property">text-decoration</span><span class="token punctuation">:</span> none</span><br /><span class="token property-line">        <span class="token property">color</span><span class="token punctuation">:</span> grey</span></code></pre>
<p id="code-skip-hello-day-25-1">I next need to set the pagination links to align with the article block. I'll give it a left padding of <code>25px</code> to match the UL indentation on tag pages. Now I need to make it clearer what the links are and what they do.</p>
<p>It's sort of old school, but I'll layer some basic colors and a drop shadow. Why not?</p>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Tags pages with Pagination</li>
</ul>
<p><code>git commit -m &quot;Style pagination&quot;</code></p>
<p>Ok, I'm going to add a sass file and a few per-file overrides to support a dark theme.</p>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Support dark mode</li>
</ul>
<p><a target="_blank" href="https://github.com/AramZS/devblog/commit/ccb004991de58b4a10fb41b37eff5ad364046bba" class="git-commit-link"><code>git commit -am &quot;Set up dark mode styles&quot;</code></a></p>
<p>Ok, I'm going to move the post description to be below the table of contents and that way I can set a fixed position for the ToC on wider screens and not worry about the <code>header</code> area overlapping with the fixed contents position. And to make sure it doesn't overlap with the footer I'll give it a max-height and set it to scroll if there is too much content.</p>
<p><a target="_blank" href="https://github.com/AramZS/devblog/commit/22240416f821b3aafe4e47f3d95fc23ec3021d58" class="git-commit-link"><code>git commit -am &quot;Set fixed table of contents&quot;</code></a></p>
<p>Ok, pretty good for a short day's work!</p>
]]></content:encoded>
	</item>
	
	<item>
		<title>Parg 24: Page Template, Nunjucks and Eleventy Filters</title>
		<link>https://fightwithtools.dev/posts/projects/devblog/hello-day-24/?source=rss</link>
		<pubDate>Mon, 30 Aug 2021 02:59:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/projects/devblog/hello-day-24/</guid>
		<description>More devblog</description>
		<content:encoded><![CDATA[<h2 id="project-scope-and-todos" tabindex="-1">Project Scope and ToDos</h2>
<ol>
<li>Static Site Generator that can build the blog and let me host it on Github Pages</li>
<li>I want to write posts in Markdown because I'm lazy, it's easy, and it is how I take notes now.</li>
<li>I don't want to spend a ton of time doing design work. I'm doing complicated designs for other projects, so I want to pull a theme I like that I can rely on someone else to keep up.</li>
<li>Once it gets going, I want template changes to be easy.</li>
<li>It should be as easy as Jekyll, so I need to be able to build it using GitHub Actions, where I can just commit a template change or Markdown file and away it goes. If I can't figure this out than fk it, just use Jekyll.</li>
<li>I require it to be used by a significant percent of my professional peers so I can get easy answers when something goes wrong.</li>
<li>I want source maps. This is a dev log site which means whatever I do with it should be easy for other developers to read.</li>
</ol>
<ul class="task-list">
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Also <a href="https://www.npmjs.com/package/@quasibit/eleventy-plugin-sitemap" target="_blank">the sitemap plugin</a> looks cool. Should grab that later.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> So does the <a href="https://www.npmjs.com/package/eleventy-plugin-reading-time" target="_blank">reading time one</a>.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Also <a href="https://github.com/jdsteinbach/eleventy-plugin-toc/" target="_blank">this TOC plugin</a> mby?</p>
</li>
<li class="task-list-item">
<p data-wordfix="true"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Use <a href="https://www.11ty.dev/docs/data-deep-merge/" target="_blank">Data Deep Merge</a> in this blog.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Decide if I want to render the CSS fancier than just a base file and do per-template splitting.</p>
</li>
</ul>
<s>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Can I use the template inside of dinky that already exists instead of copy/pasting it?</li>
</ul>
</s>
<s>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Is there a way to have permalinks to posts contain metadata without organizing them into subfolders?</li>
</ul>
</s>
<ul class="task-list">
<li class="task-list-item">
<p data-wordfix="true"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> How do I cachebreak files on the basis of new build events? Datetime? <code>site.github.build_revision</code> is <a href="https://github.com/jekyll/github-metadata/blob/master/docs/site.github.md" target="_blank">how Jekyll accomplishes this</a>, but is there a way to push <a href="https://docs.github.com/en/actions/reference/context-and-expression-syntax-for-github-actions#github-context" target="_blank">that</a> <a href="https://stackoverflow.com/questions/54310050/how-to-version-build-artifacts-using-github-actions" target="_blank">into the build process</a> for Eleventy?</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Make link text look less shitty. It looks like it is a whole, lighter, font.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Code blocks do not have good syntax highlighting. I want good syntax highlighting.</p>
</li>
<li class="task-list-item">
<p data-wordfix="true"><input disabled="true" type="checkbox" class="markdown-todo" /> Build a Markdown-it plugin to take my typing shortcuts <code>[prob, b/c, ...?]</code> and expand them on build.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> See if we can start Markdown's interpretation of H tags to <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/Heading_Elements#multiple_h1" target="_blank">start at 2, since H1</a> is always pulled from the page title metadata. If it isn't easy, I just have to change my pattern of writing in the MD documents.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Should I <a href="https://www.madebymike.com.au/writing/11ty-filters-data-shortcodes/" target="_blank">explore some shortcodes</a>?</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Order projects listing by last posted blog in that project</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Limit the output of home page post lists to a specific number of posts</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Show the latest post below the site intro on the homepage.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Tags pages with Pagination</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Posts should be able to support a preview header image that can also be shown on post lists.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Create a Markdown-It plugin that reads the project's repo URL off the folder data file and renders commit messages with <a href="https://stackoverflow.com/questions/15919635/on-github-api-what-is-the-best-way-to-get-the-last-commit-message-associated-w" target="_blank">links to the referenced commit</a>. (Is this even possible?) (Is there a way to do it with eleventy instead?)</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Create Next Day/Previous Day links on each post / Next/Previous post on post templates from projects</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Tags should be in the sidebar of articles and link to tag pages</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Create a skiplink for the todo section (or would this be better served with the ToC plugin?) - Yes it would be!</p>
</li>
</ul>
<h2 id="day-24" tabindex="-1">Day 24</h2>
<p>I'm going to pause on trying to debug the nunjucks stuff not working as expected. I have no idea why content is appearing in the wrong block and I see no previous examples of this problem. It makes me more sure than ever that I likely screwed something up with an open tag <em>somewhere</em> but I have no idea where and the tooling isn't showing me like it should. Let's just try and get tag pages' content done first, even if that content is showing up in the wrong area.</p>
<p>I think I need to get better insight into how this object is showing on the page. I want to dump it on the page and examine it. Nunjucks <a href="https://github.com/mozilla/nunjucks/issues/94#issuecomment-241729768" target="_blank">seems to have</a> <code>{{ object | dump | safe}}</code> but it isn't working with a more complicated eleventy-generated object. Let's give a custom debug filter a try. <a href="https://github.com/11ty/eleventy/issues/266#issuecomment-716176366" target="_blank">Looks like some good ideas in the eleventy issues.</a></p>
<p>Ok, <a href="https://github.com/11ty/eleventy/issues/266#issuecomment-841304247" target="_blank">used the comment with a clean echo</a>.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-24/#code-skip-hello-day-24-3" id="skip-to-code-skip-hello-day-24-3" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript">eleventyConfig<span class="token punctuation">.</span><span class="token function">addFilter</span><span class="token punctuation">(</span><span class="token string">'console'</span><span class="token punctuation">,</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">value</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />    <span class="token keyword">const</span> str <span class="token operator">=</span> util<span class="token punctuation">.</span><span class="token function">inspect</span><span class="token punctuation">(</span>value<span class="token punctuation">)</span><span class="token punctuation">;</span><br />    <span class="token keyword">return</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">&lt;div style="white-space: pre-wrap;"></span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token function">unescape</span><span class="token punctuation">(</span>str<span class="token punctuation">)</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">&lt;/div>;</span><span class="token template-punctuation string">`</span></span><br /><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p id="code-skip-hello-day-24-3">But when it has a posts object, you end up with all the posts and their content in the middle of the object, which is no good.</p>
<p data-wordfix="true">I'm just going to remove the posts part of the object, but I want to make sure that doesn't impact the overall object, which might be used elsewhere, so I'm going to clone it. I have to use <code>Object.assign</code> for this, because <code>JSON.stringify</code> can't deal with circular references. I may also want to <a href="https://www.11ty.dev/docs/filters/log/" target="_blank">try <code>log</code></a> if this doesn't work.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-24/#code-skip-hello-day-24-2" id="skip-to-code-skip-hello-day-24-2" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript">	eleventyConfig<span class="token punctuation">.</span><span class="token function">addFilter</span><span class="token punctuation">(</span><span class="token string">"console"</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">value</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />		<span class="token keyword">let</span> objToEcho<span class="token punctuation">;</span><br />		<span class="token keyword">if</span> <span class="token punctuation">(</span>value<span class="token punctuation">.</span>posts<span class="token punctuation">)</span> <span class="token punctuation">{</span><br />			objToEcho <span class="token operator">=</span> Object<span class="token punctuation">.</span><span class="token function">assign</span><span class="token punctuation">(</span><span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span> value<span class="token punctuation">)</span><span class="token punctuation">;</span><br />			<span class="token keyword">delete</span> objToEcho<span class="token punctuation">.</span>posts<span class="token punctuation">;</span><br />		<span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span><br />			objToEcho <span class="token operator">=</span> value<span class="token punctuation">;</span><br />		<span class="token punctuation">}</span><br />		<span class="token keyword">const</span> str <span class="token operator">=</span> util<span class="token punctuation">.</span><span class="token function">inspect</span><span class="token punctuation">(</span>objToEcho<span class="token punctuation">)</span><span class="token punctuation">;</span><br />		<span class="token keyword">return</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">&lt;div style="white-space: pre-wrap;"></span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token function">unescape</span><span class="token punctuation">(</span>str<span class="token punctuation">)</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">&lt;/div>;</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span><br />	<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p id="code-skip-hello-day-24-2">Ok, this is useful, so there's three objects to concern oneself with. <code>paged</code> is the object I created with the contents of this page. <code>page</code> is specific metadata about the page, and <code>pagination</code> gives me the information about the previous and next pages, along with information about the collection itself. I can look at them all with this:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-24/#code-skip-hello-day-24-1" id="skip-to-code-skip-hello-day-24-1" class="skip-link">Skip code block ▼</a></p>
<pre class="language-liquid"><code class="language-liquid">        Pages dump:<br />        {{ paged | console | safe }}<br />        {{ page | console | safe }}<br />        {{ pagination | console | safe }}</code></pre>
<p id="code-skip-hello-day-24-1">Ok, that works, the code I used from the other theme gets me most of the way there, but I'll have to alter the style to make it work properly for me.</p>
<p>Ok. Now that I know what's going on, I feel a little more comfortable asking... wtf is going on with the pagination content not falling into the given block? It has to be something wrong with my <code>base.njk</code> file. But I don't know what. Let's walk it through.</p>
<p>Ok, first I'm going to switch all spacing to spaces. Then I'm going to clean up my messy if/else in defining the <code>html</code> tag as that's difficult to read or manage.</p>
<p>Does Nunjucks support <code>elif</code> as an &quot;else if&quot; expression as I thought on <a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-9/" target="_blank">Day 9</a>? It doesn't appear in Nunjucks docs, but I would assume it does. Removing it doesn't fix my problem, but it isn't really needed, so let's remove it anyway.</p>
<p>It is sort of irritating to have a section before my content when I don't need it, so let's remove the precontent section HTML tag from the base template and add it in the areas I use it instead.</p>
<p>Still nothing.</p>
<p>I'll try a blank page.</p>
<p>Still nothing. Maybe I'm crazy, but unless the rendering engine is broken by HTML comments, something at the rendering engine level is broken.</p>
<p>Let's google this and read some Github issues.</p>
<p>Ok... <a href="https://github.com/11ty/eleventy/issues/834#issuecomment-569474008" target="_blank">this is some eleventy stuff apparently. It just doesn't work as anticipated</a>. I guess it is just rendering everything in the <code>content</code> tag.</p>
<p>Yup, that is what it is... the warning there isn't very clear but yup, can't mix and match. So no njk templates that use blocks in the base site, anywhere I want to have Nunjuck inherence I'll need to use a markdown file in my site folder and manage the actual templates using <code>_layouts</code>.</p>
<p>Ok, that works, time to commit and quit for the night.</p>
<p><a target="_blank" href="https://github.com/AramZS/devblog/commit/724988a41d3d8b4390b42cf3a310092fe2328bfb" class="git-commit-link"><code>git commit -am &quot;Finishing off day 23, TOC working, pagination is not.&quot;</code></a></p>
]]></content:encoded>
	</item>
	
	<item>
		<title>Part 23: A Table of Contents</title>
		<link>https://fightwithtools.dev/posts/projects/devblog/hello-day-23/?source=rss</link>
		<pubDate>Sun, 29 Aug 2021 02:59:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/projects/devblog/hello-day-23/</guid>
		<description>More devblog</description>
		<content:encoded><![CDATA[<h2 id="project-scope-and-todos" tabindex="-1">Project Scope and ToDos</h2>
<ol>
<li>Static Site Generator that can build the blog and let me host it on Github Pages</li>
<li>I want to write posts in Markdown because I'm lazy, it's easy, and it is how I take notes now.</li>
<li>I don't want to spend a ton of time doing design work. I'm doing complicated designs for other projects, so I want to pull a theme I like that I can rely on someone else to keep up.</li>
<li>Once it gets going, I want template changes to be easy.</li>
<li>It should be as easy as Jekyll, so I need to be able to build it using GitHub Actions, where I can just commit a template change or Markdown file and away it goes. If I can't figure this out than fk it, just use Jekyll.</li>
<li>I require it to be used by a significant percent of my professional peers so I can get easy answers when something goes wrong.</li>
<li>I want source maps. This is a dev log site which means whatever I do with it should be easy for other developers to read.</li>
</ol>
<ul class="task-list">
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Also <a href="https://www.npmjs.com/package/@quasibit/eleventy-plugin-sitemap" target="_blank">the sitemap plugin</a> looks cool. Should grab that later.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> So does the <a href="https://www.npmjs.com/package/eleventy-plugin-reading-time" target="_blank">reading time one</a>.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Also <a href="https://github.com/jdsteinbach/eleventy-plugin-toc/" target="_blank">this TOC plugin</a> mby?</p>
</li>
<li class="task-list-item">
<p data-wordfix="true"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Use <a href="https://www.11ty.dev/docs/data-deep-merge/" target="_blank">Data Deep Merge</a> in this blog.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Decide if I want to render the CSS fancier than just a base file and do per-template splitting.</p>
</li>
</ul>
<s>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Can I use the template inside of dinky that already exists instead of copy/pasting it?</li>
</ul>
</s>
<s>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Is there a way to have permalinks to posts contain metadata without organizing them into subfolders?</li>
</ul>
</s>
<ul class="task-list">
<li class="task-list-item">
<p data-wordfix="true"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> How do I cachebreak files on the basis of new build events? Datetime? <code>site.github.build_revision</code> is <a href="https://github.com/jekyll/github-metadata/blob/master/docs/site.github.md" target="_blank">how Jekyll accomplishes this</a>, but is there a way to push <a href="https://docs.github.com/en/actions/reference/context-and-expression-syntax-for-github-actions#github-context" target="_blank">that</a> <a href="https://stackoverflow.com/questions/54310050/how-to-version-build-artifacts-using-github-actions" target="_blank">into the build process</a> for Eleventy?</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Make link text look less shitty. It looks like it is a whole, lighter, font.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Code blocks do not have good syntax highlighting. I want good syntax highlighting.</p>
</li>
<li class="task-list-item">
<p data-wordfix="true"><input disabled="true" type="checkbox" class="markdown-todo" /> Build a Markdown-it plugin to take my typing shortcuts <code>[prob, b/c, ...?]</code> and expand them on build.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> See if we can start Markdown's interpretation of H tags to <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/Heading_Elements#multiple_h1" target="_blank">start at 2, since H1</a> is always pulled from the page title metadata. If it isn't easy, I just have to change my pattern of writing in the MD documents.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Should I <a href="https://www.madebymike.com.au/writing/11ty-filters-data-shortcodes/" target="_blank">explore some shortcodes</a>?</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Order projects listing by last posted blog in that project</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Limit the output of home page post lists to a specific number of posts</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Show the latest post below the site intro on the homepage.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Tags pages with Pagination</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Posts should be able to support a preview header image that can also be shown on post lists.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Create a Markdown-It plugin that reads the project's repo URL off the folder data file and renders commit messages with <a href="https://stackoverflow.com/questions/15919635/on-github-api-what-is-the-best-way-to-get-the-last-commit-message-associated-w" target="_blank">links to the referenced commit</a>. (Is this even possible?) (Is there a way to do it with eleventy instead?)</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Create Next Day/Previous Day links on each post</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Tags should be in the sidebar of articles and link to tag pages</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Create a skiplink for the todo section (or would this be better served with the ToC plugin?)</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Next/Previous post on post templates from projects</p>
</li>
</ul>
<h2 id="day-23" tabindex="-1">Day 23</h2>
<p>Huh, pretty sure RSS feeds should be in reverse chronological order, right?</p>
<p><code>git commit -m &quot;Reverse chronological order on feeds.&quot;</code></p>
<h3 id="fix-tag-styling" tabindex="-1">Fix Tag Styling</h3>
<p>Ok, going to fix the tag styling so it works on all sizes.</p>
<p><a target="_blank" href="https://github.com/AramZS/devblog/commit/083babda199a04d4777e6abb0fabd2342ef843e1" class="git-commit-link"><code>git commit -am &quot;Fix post tag section styling&quot;</code></a></p>
<h3 id="activate-table-of-contents" tabindex="-1">Activate Table of Contents</h3>
<p>Ok, <a href="https://github.com/jdsteinbach/eleventy-plugin-toc/" target="_blank">let's try the Table of Contents Plugin</a> real quick. Then I'll need to get the pagination working for tag pages.</p>
<p>I'm going to grab the style from the Wikipedia table of Contents, including their nifty little trick of setting the container to <code>display: table</code> to have it size with the contained text.</p>
<p>Interesting, my Day 1 and Day 2 posts seem to be breaking, with the following error: <code>attempted to output null or undefined value</code>. Looks like it is because there's only an <code>h1</code> tag generated out of that markdown. Because of that, it seems to be printing it twice.</p>
<p>It looks like the issue is in <a href="https://github.com/jdsteinbach/eleventy-plugin-toc/blob/master/src/BuildTOC.js#L20" target="_blank">how the code is processing the headers</a>. But I'm not seeing exactly what it is.</p>
<p>Whatever the problem is, it seems like adding <code>h1</code> to the set of tags is working. I just need to make sure to use the right headers at the right time when writing my markdown.</p>
<p>I want to have the style working a little better now. That means including the same constant for mobile mode so the TOC can have different header spacing on mobile and desktop. Can I move it to a standalone Sass file?</p>
<p>Ok, easy enough to theoretically work. I can move the variable decleration into <code>constants.sass</code> and then import it using <code>@use 'constants'</code>.</p>
<p>Hmmm. That didn't work. <a href="https://stackoverflow.com/questions/17598996/sass-use-variables-across-multiple-files/61500282#61500282" target="_blank">It looks like it should</a>.</p>
<p>I think <a href="https://alistapart.com/article/getting-started-with-sass/" target="_blank">maybe I need to rename the files to have underscores at the beginning</a>.</p>
<p>Hmm... <a href="https://stackoverflow.com/questions/60012955/how-to-use-a-sass-variable-across-multiple-pages-using-use" target="_blank">looks like the variables are namespaced now</a>? Renamed the file to <code>_variables</code> as well. Yup, that seems to have solved the issue.</p>
<p>Now when I want to use variables inside the <code>variables</code> file I have to refer to them as follows:</p>
<p><code>@media (max-width: variables.$mobile-width)</code></p>
<p><code>git commit -m &quot;Add table of contents to posts&quot;</code></p>
<h3 id="tag-pages" tabindex="-1">Tag Pages</h3>
<p>Ok, next we need to paginate the tag pages. I took the structure for the deepTagList from the <code>vredeburg</code> theme so I'm going to look to their structure for pagination as well.</p>
<p>Hmm, just pulling it in doesn't seem to work, but doesn't throw any useful errors either.</p>
<p>My <a href="https://mozilla.github.io/nunjucks/templating.html" target="_blank">block rendering</a> doesn't seem to be working as expected?</p>
<p>Here are my blocks:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-23/#code-skip-hello-day-23-2" id="skip-to-code-skip-hello-day-23-2" class="skip-link">Skip code block ▼</a></p>
<pre class="language-liquid"><code class="language-liquid"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>section</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>content<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><br />  {%<span class="token templateTag"> block content </span>%}<br />  	{{ content | safe }}<br />  {%<span class="token templateTag"> endblock </span>%}<br /><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>section</span><span class="token punctuation">></span></span><br /><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>section</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>postcontent<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><br />  {%<span class="token templateTag"> block postcontent </span>%}<br />    <span class="token comment">&lt;!-- postcontent --></span><br />    Post Content Test<br />  {%<span class="token templateTag"> endblock </span>%}<br /><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>section</span><span class="token punctuation">></span></span></code></pre>
<p id="code-skip-hello-day-23-2">And my extending template:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-23/#code-skip-hello-day-23-1" id="skip-to-code-skip-hello-day-23-1" class="skip-link">Skip code block ▼</a></p>
<pre class="language-liquid"><code class="language-liquid">{%<span class="token templateTag"> block content </span>%}<br />    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h2</span><span class="token punctuation">></span></span>Posts tagged: {{paged.tagName}}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h2</span><span class="token punctuation">></span></span><br />    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>post-summary-list<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><br />        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>ul</span><span class="token punctuation">></span></span><br />        {%<span class="token templateTag"><span class="token operator">-</span> <span class="token keyword">for</span> post <span class="token keyword">in</span> paged<span class="token punctuation">.</span>posts </span>%}<br />            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>li</span><span class="token punctuation">></span></span>{%<span class="token templateTag"> include <span class="token string">"partials/post-summary.njk"</span> </span>%}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>li</span><span class="token punctuation">></span></span><br />        {%<span class="token templateTag"><span class="token operator">-</span> endfor </span>%}<br />        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>ul</span><span class="token punctuation">></span></span><br />    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span><br />{%<span class="token templateTag"> endblock </span>%}<br /><br />{%<span class="token templateTag"> block postcontent </span>%}<br />    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>pagination-block<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><br />        Pages:<br />        {%<span class="token templateTag"> <span class="token keyword">if</span> collections<span class="token punctuation">.</span>tagList<span class="token punctuation">[</span>paged<span class="token punctuation">.</span>tagName<span class="token punctuation">]</span> <span class="token operator">></span> site<span class="token punctuation">.</span>paginate </span>%}<br />            <span class="token comment">&lt;!--Pagination--></span><br />            {%<span class="token templateTag"> include <span class="token string">"partials/pagination.njk"</span> </span>%}<br />        {%<span class="token templateTag"> endif </span>%}<br />    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span><br />{%<span class="token templateTag"> endblock </span>%}</code></pre>
<p id="code-skip-hello-day-23-1">But for some reason the content of <code>postcontent</code> is showing up in the <code>content</code> block.</p>
<p>Is there an open tag somewhere?</p>
<p>(<a href="https://symfony.com/blog/better-white-space-control-in-twig-templates" target="_blank">Found out that I was copying code with newline controls in it, not a problem, but good to know.</a>)</p>
<p>Gotta stop here.</p>
<p><a target="_blank" href="https://github.com/AramZS/devblog/commit/724988a41d3d8b4390b42cf3a310092fe2328bfb" class="git-commit-link"><code>git commit -am &quot;Finishing off day 23, TOC working, pagination is not.&quot;</code></a></p>
]]></content:encoded>
	</item>
	
	<item>
		<title>Hello World Devblog - Pt. 22</title>
		<link>https://fightwithtools.dev/posts/projects/devblog/hello-day-22/?source=rss</link>
		<pubDate>Fri, 20 Aug 2021 02:59:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/projects/devblog/hello-day-22/</guid>
		<description>More devblog</description>
		<content:encoded><![CDATA[<h2 id="project-scope-and-todos" tabindex="-1">Project Scope and ToDos</h2>
<ol>
<li>Static Site Generator that can build the blog and let me host it on Github Pages</li>
<li>I want to write posts in Markdown because I'm lazy, it's easy, and it is how I take notes now.</li>
<li>I don't want to spend a ton of time doing design work. I'm doing complicated designs for other projects, so I want to pull a theme I like that I can rely on someone else to keep up.</li>
<li>Once it gets going, I want template changes to be easy.</li>
<li>It should be as easy as Jekyll, so I need to be able to build it using GitHub Actions, where I can just commit a template change or Markdown file and away it goes. If I can't figure this out than fk it, just use Jekyll.</li>
<li>I require it to be used by a significant percent of my professional peers so I can get easy answers when something goes wrong.</li>
<li>I want source maps. This is a dev log site which means whatever I do with it should be easy for other developers to read.</li>
</ol>
<ul class="task-list">
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Also <a href="https://www.npmjs.com/package/@quasibit/eleventy-plugin-sitemap" target="_blank">the sitemap plugin</a> looks cool. Should grab that later.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> So does the <a href="https://www.npmjs.com/package/eleventy-plugin-reading-time" target="_blank">reading time one</a>.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Also <a href="https://github.com/jdsteinbach/eleventy-plugin-toc/" target="_blank">this TOC plugin</a> mby?</p>
</li>
<li class="task-list-item">
<p data-wordfix="true"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Use <a href="https://www.11ty.dev/docs/data-deep-merge/" target="_blank">Data Deep Merge</a> in this blog.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Decide if I want to render the CSS fancier than just a base file and do per-template splitting.</p>
</li>
</ul>
<s>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Can I use the template inside of dinky that already exists instead of copy/pasting it?</li>
</ul>
</s>
<ul class="task-list">
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Is there a way to have permalinks to posts contain metadata without organizing them into subfolders?</p>
</li>
<li class="task-list-item">
<p data-wordfix="true"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> How do I cachebreak files on the basis of new build events? Datetime? <code>site.github.build_revision</code> is <a href="https://github.com/jekyll/github-metadata/blob/master/docs/site.github.md" target="_blank">how Jekyll accomplishes this</a>, but is there a way to push <a href="https://docs.github.com/en/actions/reference/context-and-expression-syntax-for-github-actions#github-context" target="_blank">that</a> <a href="https://stackoverflow.com/questions/54310050/how-to-version-build-artifacts-using-github-actions" target="_blank">into the build process</a> for Eleventy?</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Make link text look less shitty. It looks like it is a whole, lighter, font.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Code blocks do not have good syntax highlighting. I want good syntax highlighting.</p>
</li>
<li class="task-list-item">
<p data-wordfix="true"><input disabled="true" type="checkbox" class="markdown-todo" /> Build a Markdown-it plugin to take my typing shortcuts <code>[prob, b/c, ...?]</code> and expand them on build.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> See if we can start Markdown's interpretation of H tags to <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/Heading_Elements#multiple_h1" target="_blank">start at 2, since H1</a> is always pulled from the page title metadata. If it isn't easy, I just have to change my pattern of writing in the MD documents.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Should I <a href="https://www.madebymike.com.au/writing/11ty-filters-data-shortcodes/" target="_blank">explore some shortcodes</a>?</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Order projects listing by last posted blog in that project</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Limit the output of home page post lists to a specific number of posts</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Show the latest post below the site intro on the homepage.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Tags pages with Pagination</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Posts should be able to support a preview header image that can also be shown on post lists.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Create a Markdown-It plugin that reads the project's repo URL off the folder data file and renders commit messages with l<a href="https://stackoverflow.com/questions/15919635/on-github-api-what-is-the-best-way-to-get-the-last-commit-message-associated-w" target="_blank">inks to the referenced commit</a>. (Is this even possible?) (Is there a way to do it with eleventy instead?)</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Create Next Day/Previous Day links on each post</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Tags should be in the sidebar of articles and link to tag pages</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Create a skiplink for the todo section (or would this be better served with the ToC plugin?)</p>
</li>
</ul>
<h2 id="day-22" tabindex="-1">Day 22</h2>
<p>Ok did the basics of finishing off tags pages. I also want to link to them on the individual posts.</p>
<p>But we don't want to link to tag pages that I removed because they're collections but not what I think of as tags. So the same filter I applied to build out the tag pages themselves needs to be applied to the post template. Luckily, I have it set up already.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-22/#code-skip-hello-day-22-6" id="skip-to-code-skip-hello-day-22-6" class="skip-link">Skip code block ▼</a></p>
<pre class="language-js"><code class="language-js">	<span class="token keyword">function</span> <span class="token function">filterTagList</span><span class="token punctuation">(</span><span class="token parameter">tags</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />		<span class="token keyword">return</span> <span class="token punctuation">(</span>tags <span class="token operator">||</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">filter</span><span class="token punctuation">(</span><br />			<span class="token punctuation">(</span><span class="token parameter">tag</span><span class="token punctuation">)</span> <span class="token operator">=></span><br />				<span class="token punctuation">[</span><span class="token string">"all"</span><span class="token punctuation">,</span> <span class="token string">"nav"</span><span class="token punctuation">,</span> <span class="token string">"post"</span><span class="token punctuation">,</span> <span class="token string">"posts"</span><span class="token punctuation">,</span> <span class="token string">"projects"</span><span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">indexOf</span><span class="token punctuation">(</span>tag<span class="token punctuation">)</span> <span class="token operator">===</span> <span class="token operator">-</span><span class="token number">1</span><br />		<span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token punctuation">}</span><br /><br />	eleventyConfig<span class="token punctuation">.</span><span class="token function">addFilter</span><span class="token punctuation">(</span><span class="token string">"filterTagList"</span><span class="token punctuation">,</span> filterTagList<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p id="code-skip-hello-day-22-6">And now I can run my tags list through that filter in the template.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-22/#code-skip-hello-day-22-5" id="skip-to-code-skip-hello-day-22-5" class="skip-link">Skip code block ▼</a></p>
<pre class="language-liquid"><code class="language-liquid">{%<span class="token templateTag"> block prefooter </span>%}<br />	<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>taglist<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><br />		<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h6</span><span class="token punctuation">></span></span>Tags: <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h6</span><span class="token punctuation">></span></span><br />        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>ul</span><span class="token punctuation">></span></span><br />			{%<span class="token templateTag"><span class="token operator">-</span> <span class="token keyword">for</span> tag <span class="token keyword">in</span> tags <span class="token operator">|</span> filterTagList <span class="token operator">-</span></span>%}<br />			    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>li</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>{{ site.site_url }}/tag/{{ tag | slug }}<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>{{ tag }}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>a</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>li</span><span class="token punctuation">></span></span><br />			{%<span class="token templateTag"><span class="token operator">-</span> endfor <span class="token operator">-</span></span>%}<br />        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>ul</span><span class="token punctuation">></span></span><br />	<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span><br />{%<span class="token templateTag"> endblock </span>%}</code></pre>
<p id="code-skip-hello-day-22-5">I don't like how that looks though, so let's apply some styling. We'll keep it in the semantically correct unordered list HTML, but I want to change the layout. First let's move it to be an <code>inline-block</code>. Then let's add some symbols.</p>
<p>Ok we're going to use <code>:after</code>. Oh, why is it autocorrecting me to use <code>::after</code>?</p>
<p><a href="https://stackoverflow.com/questions/17684797/should-i-use-single-colons-or-double-colons-for-before-after-first-le" target="_blank">Apparently, that's the standard!</a> Did not know that. Ok, so I want to have a <code>|</code> seperater between each element, along with the list starting with the character. I know the pseudo-classes for this!</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-22/#code-skip-hello-day-22-4" id="skip-to-code-skip-hello-day-22-4" class="skip-link">Skip code block ▼</a></p>
<pre class="language-sass"><code class="language-sass"><span class="token selector">#taglist</span><br />    <span class="token selector">li</span><br /><span class="token property-line">        <span class="token property">font-size</span><span class="token punctuation">:</span> 10px</span><br /><span class="token property-line">        <span class="token property">line-height</span><span class="token punctuation">:</span> 6px</span><br /><span class="token property-line">        <span class="token property">display</span><span class="token punctuation">:</span> inline-block</span><br /><span class="token property-line">        <span class="token property">&amp;</span><span class="token punctuation">:</span><span class="token punctuation">:</span><span class="token property">after</span></span><br /><span class="token property-line">            <span class="token property">content</span><span class="token punctuation">:</span> "|"</span><br /><span class="token property-line">            <span class="token property">margin</span><span class="token punctuation">:</span> 0 3px</span><br /><span class="token property-line">        <span class="token property">&amp;</span><span class="token punctuation">:</span><span class="token property">first-of-type</span><span class="token punctuation">:</span><span class="token punctuation">:</span><span class="token property">before</span></span><br /><span class="token property-line">            <span class="token property">content</span><span class="token punctuation">:</span> "|"</span><br /><span class="token property-line">            <span class="token property">margin</span><span class="token punctuation">:</span> 0</span><br /><span class="token property-line">            <span class="token property">margin-right</span><span class="token punctuation">:</span> 3px</span></code></pre>
<p id="code-skip-hello-day-22-4">Hmm, even with line-height set low, I'm still seeing a large separation between lines. It doesn't appear to be based on line-height, I'm not sure where the separation is coming from, it isn't in margin or padding in the Computed area of the styles.</p>
<p>I think it is just the nature of using <code>inline-block</code> so better to use something else. I'll use <code>display: block</code> and <code>float: left</code>. Then to make things flow properly without it colliding into the element below it I'll have to add the same to the <code>ul</code> container. So final style is like this.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-22/#code-skip-hello-day-22-3" id="skip-to-code-skip-hello-day-22-3" class="skip-link">Skip code block ▼</a></p>
<pre class="language-sass"><code class="language-sass"><span class="token selector">#taglist</span><br />    <span class="token selector">ul</span><br /><span class="token property-line">        <span class="token property">display</span><span class="token punctuation">:</span> block</span><br /><span class="token property-line">        <span class="token property">position</span><span class="token punctuation">:</span> relative</span><br /><span class="token property-line">        <span class="token property">float</span><span class="token punctuation">:</span> left</span><br /><span class="token property-line">        <span class="token property">margin-bottom</span><span class="token punctuation">:</span> 12px</span><br />        <span class="token selector">li</span><br /><span class="token property-line">            <span class="token property">font-size</span><span class="token punctuation">:</span> 10px</span><br /><span class="token property-line">            <span class="token property">line-height</span><span class="token punctuation">:</span> 12px</span><br /><span class="token property-line">            <span class="token property">height</span><span class="token punctuation">:</span> 12px</span><br /><span class="token property-line">            <span class="token property">display</span><span class="token punctuation">:</span> block</span><br /><span class="token property-line">            <span class="token property">float</span><span class="token punctuation">:</span> left</span><br /><span class="token property-line">            <span class="token property">margin</span><span class="token punctuation">:</span> 3px 0</span><br /><span class="token property-line">            <span class="token property">padding</span><span class="token punctuation">:</span> 0</span><br /><span class="token property-line">            <span class="token property">&amp;</span><span class="token punctuation">:</span><span class="token punctuation">:</span><span class="token property">after,</span> <span class="token property">&amp;</span><span class="token punctuation">:</span><span class="token property">first-of-type</span><span class="token punctuation">:</span><span class="token punctuation">:</span><span class="token property">before</span></span><br /><span class="token property-line">                <span class="token property">content</span><span class="token punctuation">:</span> "|"</span><br /><span class="token property-line">                <span class="token property">font-size</span><span class="token punctuation">:</span> 11px</span><br /><span class="token property-line">                <span class="token property">font-weight</span><span class="token punctuation">:</span> bold</span><br /><span class="token property-line">                <span class="token property">margin</span><span class="token punctuation">:</span> 0 3px</span><br /><span class="token property-line">            <span class="token property">&amp;</span><span class="token punctuation">:</span><span class="token property">first-of-type</span><span class="token punctuation">:</span><span class="token punctuation">:</span><span class="token property">before</span></span><br /><span class="token property-line">                <span class="token property">margin</span><span class="token punctuation">:</span> 0</span><br /><span class="token property-line">                <span class="token property">margin-right</span><span class="token punctuation">:</span> 3px</span></code></pre>
<h3 id="first-response!" tabindex="-1">First response!</h3>
<p id="code-skip-hello-day-22-3">Ok, I noticed <a href="https://github.com/AramZS/devblog/pull/1" target="_blank">I have a PR</a> around <a href="https://github.com/11ty/eleventy/issues/1879" target="_blank">my attempt to open a custom environment</a>. Let's see if it solves <a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-11/" target="_blank">my problems from day 11</a>.</p>
<p>First <a href="https://github.com/pdehaan" target="_blank"><code>pdehaan</code></a> noted I had a dumb error. Let's see if we can get the array of file strings working properly.</p>
<p data-wordfix="true">Also they ask: Why did I include the normalize function? Well, I can look back <a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-10/" target="_blank">at day 10</a> and see that the reason is because, <a href="https://github.com/11ty/eleventy/blob/6776e871128cc3f9895edddadc6408db8abd7fde/src/TemplatePath.js#L95" target="_blank">that's what Eleventy did</a>. Good to know. It doesn't look like I need it... on Mac at least? But I assume that this has to do with handling weird paths in a multitude of operating systems, so I'll leave it in, just in case I want to develop in another environment.</p>
<p>Ok, let's leave it in place, but correctly fix all the paths.</p>
<p>Good stuff! Looks like it works.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-22/#code-skip-hello-day-22-2" id="skip-to-code-skip-hello-day-22-2" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript"><span class="token punctuation">[</span><br />  <span class="token string">'/Users/zuckerscharffa/Dev/fightwithtooldev/src/_includes'</span><span class="token punctuation">,</span><br />  <span class="token string">'/Users/zuckerscharffa/Dev/fightwithtooldev/src/_layouts'</span><span class="token punctuation">,</span><br />  <span class="token string">'/Users/zuckerscharffa/Dev/fightwithtooldev/src'</span><span class="token punctuation">,</span><br />  <span class="token string">'.'</span><br /><span class="token punctuation">]</span></code></pre>
<p id="code-skip-hello-day-22-2">So, do all the other things that broke when I last tried this work? Nope, let's move on to the other comments in the PR.</p>
<p>Ok, so first, I've got a new error. For some reason, it isn't going down to the <code>partials</code> path inside my <code>_includes</code> folder. Ok, I tried removing that specific call and it still isn't working, now it can't see <code>base.njk</code>, so the <code>_includes</code> folder isn't working at all. Let's try the version in the PR.</p>
<p>Huh, ok, does it need <em>relative</em> paths, not absolute ones for some reason?</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-22/#code-skip-hello-day-22-1" id="skip-to-code-skip-hello-day-22-1" class="skip-link">Skip code block ▼</a></p>
<pre><code>[ 'src/_includes', 'src/_layouts', 'src' ]
</code></pre>
<p data-wordfix="true" id="code-skip-hello-day-22-1"><code>pdehaan</code> left off the <code>.</code> path, though that is included in the standard Eleventy setup. I'll add it back in, just for consistency.</p>
<p>Let's fix the other errors I made, before we dive back into the environment issues in more detail.</p>
<p>Ok, I think I've puilled in all of <code>pdehaan</code> suggestions. (Oops I probably should have made a commit after the tags work huh?)</p>
<p>A commit to cover tags changes:</p>
<p><code>git commit -m &quot;Get tags pages working&quot;</code></p>
<p>Ok now let's commit with the relative file paths working in the suggested way, since everything seems to be working.</p>
<p data-wordfix="true">Oh, <a href="https://github.com/11ty/11ty-website/pull/1135" target="_blank">let's also fix the styles for my PR to the Eleventy website while I'm here</a>. And, while checking the issues involved with the problem, I noticed <a href="https://github.com/11ty/eleventy/issues/895" target="_blank">my input may have helped push a Nunjucks config option into the eventual Eleventy v1 release</a>.</p>
<p>His suggestions to add the <code>or</code> to the title, while I understand, I want to avoid, as part of the reason I want it to throw errors is specifically to catch stuff like leaving out a title where there needs to be a title.</p>
<p>I tried a bunch of different ways to do it with the structure of code I had before, but <a href="https://github.com/AramZS/devblog/pull/1/files/7a7fdd4e87fe39360c573b23da06606ae5e9b072#r692597530" target="_blank">something is wonky</a>. I'll remove it out of the flow for now so I can deploy.</p>
<p>Going to break for now, gotta eat.</p>
<p><a target="_blank" href="https://github.com/AramZS/devblog/commit/4e4fd0139dfecf65b13cabc7394b869163ceabe6" class="git-commit-link"><code>git commit -am &quot;Finishing off day 22&quot; </code></a></p>
]]></content:encoded>
	</item>
	
	<item>
		<title>Part 21: Complex Eleventy Tags</title>
		<link>https://fightwithtools.dev/posts/projects/devblog/hello-day-21/?source=rss</link>
		<pubDate>Tue, 17 Aug 2021 02:59:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/projects/devblog/hello-day-21/</guid>
		<description>More devblog</description>
		<content:encoded><![CDATA[<h2 id="project-scope-and-todos" tabindex="-1">Project Scope and ToDos</h2>
<ol>
<li>Static Site Generator that can build the blog and let me host it on Github Pages</li>
<li>I want to write posts in Markdown because I'm lazy, it's easy, and it is how I take notes now.</li>
<li>I don't want to spend a ton of time doing design work. I'm doing complicated designs for other projects, so I want to pull a theme I like that I can rely on someone else to keep up.</li>
<li>Once it gets going, I want template changes to be easy.</li>
<li>It should be as easy as Jekyll, so I need to be able to build it using GitHub Actions, where I can just commit a template change or Markdown file and away it goes. If I can't figure this out than fk it, just use Jekyll.</li>
<li>I require it to be used by a significant percent of my professional peers so I can get easy answers when something goes wrong.</li>
<li>I want source maps. This is a dev log site which means whatever I do with it should be easy for other developers to read.</li>
</ol>
<ul class="task-list">
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Also <a href="https://www.npmjs.com/package/@quasibit/eleventy-plugin-sitemap" target="_blank">the sitemap plugin</a> looks cool. Should grab that later.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> So does the <a href="https://www.npmjs.com/package/eleventy-plugin-reading-time" target="_blank">reading time one</a>.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Also <a href="https://github.com/jdsteinbach/eleventy-plugin-toc/" target="_blank">this TOC plugin</a> mby?</p>
</li>
<li class="task-list-item">
<p data-wordfix="true"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Use <a href="https://www.11ty.dev/docs/data-deep-merge/" target="_blank">Data Deep Merge</a> in this blog.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Decide if I want to render the CSS fancier than just a base file and do per-template splitting.</p>
</li>
</ul>
<s>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Can I use the template inside of dinky that already exists instead of copy/pasting it?</li>
</ul>
</s>
<ul class="task-list">
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Is there a way to have permalinks to posts contain metadata without organizing them into subfolders?</p>
</li>
<li class="task-list-item">
<p data-wordfix="true"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> How do I cachebreak files on the basis of new build events? Datetime? <code>site.github.build_revision</code> is <a href="https://github.com/jekyll/github-metadata/blob/master/docs/site.github.md" target="_blank">how Jekyll accomplishes this</a>, but is there a way to push <a href="https://docs.github.com/en/actions/reference/context-and-expression-syntax-for-github-actions#github-context" target="_blank">that</a> <a href="https://stackoverflow.com/questions/54310050/how-to-version-build-artifacts-using-github-actions" target="_blank">into the build process</a> for Eleventy?</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Make link text look less shitty. It looks like it is a whole, lighter, font.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Code blocks do not have good syntax highlighting. I want good syntax highlighting.</p>
</li>
<li class="task-list-item">
<p data-wordfix="true"><input disabled="true" type="checkbox" class="markdown-todo" /> Build a Markdown-it plugin to take my typing shortcuts <code>[prob, b/c, ...?]</code> and expand them on build.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> See if we can start Markdown's interpretation of H tags to <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/Heading_Elements#multiple_h1" target="_blank">start at 2, since H1</a> is always pulled from the page title metadata. If it isn't easy, I just have to change my pattern of writing in the MD documents.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Should I <a href="https://www.madebymike.com.au/writing/11ty-filters-data-shortcodes/" target="_blank">explore some shortcodes</a>?</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Order projects listing by last posted blog in that project</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Limit the output of home page post lists to a specific number of posts</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Show the latest post below the site intro on the homepage.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Tags pages with Pagination</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Posts should be able to support a preview header image that can also be shown on post lists.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Create a Markdown-It plugin that reads the project's repo URL off the folder data file and renders commit messages with l<a href="https://stackoverflow.com/questions/15919635/on-github-api-what-is-the-best-way-to-get-the-last-commit-message-associated-w" target="_blank">inks to the referenced commit</a>. (Is this even possible?) (Is there a way to do it with eleventy instead?)</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Create Next Day/Previous Day links on each post</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Tags should be in the sidebar of articles and link to tag pages</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Create a skiplink for the todo section (or would this be better served with the ToC plugin?)</p>
</li>
</ul>
<h2 id="day-21" tabindex="-1">Day 21</h2>
<p>Hmm I still want to paginate my tags pages. I originally thought that I could just add to the number of <code>size</code> in the YAML front matter. But of course that doesn't work, the template doesn't have knowledge of anything other than the list of tags at that point.</p>
<p>So we need to pass in a set of tags with the actual posts mapped per-tag. There doesn't seem to be a built in way to do this, so I need to adjust the <code>tagList</code> collection. I need to make it return an object where each tag is a top-level property that points to an array of posts.</p>
<p>Previously I had:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-21/#code-skip-hello-day-21-5" id="skip-to-code-skip-hello-day-21-5" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript">collection<span class="token punctuation">.</span><span class="token function">getAll</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">item</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />	<span class="token punctuation">(</span>item<span class="token punctuation">.</span>data<span class="token punctuation">.</span>tags <span class="token operator">||</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">tag</span><span class="token punctuation">)</span> <span class="token operator">=></span> tagSet<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span>tag<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p id="code-skip-hello-day-21-5">But now lets switch it around.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-21/#code-skip-hello-day-21-4" id="skip-to-code-skip-hello-day-21-4" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">function</span> <span class="token function">filterTagList</span><span class="token punctuation">(</span><span class="token parameter">tags</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />	<span class="token keyword">return</span> <span class="token punctuation">(</span>tags <span class="token operator">||</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">filter</span><span class="token punctuation">(</span><br />		<span class="token punctuation">(</span><span class="token parameter">tag</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">[</span><span class="token string">"all"</span><span class="token punctuation">,</span> <span class="token string">"nav"</span><span class="token punctuation">,</span> <span class="token string">"post"</span><span class="token punctuation">,</span> <span class="token string">"posts"</span><span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">indexOf</span><span class="token punctuation">(</span>tag<span class="token punctuation">)</span> <span class="token operator">===</span> <span class="token operator">-</span><span class="token number">1</span><br />	<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span><br /><br />collection<span class="token punctuation">.</span><span class="token function">getAll</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">item</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />			<span class="token function">filterTagList</span><span class="token punctuation">(</span>item<span class="token punctuation">.</span>data<span class="token punctuation">.</span>tags<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">tag</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />				<span class="token keyword">if</span> <span class="token punctuation">(</span>tagSet<span class="token punctuation">.</span><span class="token function">hasOwnProperty</span><span class="token punctuation">(</span>tag<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />					tagSet<span class="token punctuation">[</span>tag<span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span>item<span class="token punctuation">)</span><span class="token punctuation">;</span><br />				<span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span><br />					tagSet<span class="token punctuation">[</span>tag<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Set</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />					tagSet<span class="token punctuation">[</span>tag<span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span>item<span class="token punctuation">)</span><span class="token punctuation">;</span><br />				<span class="token punctuation">}</span><br />			<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />		<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />		<span class="token keyword">return</span> tagSet<span class="token punctuation">;</span></code></pre>
<p id="code-skip-hello-day-21-4">Hmmm, not the most efficient, we're doing the same line of code twice. Let's simplify.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-21/#code-skip-hello-day-21-3" id="skip-to-code-skip-hello-day-21-3" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript"><span class="token function">filterTagList</span><span class="token punctuation">(</span>item<span class="token punctuation">.</span>data<span class="token punctuation">.</span>tags<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">tag</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />  <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>tagSet<span class="token punctuation">.</span><span class="token function">hasOwnProperty</span><span class="token punctuation">(</span>tag<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />  	tagSet<span class="token punctuation">[</span>tag<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Set</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />  <span class="token punctuation">}</span><br />  tagSet<span class="token punctuation">[</span>tag<span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span>item<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p id="code-skip-hello-day-21-3">Ok, let's see if this works. Should be good, but how do I get the actual items? I'll have to change the template. Hmm, it looks like there isn't really a way to access the key in the YAML arguments. I'll have to add that too somehow?</p>
<p>Note the use of Set here, to keep posts unique.</p>
<p>Oops forgot that <code>Set</code> uses <code>add</code> not <code>push</code> for adding to the set.</p>
<p>Hmm. Better.</p>
<p>Now I'll have to adjust the pagination permalink it looks like to resolve this error:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-21/#code-skip-hello-day-21-2" id="skip-to-code-skip-hello-day-21-2" class="skip-link">Skip code block ▼</a></p>
<pre class="language-bash"><code class="language-bash">Problem writing Eleventy templates: <span class="token punctuation">(</span>more <span class="token keyword">in</span> DEBUG output<span class="token punctuation">)</span><br /><span class="token operator">></span> Having trouble rendering njk template ./src/tags-pages.njk<br /><br /><span class="token variable"><span class="token variable">`</span>TemplateContentRenderError<span class="token variable">`</span></span> was thrown<br /><span class="token operator">></span> <span class="token punctuation">(</span>./src/tags-pages.njk<span class="token punctuation">)</span><br />  Error: slugify: string argument expected<br /><br /><span class="token variable"><span class="token variable">`</span>Template render error<span class="token variable">`</span></span> was thrown:<br />    Template render error: <span class="token punctuation">(</span>./src/tags-pages.njk<span class="token punctuation">)</span><br />      Error: slugify: string argument expected</code></pre>
<p data-wordfix="true" id="code-skip-hello-day-21-2">Oh, right, I can't access <code>Set</code>s with <code>[0]</code>. I don't think Eleventy anticipates Sets anyway, so I should likely take the time to convert the Sets of posts into Arrays.</p>
<p>Ok, easy enough, let's use the spread operator, that's what it is for right?</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-21/#code-skip-hello-day-21-1" id="skip-to-code-skip-hello-day-21-1" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript">		Object<span class="token punctuation">.</span><span class="token function">keys</span><span class="token punctuation">(</span>tagSet<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">key</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />			<span class="token comment">// console.log(key);        // the name of the current key.</span><br />			<span class="token comment">// console.log(myObj[key]); // the value of the current key.</span><br />			tagSet<span class="token punctuation">[</span>key<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token operator">...</span>tagSet<span class="token punctuation">[</span>key<span class="token punctuation">]</span><span class="token punctuation">]</span><span class="token punctuation">;</span><br />		<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />		console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><br />			<span class="token string">"tagset"</span><span class="token punctuation">,</span><br />			tagSet<span class="token punctuation">[</span>Object<span class="token punctuation">.</span><span class="token function">keys</span><span class="token punctuation">(</span>tagSet<span class="token punctuation">)</span><span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">]</span><span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">.</span>data<span class="token punctuation">.</span>verticalTag<br />		<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p id="code-skip-hello-day-21-1">Ok, I'm getting the right information here in the console.log statement. It would seem that this is set up properly as a collection, but something about how it is being handled into the tags-pages isn't working.</p>
<p data-wordfix="true">I'm going to take a look around and see how it works. There's <a href="https://www.11ty.dev/docs/quicktips/tag-pages/" target="_blank">a basic tag page post on the Eleventy.dev site</a>, but it doesn't allow for pagination of the tag pages in the way I was hoping.</p>
<p data-wordfix="true">Ok. So I think that, <a href="https://www.11ty.dev/docs/pagination/nav/" target="_blank">judging from the page on Pagination Navigation</a>, I have to pass an array, not an object. Let's change the transformation into a set into a transformation from an object to an array.</p>
<p data-wordfix="true">Nope, that doesn't do it. And checking the docs it makes it clear that <a href="https://www.11ty.dev/docs/pagination/#paging-an-object" target="_blank">we can indeed paginate an object</a>.</p>
<p>Hmmm. So I think maybe this just isn't working the way I would have hoped. <a href="https://github.com/11ty/eleventy/issues/332" target="_blank">It looks like I'm not the only person to want to do this</a>. <a href="https://github.com/11ty/eleventy/blob/master/src/Plugins/Pagination.js" target="_blank">Judging by the pagination code</a> this is indeed the best way to do what I want to do, which seems, sort of a shame. <a href="https://github.com/dafiulh/vredeburg/blob/master/src/tag.njk" target="_blank">Others have taken a similar approach as well it looks like</a>.</p>
<p>I like how the <a href="https://vredeburg.netlify.app/" target="_blank">vredeburg</a> these handles it. Very solid objects that make pagination easy and page links available. I should be able to adapt it easy. Switching over the code seems like it should be easy enough. The pagination seems to have applied, but the <code>eleventyComputed</code> doesn't seem to be working. Oh, a good time to commit!</p>
<p><a target="_blank" href="https://github.com/AramZS/devblog/commit/6804f3143608ac461173f76e0b467dfd382d5bd3" class="git-commit-link"><code>git commit -am &quot;Getting tag pages working, mostly there&quot;</code></a></p>
<p>Oh, I used tabs instead of spaces. That was the problem. Well, solved now! I'll add that to my editorconfig file and be good to go!</p>
<p><a target="_blank" href="https://github.com/AramZS/devblog/commit/428928442fe2ddf76cd8195b106e871d161101c2" class="git-commit-link"><code>git commit -am &quot;Getting the basics of tags pages working&quot;</code></a></p>
]]></content:encoded>
	</item>
	
	<item>
		<title>Part 20: Working with Shortcodes and Collections</title>
		<link>https://fightwithtools.dev/posts/projects/devblog/hello-day-20/?source=rss</link>
		<pubDate>Tue, 03 Aug 2021 02:59:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/projects/devblog/hello-day-20/</guid>
		<description>More devblog</description>
		<content:encoded><![CDATA[<h2 id="project-scope-and-todos" tabindex="-1">Project Scope and ToDos</h2>
<ol>
<li>Static Site Generator that can build the blog and let me host it on Github Pages</li>
<li>I want to write posts in Markdown because I'm lazy, it's easy, and it is how I take notes now.</li>
<li>I don't want to spend a ton of time doing design work. I'm doing complicated designs for other projects, so I want to pull a theme I like that I can rely on someone else to keep up.</li>
<li>Once it gets going, I want template changes to be easy.</li>
<li>It should be as easy as Jekyll, so I need to be able to build it using GitHub Actions, where I can just commit a template change or Markdown file and away it goes. If I can't figure this out than fk it, just use Jekyll.</li>
<li>I require it to be used by a significant percent of my professional peers so I can get easy answers when something goes wrong.</li>
<li>I want source maps. This is a dev log site which means whatever I do with it should be easy for other developers to read.</li>
</ol>
<ul class="task-list">
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Also <a href="https://www.npmjs.com/package/@quasibit/eleventy-plugin-sitemap" target="_blank">the sitemap plugin</a> looks cool. Should grab that later.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> So does the <a href="https://www.npmjs.com/package/eleventy-plugin-reading-time" target="_blank">reading time one</a>.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Also <a href="https://github.com/jdsteinbach/eleventy-plugin-toc/" target="_blank">this TOC plugin</a> mby?</p>
</li>
<li class="task-list-item">
<p data-wordfix="true"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Use <a href="https://www.11ty.dev/docs/data-deep-merge/" target="_blank">Data Deep Merge</a> in this blog.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Decide if I want to render the CSS fancier than just a base file and do per-template splitting.</p>
</li>
</ul>
<s>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Can I use the template inside of dinky that already exists instead of copy/pasting it?</li>
</ul>
</s>
<ul class="task-list">
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Is there a way to have permalinks to posts contain metadata without organizing them into subfolders?</p>
</li>
<li class="task-list-item">
<p data-wordfix="true"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> How do I cachebreak files on the basis of new build events? Datetime? <code>site.github.build_revision</code> is <a href="https://github.com/jekyll/github-metadata/blob/master/docs/site.github.md" target="_blank">how Jekyll accomplishes this</a>, but is there a way to push <a href="https://docs.github.com/en/actions/reference/context-and-expression-syntax-for-github-actions#github-context" target="_blank">that</a> <a href="https://stackoverflow.com/questions/54310050/how-to-version-build-artifacts-using-github-actions" target="_blank">into the build process</a> for Eleventy?</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Make link text look less shitty. It looks like it is a whole, lighter, font.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Code blocks do not have good syntax highlighting. I want good syntax highlighting.</p>
</li>
<li class="task-list-item">
<p data-wordfix="true"><input disabled="true" type="checkbox" class="markdown-todo" /> Build a Markdown-it plugin to take my typing shortcuts <code>[prob, b/c, ...?]</code> and expand them on build.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> See if we can start Markdown's interpretation of H tags to <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/Heading_Elements#multiple_h1" target="_blank">start at 2, since H1</a> is always pulled from the page title metadata. If it isn't easy, I just have to change my pattern of writing in the MD documents.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Should I <a href="https://www.madebymike.com.au/writing/11ty-filters-data-shortcodes/" target="_blank">explore some shortcodes</a>?</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Order projects listing by last posted blog in that project</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Limit the output of home page post lists to a specific number of posts</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Show the latest post below the site intro on the homepage.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Tags pages with Pagination</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Posts should be able to support a preview header image that can also be shown on post lists.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Create a Markdown-It plugin that reads the project's repo URL off the folder data file and renders commit messages with l<a href="https://stackoverflow.com/questions/15919635/on-github-api-what-is-the-best-way-to-get-the-last-commit-message-associated-w" target="_blank">inks to the referenced commit</a>. (Is this even possible?) (Is there a way to do it with eleventy instead?)</p>
</li>
</ul>
<h2 id="day-20" tabindex="-1">Day 20</h2>
<p>Ok, well, first problem was I hadn't switched the variable. Doing that got the reverse working. Let's try removing the array clone.</p>
<p>Hmm. Interesting, doing that appears to keep the tag pages reversed, but the homepage post list from the <code>projectList</code> shortcode is broken again.</p>
<p>I checked <a href="https://github.com/11ty/eleventy/issues/215" target="_blank">this issue</a> first and it looks this was reported, but not this exact context. <a href="https://github.com/11ty/eleventy/issues/352" target="_blank">It looks like it was an issue with getAllSorted</a>. Ok, I'm going to suggest documentation and keep <code>.slice</code> in place. I could potentially use the <code>reverse</code> filter, but I'm not sure that would work well with the functionality I'm trying to create, which gives me the ability to generate and alter these lists using arguments from the Markdown front-matter. It would be good <a href="https://github.com/11ty/11ty-website/pull/1135" target="_blank">to warn that collections manipulated in shortcodes impact other uses of the same collections</a>.</p>
<p>Got a late start so, short day today.</p>
<p><a target="_blank" href="https://github.com/AramZS/devblog/commit/bcc261dba24bbc26d86c539f851f18a1a723512e" class="git-commit-link"><code>git commit -am &quot;Solve issue with shortcodes mutating collections&quot;</code></a></p>
]]></content:encoded>
	</item>
	
	<item>
		<title>Part 19: Project Tag Pages</title>
		<link>https://fightwithtools.dev/posts/projects/devblog/hello-day-19/?source=rss</link>
		<pubDate>Sun, 01 Aug 2021 02:59:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/projects/devblog/hello-day-19/</guid>
		<description>Generating multiple tag pages</description>
		<content:encoded><![CDATA[<h2 id="project-scope-and-todos" tabindex="-1">Project Scope and ToDos</h2>
<ol>
<li>Static Site Generator that can build the blog and let me host it on Github Pages</li>
<li>I want to write posts in Markdown because I'm lazy, it's easy, and it is how I take notes now.</li>
<li>I don't want to spend a ton of time doing design work. I'm doing complicated designs for other projects, so I want to pull a theme I like that I can rely on someone else to keep up.</li>
<li>Once it gets going, I want template changes to be easy.</li>
<li>It should be as easy as Jekyll, so I need to be able to build it using GitHub Actions, where I can just commit a template change or Markdown file and away it goes. If I can't figure this out than fk it, just use Jekyll.</li>
<li>I require it to be used by a significant percent of my professional peers so I can get easy answers when something goes wrong.</li>
<li>I want source maps. This is a dev log site which means whatever I do with it should be easy for other developers to read.</li>
</ol>
<ul class="task-list">
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Also <a href="https://www.npmjs.com/package/@quasibit/eleventy-plugin-sitemap" target="_blank">the sitemap plugin</a> looks cool. Should grab that later.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> So does the <a href="https://www.npmjs.com/package/eleventy-plugin-reading-time" target="_blank">reading time one</a>.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Also <a href="https://github.com/jdsteinbach/eleventy-plugin-toc/" target="_blank">this TOC plugin</a> mby?</p>
</li>
<li class="task-list-item">
<p data-wordfix="true"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Use <a href="https://www.11ty.dev/docs/data-deep-merge/" target="_blank">Data Deep Merge</a> in this blog.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Decide if I want to render the CSS fancier than just a base file and do per-template splitting.</p>
</li>
</ul>
<s>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Can I use the template inside of dinky that already exists instead of copy/pasting it?</li>
</ul>
</s>
<ul class="task-list">
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Is there a way to have permalinks to posts contain metadata without organizing them into subfolders?</p>
</li>
<li class="task-list-item">
<p data-wordfix="true"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> How do I cachebreak files on the basis of new build events? Datetime? <code>site.github.build_revision</code> is <a href="https://github.com/jekyll/github-metadata/blob/master/docs/site.github.md" target="_blank">how Jekyll accomplishes this</a>, but is there a way to push <a href="https://docs.github.com/en/actions/reference/context-and-expression-syntax-for-github-actions#github-context" target="_blank">that</a> <a href="https://stackoverflow.com/questions/54310050/how-to-version-build-artifacts-using-github-actions" target="_blank">into the build process</a> for Eleventy?</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Make link text look less shitty. It looks like it is a whole, lighter, font.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Code blocks do not have good syntax highlighting. I want good syntax highlighting.</p>
</li>
<li class="task-list-item">
<p data-wordfix="true"><input disabled="true" type="checkbox" class="markdown-todo" /> Build a Markdown-it plugin to take my typing shortcuts <code>[prob, b/c, ...?]</code> and expand them on build.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> See if we can start Markdown's interpretation of H tags to <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/Heading_Elements#multiple_h1" target="_blank">start at 2, since H1</a> is always pulled from the page title metadata. If it isn't easy, I just have to change my pattern of writing in the MD documents.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Should I <a href="https://www.madebymike.com.au/writing/11ty-filters-data-shortcodes/" target="_blank">explore some shortcodes</a>?</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Order projects listing by last posted blog in that project</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Limit the output of home page post lists to a specific number of posts</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Show the latest post below the site intro on the homepage.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Tags pages with Pagination</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Posts should be able to support a preview header image that can also be shown on post lists.</p>
</li>
</ul>
<h2 id="day-19" tabindex="-1">Day 19</h2>
<h3 id="oh-let's-turn-on-gpc" tabindex="-1">Oh let's turn on GPC</h3>
<p>Oh, I'm not doing any personalized tracking to turn off, but I might as well register my support for <a href="https://globalprivacycontrol.org/" target="_blank">GPC</a>. It should be easy enough to set up a location for me to store <code>.well-known</code> data and pass it through. I'll have an internal folder at <code>src/_well-known</code> and set up a passthrough copy from there.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-19/#code-skip-hello-day-19-3" id="skip-to-code-skip-hello-day-19-3" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript"><span class="token comment">// added to .eleventy.js</span><br />eleventyConfig<span class="token punctuation">.</span><span class="token function">addPassthroughCopy</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token string-property property">"src/_well-known"</span><span class="token operator">:</span> <span class="token string">".well-known"</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p id="code-skip-hello-day-19-3">Then I can just add a <code>gpc.json</code> file in that folder</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-19/#code-skip-hello-day-19-2" id="skip-to-code-skip-hello-day-19-2" class="skip-link">Skip code block ▼</a></p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span><br />	<span class="token property">"gpc"</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span><br />	<span class="token property">"lastUpdate"</span><span class="token operator">:</span> <span class="token string">"2021-07-31"</span><br /><span class="token punctuation">}</span></code></pre>
<p id="code-skip-hello-day-19-2"><a target="_blank" href="https://github.com/AramZS/devblog/commit/f320bf640e1538d18f03f157f6279dee1111f4c5" class="git-commit-link"><code>git commit -am &quot;Add GPC .well-known file&quot;</code></a></p>
<h3 id="tag-pages-let's-do-it!" tabindex="-1">Tag pages, let's do it!</h3>
<p data-wordfix="true">Huh, my front page posts are no longer reversing properly. I think because <code>reverse</code> <a href="https://www.11ty.dev/docs/collections/#sort-descending" target="_blank">happens in-place</a> it's causing some issues.</p>
<p>Let's clone the array before we operate on it in the shortcode. This will be an easy way to avoid any accidental problems.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-19/#code-skip-hello-day-19-1" id="skip-to-code-skip-hello-day-19-1" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript">	eleventyConfig<span class="token punctuation">.</span><span class="token function">addShortcode</span><span class="token punctuation">(</span><br />		<span class="token string">"projectList"</span><span class="token punctuation">,</span><br />		<span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">collectionName<span class="token punctuation">,</span> collectionOfPosts<span class="token punctuation">,</span> order<span class="token punctuation">,</span> hlevel<span class="token punctuation">,</span> limit</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />			<span class="token keyword">var</span> postCollection <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span><br />			<span class="token keyword">if</span> <span class="token punctuation">(</span>collectionOfPosts<span class="token punctuation">)</span> <span class="token punctuation">{</span><br />				postCollection <span class="token operator">=</span> collectionOfPosts<span class="token punctuation">.</span><span class="token function">slice</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />			<span class="token punctuation">}</span></code></pre>
<p id="code-skip-hello-day-19-1">Ok, good stuff!</p>
<p>Now let's look into pagination of tags pages.</p>
<p>Ok, the reverse is not working again... wtf...</p>
<p data-wordfix="true">Yeah, I'm pretty sure every place I'm calling reverse now is on a clone of the collections array. My post collection pull for the index page isn't reversing, it's just slicing one off the end. I'm not sure why the ordering here is wonky. Especially because it shouldn't even be a problem. <a href="https://www.11ty.dev/docs/collections/#advanced-custom-filtering-and-sorting" target="_blank">According to the Eleventy site</a>:</p>
<blockquote>
<p>Note that while Array .reverse() mutates the array in-place, all Eleventy Collection API methods return new copies of collection arrays and can be modified without side effects to other collections.</p>
</blockquote>
<p>So what is happening here?</p>
<p data-wordfix="true">Should I just use <a href="https://www.11ty.dev/docs/pagination/#reverse-the-data" target="_blank">the reverse call intended for pagination</a> instead?</p>
<p>Got distracted and ended up not finishing. The downside of weekend development.</p>
<p><a target="_blank" href="https://github.com/AramZS/devblog/commit/672899d827824beee1556b3dd22cf7372499c660" class="git-commit-link"><code>git commit -am &quot;First run at tag pages&quot;</code></a></p>
]]></content:encoded>
	</item>
	
	<item>
		<title>Part 18: Tag Pages</title>
		<link>https://fightwithtools.dev/posts/projects/devblog/hello-day-18/?source=rss</link>
		<pubDate>Sat, 31 Jul 2021 02:59:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/projects/devblog/hello-day-18/</guid>
		<description>Ok, I'm still disappointed with markdown-it. So let's take on a different task today. I'm going to take on showing the latest post and the tags pages, if I can pull off both.</description>
		<content:encoded><![CDATA[<h2 id="project-scope-and-todos" tabindex="-1">Project Scope and ToDos</h2>
<ol>
<li>Static Site Generator that can build the blog and let me host it on Github Pages</li>
<li>I want to write posts in Markdown because I'm lazy, it's easy, and it is how I take notes now.</li>
<li>I don't want to spend a ton of time doing design work. I'm doing complicated designs for other projects, so I want to pull a theme I like that I can rely on someone else to keep up.</li>
<li>Once it gets going, I want template changes to be easy.</li>
<li>It should be as easy as Jekyll, so I need to be able to build it using GitHub Actions, where I can just commit a template change or Markdown file and away it goes. If I can't figure this out than fk it, just use Jekyll.</li>
<li>I require it to be used by a significant percent of my professional peers so I can get easy answers when something goes wrong.</li>
<li>I want source maps. This is a dev log site which means whatever I do with it should be easy for other developers to read.</li>
</ol>
<ul class="task-list">
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Also <a href="https://www.npmjs.com/package/@quasibit/eleventy-plugin-sitemap" target="_blank">the sitemap plugin</a> looks cool. Should grab that later.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> So does the <a href="https://www.npmjs.com/package/eleventy-plugin-reading-time" target="_blank">reading time one</a>.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Also <a href="https://github.com/jdsteinbach/eleventy-plugin-toc/" target="_blank">this TOC plugin</a> mby?</p>
</li>
<li class="task-list-item">
<p data-wordfix="true"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Use <a href="https://www.11ty.dev/docs/data-deep-merge/" target="_blank">Data Deep Merge</a> in this blog.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Decide if I want to render the CSS fancier than just a base file and do per-template splitting.</p>
</li>
</ul>
<s>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Can I use the template inside of dinky that already exists instead of copy/pasting it?</li>
</ul>
</s>
<ul class="task-list">
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Is there a way to have permalinks to posts contain metadata without organizing them into subfolders?</p>
</li>
<li class="task-list-item">
<p data-wordfix="true"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> How do I cachebreak files on the basis of new build events? Datetime? <code>site.github.build_revision</code> is <a href="https://github.com/jekyll/github-metadata/blob/master/docs/site.github.md" target="_blank">how Jekyll accomplishes this</a>, but is there a way to push <a href="https://docs.github.com/en/actions/reference/context-and-expression-syntax-for-github-actions#github-context" target="_blank">that</a> <a href="https://stackoverflow.com/questions/54310050/how-to-version-build-artifacts-using-github-actions" target="_blank">into the build process</a> for Eleventy?</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Make link text look less shitty. It looks like it is a whole, lighter, font.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Code blocks do not have good syntax highlighting. I want good syntax highlighting.</p>
</li>
<li class="task-list-item">
<p data-wordfix="true"><input disabled="true" type="checkbox" class="markdown-todo" /> Build a Markdown-it plugin to take my typing shortcuts <code>[prob, b/c, ...?]</code> and expand them on build.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> See if we can start Markdown's interpretation of H tags to <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/Heading_Elements#multiple_h1" target="_blank">start at 2, since H1</a> is always pulled from the page title metadata. If it isn't easy, I just have to change my pattern of writing in the MD documents.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Should I <a href="https://www.madebymike.com.au/writing/11ty-filters-data-shortcodes/" target="_blank">explore some shortcodes</a>?</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Order projects listing by last posted blog in that project</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Limit the output of home page post lists to a specific number of posts</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Show the latest post below the site intro on the homepage.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Tags pages with Pagination</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Posts should be able to support a preview header image that can also be shown on post lists.</p>
</li>
</ul>
<h2 id="day-18" tabindex="-1">Day 18</h2>
<p>Ok, I'm still disappointed with markdown-it. So let's take on a different task today. I'm going to take on showing the latest post and the tags pages, if I can pull off both.</p>
<p>For the home page, it looks like <a href="https://stackoverflow.com/questions/64337175/get-latest-post-to-show-on-home-page-with-eleventy" target="_blank">I can pull a good example</a>. It is dependent on <a href="https://github.com/11ty/eleventy-base-blog/blob/1be6346bde9ebe4afc23d7feaf0370817ad90f15/.eleventy.js#L31" target="_blank">a filter</a> though. Oh this idea, to truncate an array with a filter, is really cool. I wish I hard realized it existed before I set up the limit number on the collection. But I'll pull it over. That said, I prefer to name it what it actually does and call it <code>slice</code>. Ok, now I can have a single post on the homepage. But I don't really want the whole thing. Time to use the &quot;description&quot; metadata key and value. I'll need it for SEO anyway, so good to have something else on the site that uses the value. I want to have a good separator in place to differentiate the post content. I can add an <code>hr</code>, but it will need some custom styling.</p>
<p>I'll use my index-specific Sass here.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-18/#code-skip-hello-day-18-2" id="skip-to-code-skip-hello-day-18-2" class="skip-link">Skip code block ▼</a></p>
<pre class="language-css"><code class="language-css">    .front-post<br />        hr<br />            <span class="token property">margin-bottom</span><span class="token punctuation">:</span> 6px<br />        h3<br />            <span class="token property">margin-top</span><span class="token punctuation">:</span> 2px</code></pre>
<p id="code-skip-hello-day-18-2">Ok, on to the tag pages.</p>
<p>I'll start by duplicating the projects page. Now the question is how to get a list of collections.</p>
<p data-wordfix="true">There doesn't seem to be a native way, but <a href="https://github.com/11ty/eleventy-base-blog/blob/1be6346bde9ebe4afc23d7feaf0370817ad90f15/.eleventy.js#L47" target="_blank">I can build on the techniques that the Eleventy site itself uses</a>.</p>
<p>Ok, what does that create exactly? According to <code>console.log</code>:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-18/#code-skip-hello-day-18-1" id="skip-to-code-skip-hello-day-18-1" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript"><span class="token punctuation">[</span><br />  <span class="token string">'projects'</span><span class="token punctuation">,</span><br />  <span class="token string">'Starters'</span><span class="token punctuation">,</span><br />  <span class="token string">'11ty'</span><span class="token punctuation">,</span><br />  <span class="token string">'Node'</span><span class="token punctuation">,</span><br />  <span class="token string">'Sass'</span><span class="token punctuation">,</span><br />  <span class="token string">'WiP'</span><span class="token punctuation">,</span><br />  <span class="token string">'Github Actions'</span><br /><span class="token punctuation">]</span></code></pre>
<p data-wordfix="true" id="code-skip-hello-day-18-1">Ok and from there I can base the new page off <a href="https://www.11ty.dev/docs/pagination/#paging-a-collection" target="_blank">the example from the eleventy site</a>. It worked! Now I have a set of pages.</p>
<p>I can use my postList shortcode here to get a list of posts. Just have to update it so the posts are linked.</p>
<p>This is a good start, next step is paginating these tag pages!</p>
<p><a target="_blank" href="https://github.com/AramZS/devblog/commit/5c52159e6bd3edfe79a54f8b9e6d66c56cb02c11" class="git-commit-link"><code>git commit -am &quot;Setting up homepage post and tag pages&quot;</code></a></p>
]]></content:encoded>
	</item>
	
	<item>
		<title>Homepage Fixes on Day 17</title>
		<link>https://fightwithtools.dev/posts/projects/devblog/hello-day-17/?source=rss</link>
		<pubDate>Fri, 30 Jul 2021 02:59:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/projects/devblog/hello-day-17/</guid>
		<description>Part 17 of setting up 11ty dev blog.</description>
		<content:encoded><![CDATA[<h2 id="project-scope-and-todos" tabindex="-1">Project Scope and ToDos</h2>
<ol>
<li>Static Site Generator that can build the blog and let me host it on Github Pages</li>
<li>I want to write posts in Markdown because I'm lazy, it's easy, and it is how I take notes now.</li>
<li>I don't want to spend a ton of time doing design work. I'm doing complicated designs for other projects, so I want to pull a theme I like that I can rely on someone else to keep up.</li>
<li>Once it gets going, I want template changes to be easy.</li>
<li>It should be as easy as Jekyll, so I need to be able to build it using GitHub Actions, where I can just commit a template change or Markdown file and away it goes. If I can't figure this out than fk it, just use Jekyll.</li>
<li>I require it to be used by a significant percent of my professional peers so I can get easy answers when something goes wrong.</li>
<li>I want source maps. This is a dev log site which means whatever I do with it should be easy for other developers to read.</li>
</ol>
<ul class="task-list">
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Also <a href="https://www.npmjs.com/package/@quasibit/eleventy-plugin-sitemap" target="_blank">the sitemap plugin</a> looks cool. Should grab that later.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> So does the <a href="https://www.npmjs.com/package/eleventy-plugin-reading-time" target="_blank">reading time one</a>.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Also <a href="https://github.com/jdsteinbach/eleventy-plugin-toc/" target="_blank">this TOC plugin</a> mby?</p>
</li>
<li class="task-list-item">
<p data-wordfix="true"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Use <a href="https://www.11ty.dev/docs/data-deep-merge/" target="_blank">Data Deep Merge</a> in this blog.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Decide if I want to render the CSS fancier than just a base file and do per-template splitting.</p>
</li>
</ul>
<s>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Can I use the template inside of dinky that already exists instead of copy/pasting it?</li>
</ul>
</s>
<ul class="task-list">
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Is there a way to have permalinks to posts contain metadata without organizing them into subfolders?</p>
</li>
<li class="task-list-item">
<p data-wordfix="true"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> How do I cachebreak files on the basis of new build events? Datetime? <code>site.github.build_revision</code> is <a href="https://github.com/jekyll/github-metadata/blob/master/docs/site.github.md" target="_blank">how Jekyll accomplishes this</a>, but is there a way to push <a href="https://docs.github.com/en/actions/reference/context-and-expression-syntax-for-github-actions#github-context" target="_blank">that</a> <a href="https://stackoverflow.com/questions/54310050/how-to-version-build-artifacts-using-github-actions" target="_blank">into the build process</a> for Eleventy?</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Make link text look less shitty. It looks like it is a whole, lighter, font.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Code blocks do not have good syntax highlighting. I want good syntax highlighting.</p>
</li>
<li class="task-list-item">
<p data-wordfix="true"><input disabled="true" type="checkbox" class="markdown-todo" /> Build a Markdown-it plugin to take my typing shortcuts <code>[prob, b/c, ...?]</code> and expand them on build.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> See if we can start Markdown's interpretation of H tags to <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/Heading_Elements#multiple_h1" target="_blank">start at 2, since H1</a> is always pulled from the page title metadata. If it isn't easy, I just have to change my pattern of writing in the MD documents.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Should I <a href="https://www.madebymike.com.au/writing/11ty-filters-data-shortcodes/" target="_blank">explore some shortcodes</a>?</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Order projects listing by last posted blog in that project</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Limit the output of home page post lists to a specific number of posts</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Show the latest post below the site intro on the homepage.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Tags pages with Pagination</p>
</li>
</ul>
<h2 id="day-17" tabindex="-1">Day 17</h2>
<p>So as of last time I checked out <a href="https://docs.joshuatz.com/cheatsheets/node-and-npm/markdown-it/" target="_blank">this walkthrough</a>.</p>
<p>It has a little more information for me to use than the Markdown-it documentation. It also recommended I check out one of the markdown-it plugins I was actually able to get working. <a href="https://github.com/valeriangalliat/markdown-it-anchor/blob/HEAD/index.js" target="_blank">So let's do that</a>.</p>
<p>Just looking at my homepage and realizing I need to add some to-dos:</p>
<ul class="task-list">
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Order projects listing by last posted blog in that project</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Limit the output of home page post lists to a specific number of posts</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Show the latest post below the site intro on the homepage.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Tags pages with Pagination</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Posts should be able to support a preview header image that can also be shown on post lists.</p>
</li>
</ul>
<p>Ok, let's take on projects by last updated. I guess this means another field to add to that projects object. I guess I'll start off by getting the front matter. I guess the first step is pulling in a markdown frontmatter processor.</p>
<p data-wordfix="true">It looks <a href="https://www.npmjs.com/package/markdown-it-front-matter" target="_blank">like <code>markdown-it</code> doesn't ship with frontmatter parsing</a>. <a href="https://www.11ty.dev/docs/data-frontmatter/" target="_blank">Eleventy uses grey-matter to handle frontmatter</a> so if I pull that package in it won't increase our NPM package footprint.</p>
<p>Ok, so with that in hand, let's get the file content.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-17/#code-skip-hello-day-17-4" id="skip-to-code-skip-hello-day-17-4" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> <span class="token punctuation">{</span> readdirSync<span class="token punctuation">,</span> readFileSync <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">"fs"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token keyword">const</span> path <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">"path"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token keyword">const</span> matter <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">"gray-matter"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token comment">// ...</span><br />	<span class="token keyword">const</span> projectFilesContent <span class="token operator">=</span> projectFiles<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">filePath</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />		<span class="token keyword">return</span> <span class="token function">readFileSync</span><span class="token punctuation">(</span><br />			path<span class="token punctuation">.</span><span class="token function">resolve</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">./src/posts/projects/</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>projectDir<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">/</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>filePath<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><br />		<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toString</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// Don't forget the `toString` part!</span><br />	<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p id="code-skip-hello-day-17-4">Gotta remember to use <code>path</code> in this because otherwise it just gives me the last portion of the path.</p>
<p>Ok, so let's use grey-matter to pull out that data. Where on the object does it live? I'm not getting anything yet.</p>
<p>Ok, it's because the front-matter data lives on <code>object.data</code> so my date is at <code>object.data.date</code>. Cool. Ok, got it working now. I can use <code>Array.reduce</code> here to figure out the most recent date.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-17/#code-skip-hello-day-17-3" id="skip-to-code-skip-hello-day-17-3" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript">	lastUpdated <span class="token operator">=</span> projectFilesContent<span class="token punctuation">.</span><span class="token function">reduce</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">prevValue<span class="token punctuation">,</span> fileContent</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />		<span class="token keyword">try</span> <span class="token punctuation">{</span><br />			<span class="token keyword">const</span> mdObject <span class="token operator">=</span> <span class="token function">matter</span><span class="token punctuation">(</span>fileContent<span class="token punctuation">)</span><span class="token punctuation">;</span><br />			<span class="token comment">// console.log("data", mdObject.data);</span><br />			<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>mdObject<span class="token punctuation">.</span>data <span class="token operator">||</span> <span class="token operator">!</span>mdObject<span class="token punctuation">.</span>data<span class="token punctuation">.</span>date<span class="token punctuation">)</span> <span class="token punctuation">{</span><br />				<span class="token keyword">return</span> <span class="token number">0</span><span class="token punctuation">;</span><br />			<span class="token punctuation">}</span><br />			<span class="token keyword">const</span> datetime <span class="token operator">=</span> Date<span class="token punctuation">.</span><span class="token function">parse</span><span class="token punctuation">(</span>mdObject<span class="token punctuation">.</span>data<span class="token punctuation">.</span>date<span class="token punctuation">)</span><span class="token punctuation">;</span><br />			<span class="token keyword">if</span> <span class="token punctuation">(</span>prevValue <span class="token operator">></span> datetime<span class="token punctuation">)</span> <span class="token punctuation">{</span><br />				<span class="token keyword">return</span> prevValue<span class="token punctuation">;</span><br />			<span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span><br />				<span class="token keyword">return</span> datetime<span class="token punctuation">;</span><br />			<span class="token punctuation">}</span><br />		<span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span>e<span class="token punctuation">)</span> <span class="token punctuation">{</span><br />			console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">"Could not find date"</span><span class="token punctuation">,</span> e<span class="token punctuation">)</span><span class="token punctuation">;</span><br />			<span class="token keyword">return</span> <span class="token number">0</span><span class="token punctuation">;</span><br />		<span class="token punctuation">}</span><br />	<span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p id="code-skip-hello-day-17-3">And then I can sort it.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-17/#code-skip-hello-day-17-2" id="skip-to-code-skip-hello-day-17-2" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript">directorySet<span class="token punctuation">.</span><span class="token function">sort</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">a<span class="token punctuation">,</span> b</span><span class="token punctuation">)</span> <span class="token operator">=></span> b<span class="token punctuation">.</span>lastUpdatedPost <span class="token operator">-</span> a<span class="token punctuation">.</span>lastUpdatedPost<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p id="code-skip-hello-day-17-2">Done!</p>
<p>Ok, now I can limit the posts output on the homepage by adding a limit count ot the shortcode.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-17/#code-skip-hello-day-17-1" id="skip-to-code-skip-hello-day-17-1" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript">	eleventyConfig<span class="token punctuation">.</span><span class="token function">addShortcode</span><span class="token punctuation">(</span><br />		<span class="token string">"projectList"</span><span class="token punctuation">,</span><br />		<span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">collectionName<span class="token punctuation">,</span> collectionOfPosts<span class="token punctuation">,</span> order<span class="token punctuation">,</span> hlevel<span class="token punctuation">,</span> limit</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />		<span class="token comment">// ...</span><br />			<span class="token keyword">if</span> <span class="token punctuation">(</span>collectionOfPosts <span class="token operator">&amp;&amp;</span> limit<span class="token punctuation">)</span> <span class="token punctuation">{</span><br />				collectionOfPosts <span class="token operator">=</span> collectionOfPosts<span class="token punctuation">.</span><span class="token function">slice</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> limit<span class="token punctuation">)</span><span class="token punctuation">;</span><br />			<span class="token punctuation">}</span></code></pre>
<p id="code-skip-hello-day-17-1">Works!</p>
<p><a target="_blank" href="https://github.com/AramZS/devblog/commit/a0d669c443f642038be890304bd4d10dea002045" class="git-commit-link"><code>git commit -am &quot;Improve homepage outputs and ordering!&quot; </code></a></p>
]]></content:encoded>
	</item>
	
	<item>
		<title>Part 16: Taking a run at Markdown It Plugins</title>
		<link>https://fightwithtools.dev/posts/projects/devblog/hello-day-16/?source=rss</link>
		<pubDate>Mon, 26 Jul 2021 02:59:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/projects/devblog/hello-day-16/</guid>
		<description>Day 16 of setting up 11ty dev blog.</description>
		<content:encoded><![CDATA[<h2 id="project-scope-and-todos" tabindex="-1">Project Scope and ToDos</h2>
<ol>
<li>Static Site Generator that can build the blog and let me host it on Github Pages</li>
<li>I want to write posts in Markdown because I'm lazy, it's easy, and it is how I take notes now.</li>
<li>I don't want to spend a ton of time doing design work. I'm doing complicated designs for other projects, so I want to pull a theme I like that I can rely on someone else to keep up.</li>
<li>Once it gets going, I want template changes to be easy.</li>
<li>It should be as easy as Jekyll, so I need to be able to build it using GitHub Actions, where I can just commit a template change or Markdown file and away it goes. If I can't figure this out than fk it, just use Jekyll.</li>
<li>I require it to be used by a significant percent of my professional peers so I can get easy answers when something goes wrong.</li>
<li>I want source maps. This is a dev log site which means whatever I do with it should be easy for other developers to read.</li>
</ol>
<ul class="task-list">
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Also <a href="https://www.npmjs.com/package/@quasibit/eleventy-plugin-sitemap" target="_blank">the sitemap plugin</a> looks cool. Should grab that later.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> So does the <a href="https://www.npmjs.com/package/eleventy-plugin-reading-time" target="_blank">reading time one</a>.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Also <a href="https://github.com/jdsteinbach/eleventy-plugin-toc/" target="_blank">this TOC plugin</a> mby?</p>
</li>
<li class="task-list-item">
<p data-wordfix="true"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Use <a href="https://www.11ty.dev/docs/data-deep-merge/" target="_blank">Data Deep Merge</a> in this blog.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Decide if I want to render the CSS fancier than just a base file and do per-template splitting.</p>
</li>
</ul>
<s>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Can I use the template inside of dinky that already exists instead of copy/pasting it?</li>
</ul>
</s>
<ul class="task-list">
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Is there a way to have permalinks to posts contain metadata without organizing them into subfolders?</p>
</li>
<li class="task-list-item">
<p data-wordfix="true"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> How do I cachebreak files on the basis of new build events? Datetime? <code>site.github.build_revision</code> is <a href="https://github.com/jekyll/github-metadata/blob/master/docs/site.github.md" target="_blank">how Jekyll accomplishes this</a>, but is there a way to push <a href="https://docs.github.com/en/actions/reference/context-and-expression-syntax-for-github-actions#github-context" target="_blank">that</a> <a href="https://stackoverflow.com/questions/54310050/how-to-version-build-artifacts-using-github-actions" target="_blank">into the build process</a> for Eleventy?</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Make link text look less shitty. It looks like it is a whole, lighter, font.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Code blocks do not have good syntax highlighting. I want good syntax highlighting.</p>
</li>
<li class="task-list-item">
<p data-wordfix="true"><input disabled="true" type="checkbox" class="markdown-todo" /> Build a Markdown-it plugin to take my typing shortcuts <code>[prob, b/c, ...?]</code> and expand them on build.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> See if we can start Markdown's interpretation of H tags to <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/Heading_Elements#multiple_h1" target="_blank">start at 2, since H1</a> is always pulled from the page title metadata. If it isn't easy, I just have to change my pattern of writing in the MD documents.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Should I <a href="https://www.madebymike.com.au/writing/11ty-filters-data-shortcodes/" target="_blank">explore some shortcodes</a>?</p>
</li>
</ul>
<h2 id="day-16" tabindex="-1">Day 16</h2>
<p>Ok, so I'd like to continue using my shortcuts like <code>b/c</code> or <code>prob</code>. Seems like the way to go there is to set it up as a markdown-it shortcode. I'd like to try my hand at that.</p>
<h3 id="run-one-at-a-markdown-it-plugins" tabindex="-1">Run One at a Markdown It Plugins</h3>
<p>We can take a look at <a href="https://github.com/markdown-it/markdown-it#api" target="_blank">Markdown-it's documentation</a> for help here.</p>
<p>Oh, README says this is the wrong place to look at for plugins. Ok.</p>
<p><a href="https://github.com/markdown-it/markdown-it/tree/master/docs" target="_blank">Info for plugin developers</a>... ok, two links in here.</p>
<p data-wordfix="true">Ok... I'm not sure how useful these are. The douments are nice for understanding the philosophy involved. But not great to kick me off. Ok, <a href="https://github.com/markdown-it/markdown-it/blob/master/docs/development.md#general-considerations-for-plugins" target="_blank">let's take recommendation 2</a> and look at some existing plugins. It sounds like I might possibly conflict with other plugins, so I probably should use an inline or block rule. That's useful.</p>
<p>Oh, this looks useful and like a good idea, <a href="https://www.npmjs.com/package/markdown-it-anchor" target="_blank">anchor links on my headers</a>.</p>
<p>Let's try and pull it in along with a slugify method that can make for clear URLs.</p>
<p>It recommends I use <code>'@sindresorhus/slugify'</code> or <code>string</code> to handle the slugify process. The 2nd is basic, but the first doesn't work well with how I structured this project. (It requires being called from a module, and my project isn't set up that way.) So, I'll use <code>slugify</code> which I have used in other projects in the past.</p>
<p>Ok, that worked!</p>
<p><a target="_blank" href="https://github.com/AramZS/devblog/commit/f7e81ae7548dda8e7f9186f9a0d4861b366a7482" class="git-commit-link"><code>git commit -am &quot;Add anchors to headers&quot;</code></a></p>
<p>Oh, there are some good looking markdown-it plugins here. I'm going to install <a href="https://www.npmjs.com/package/@gerhobbelt/markdown-it-footnote" target="_blank">the footnote one</a> as well. Oh that didn't work. I'll try <a href="https://github.com/markdown-it/markdown-it-footnote" target="_blank">the base one instead</a> in a little bit.</p>
<h3 id="trying-to-figure-out-the-markdown-it-data-structure" tabindex="-1">Trying to Figure Out the Markdown It Data Structure</h3>
<p>Ok... What's a basic looking plugin I can look at easily as an example? The <a href="https://github.com/kwvanderlinde/markdown-it-wikilinks/blob/master/index.js" target="_blank">Wikilinks plugin</a> looks good.</p>
<p>Ok so... no particular described format and I don't feel like digging through the markdown-it code to figure out how these plugins are supposed to work. Not the most developer friendly library I guess.</p>
<p>Ok, to facilitate a similar structure, I'll take the Wikilinks plugin and place it in my own folder under <code>_custom-plugins</code>. I'm not going to be taking in options right now, so I can remove that stuff from the plugin.</p>
<p>The plugin looks like it is very dependent on a modules called <code>markdown-it-regexp</code>. So let's <a href="https://github.com/rlidwka/markdown-it-regexp" target="_blank">check out how that works</a>. It <a href="https://github.com/rlidwka/markdown-it-regexp/blob/master/lib/index.js#L61" target="_blank">looks like it handles regex rules and does the work of registering those rules</a> with the Markdown-it rules manager called <code>ruler</code>. It seems to take two arguments, a regex pattern and a function to run on that regex pattern. All this seems relatively straightforward, which makes me feel a lot better about using a library that doesn't seem to have had any activity since 2016.</p>
<p>I have to admit, I'm not super thrilled with Markdown-it. <a href="https://glitch.com/edit/#!/thespin?path=markdown-to-col.js%3A1%3A0" target="_blank">Normally I use</a> <a href="https://www.npmjs.com/package/showdown" target="_blank">Showdown</a> for Markdown parsing, but a lot of the Eleventy docs push Markdown-it. I guess I'll stick with it for now, but I'm not sure I'd recommend it or use it in a future project.</p>
<p>Ok, let's strip it down to the basics.</p>
<p data-wordfix="true">First my regex, I want to replace my use of <code>prob</code> with <code>probably</code>. So easy enough, gotta surround it with spaces. <code>/\sprob\s/</code> is a start. But it looks from the example that I should also have a capture group. Ok so instead I'll make it <code>/\s(prob)\s/,</code> Let's assume I'll eventually have a bunch of patterns, so I need to check to see that the pattern is giving me back one of a set of specific patterns. Then I can apply my specific transform.</p>
<p>Hmmm it should work now, but I'm not seeing any results. I tried adding a console.log, but still nothing.</p>
<p>Oh, oops, the pattern I'm using from the Wikilinks plugin, <a href="https://github.com/kwvanderlinde/markdown-it-wikilinks#usage" target="_blank">means I have to execute it as a function first</a>.</p>
<p>Hmmmm. Still no go. Is the plugin even initiating? Let's put a console.log outside of the return statement and see.</p>
<p>Ok, the console.log outside of the return fired (once I exited watch mode and restarted it, I guess plugins don't get reloaded during <code>watch</code> mode?). But it isn't treating my text?</p>
<h3 id="markdown-it-and-regexp" tabindex="-1">Markdown It and Regexp</h3>
<p>Ok, <a href="https://jsfiddle.net/yd2gLxev/" target="_blank">the sample code</a> given in the Readme of <code>markdown-it-regexp</code> doesn't work. It's just failing silently. This isn't a good sign. But there seem to be more modern plugins using it fine? Ok, the issue seems to be with how the jsfiddle is setup. When I set it up in a Glitch site, it seems to work just fine.</p>
<p>Ok, now I am even more annoyed that this isn't working. It should, by all rights. All I can think is that it must have something to do with the specific way eleventy implements Markdown-It?</p>
<p>I tried returning the <code>Plugin</code> function from <code>markdown-it-regexp</code>. No go there either. Frustrating. Just none of this stuff is executing. I'm starting to think that maybe this is a lost cause. It isn't working and I'm wondering if I should <a href="https://www.npmjs.com/package/markdown-it-regex" target="_blank">switch to trying out another option</a>. Nothing but silent failures. Nothing is working.</p>
<p>Ok, trying to use <a href="https://www.npmjs.com/package/markdown-it-regex" target="_blank">markdown-it-regex</a>. But it won't work either. I keep getting <code>plugin.apply is not a function</code>. Which makes me think the problem with the last plugin might be showing up here, where the way the markdown-it tool is being applied by eleventy isn't normal or at least isn't what some of these plugin authors expect.</p>
<p>Ok, nothing working here. Time to switch approaches. <a href="https://docs.joshuatz.com/cheatsheets/node-and-npm/markdown-it/" target="_blank">This walkthrough looks like it might be promising</a>.</p>
<p><a target="_blank" href="https://github.com/AramZS/devblog/commit/89bf4940ef9ccd80deef9151549a3fd1da77d66a" class="git-commit-link"><code>git commit -am &quot;Day 16 - I fail to write a Markdown-it plugin&quot;</code></a></p>
]]></content:encoded>
	</item>
	
	<item>
		<title>Part 15: Mobile Style Tweaks</title>
		<link>https://fightwithtools.dev/posts/projects/devblog/hello-day-15/?source=rss</link>
		<pubDate>Sun, 25 Jul 2021 02:59:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/projects/devblog/hello-day-15/</guid>
		<description>Day 15 of setting up 11ty dev blog.</description>
		<content:encoded><![CDATA[<h2 id="project-scope-and-todos" tabindex="-1">Project Scope and ToDos</h2>
<ol>
<li>Static Site Generator that can build the blog and let me host it on Github Pages</li>
<li>I want to write posts in Markdown because I'm lazy, it's easy, and it is how I take notes now.</li>
<li>I don't want to spend a ton of time doing design work. I'm doing complicated designs for other projects, so I want to pull a theme I like that I can rely on someone else to keep up.</li>
<li>Once it gets going, I want template changes to be easy.</li>
<li>It should be as easy as Jekyll, so I need to be able to build it using GitHub Actions, where I can just commit a template change or Markdown file and away it goes. If I can't figure this out than fk it, just use Jekyll.</li>
<li>I require it to be used by a significant percent of my professional peers so I can get easy answers when something goes wrong.</li>
<li>I want source maps. This is a dev log site which means whatever I do with it should be easy for other developers to read.</li>
</ol>
<ul class="task-list">
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Also <a href="https://www.npmjs.com/package/@quasibit/eleventy-plugin-sitemap" target="_blank">the sitemap plugin</a> looks cool. Should grab that later.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> So does the <a href="https://www.npmjs.com/package/eleventy-plugin-reading-time" target="_blank">reading time one</a>.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Also <a href="https://github.com/jdsteinbach/eleventy-plugin-toc/" target="_blank">this TOC plugin</a> mby?</p>
</li>
<li class="task-list-item">
<p data-wordfix="true"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Use <a href="https://www.11ty.dev/docs/data-deep-merge/" target="_blank">Data Deep Merge</a> in this blog.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Decide if I want to render the CSS fancier than just a base file and do per-template splitting.</p>
</li>
</ul>
<s>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Can I use the template inside of dinky that already exists instead of copy/pasting it?</li>
</ul>
</s>
<ul class="task-list">
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Is there a way to have permalinks to posts contain metadata without organizing them into subfolders?</p>
</li>
<li class="task-list-item">
<p data-wordfix="true"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> How do I cachebreak files on the basis of new build events? Datetime? <code>site.github.build_revision</code> is <a href="https://github.com/jekyll/github-metadata/blob/master/docs/site.github.md" target="_blank">how Jekyll accomplishes this</a>, but is there a way to push <a href="https://docs.github.com/en/actions/reference/context-and-expression-syntax-for-github-actions#github-context" target="_blank">that</a> <a href="https://stackoverflow.com/questions/54310050/how-to-version-build-artifacts-using-github-actions" target="_blank">into the build process</a> for Eleventy?</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Make link text look less shitty. It looks like it is a whole, lighter, font.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Code blocks do not have good syntax highlighting. I want good syntax highlighting.</p>
</li>
<li class="task-list-item">
<p data-wordfix="true"><input disabled="true" type="checkbox" class="markdown-todo" /> Build a Markdown-it plugin to take my typing shortcuts <code>[prob, b/c, ...?]</code> and expand them on build.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> See if we can start Markdown's interpretation of H tags to <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/Heading_Elements#multiple_h1" target="_blank">start at 2, since H1</a> is always pulled from the page title metadata. If it isn't easy, I just have to change my pattern of writing in the MD documents.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Should I <a href="https://www.madebymike.com.au/writing/11ty-filters-data-shortcodes/" target="_blank">explore some shortcodes</a>?</p>
</li>
</ul>
<h2 id="day-15" tabindex="-1">Day 15</h2>
<p>Ok, let's add a little styling to handle mobile devices. Looking at the sizes the changes happen and also when the lines tend to start to break, I think I want a custom break point for the frontpage grid.</p>
<p>I'll put <code>$mobile-width: 890px</code> at the top of my stylesheet and set the width there. Then I can reuse it on per-unit queries like:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-15/#code-skip-hello-day-15-4" id="skip-to-code-skip-hello-day-15-4" class="skip-link">Skip code block ▼</a></p>
<pre class="language-css"><code class="language-css">        @media <span class="token punctuation">(</span><span class="token property">max-width</span><span class="token punctuation">:</span> $mobile-width<span class="token punctuation">)</span><br />            <span class="token property">display</span><span class="token punctuation">:</span> block</code></pre>
<p id="code-skip-hello-day-15-4">Ok, I want to set a link to the home page on every page. I started with a query to check for <code>/posts</code> and <code>/projects</code> in the base template. But I don't like how it looks if it is below the main content of the header. Let's switch up the design.</p>
<p>Ok, that's looking better. But I want the title of the page to span longer then it does now.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-15/#code-skip-hello-day-15-3" id="skip-to-code-skip-hello-day-15-3" class="skip-link">Skip code block ▼</a></p>
<pre class="language-css"><code class="language-css">@media print<span class="token punctuation">,</span> screen and <span class="token punctuation">(</span><span class="token property">max-width</span><span class="token punctuation">:</span> $large-mobile<span class="token punctuation">)</span><br />    header<br />        <span class="token property">padding-right</span><span class="token punctuation">:</span> 260px</code></pre>
<p id="code-skip-hello-day-15-3">Hm. That's not working.</p>
<p>I'll come back to it in a second. I want to get a breadcrumb path working, but there's no way to split the URL at the build process, at least not one that I can see that's built in. I guess the answer is a filter I can run the URL through.</p>
<p>To manipulate chunks of the URL I am going to have to turn the URL into an array and manipulate it, along with handling the domain env variable.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-15/#code-skip-hello-day-15-2" id="skip-to-code-skip-hello-day-15-2" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript">	eleventyConfig<span class="token punctuation">.</span><span class="token function">addFilter</span><span class="token punctuation">(</span><span class="token string">"relproject"</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">url</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />		<span class="token keyword">var</span> urlArray <span class="token operator">=</span> url<span class="token punctuation">.</span><span class="token function">split</span><span class="token punctuation">(</span><span class="token string">'/'</span><span class="token punctuation">)</span><br />		<span class="token keyword">var</span> urlFiltered <span class="token operator">=</span> urlArray<span class="token punctuation">.</span><span class="token function">filter</span><span class="token punctuation">(</span><span class="token parameter">e</span> <span class="token operator">=></span> e<span class="token punctuation">.</span>length <span class="token operator">></span> <span class="token number">0</span><span class="token punctuation">)</span><br />		urlFiltered<span class="token punctuation">.</span><span class="token function">pop</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token comment">// Remove post path</span><br />		urlFiltered<span class="token punctuation">.</span><span class="token function">shift</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token comment">// Remove `posts/`</span><br />		<span class="token keyword">return</span> process<span class="token punctuation">.</span>env<span class="token punctuation">.</span><span class="token constant">DOMAIN</span> <span class="token operator">+</span> <span class="token string">'/'</span> <span class="token operator">+</span> urlFiltered<span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span><span class="token string">'/'</span><span class="token punctuation">)</span><br />	  <span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre>
<p id="code-skip-hello-day-15-2">Now I can use it in a template tag like this:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-15/#code-skip-hello-day-15-1" id="skip-to-code-skip-hello-day-15-1" class="skip-link">Skip code block ▼</a></p>
<pre class="language-liquid"><code class="language-liquid"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>a</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>project-link<span class="token punctuation">"</span></span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>{{ page.url | relproject }}<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>{{project}}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>a</span><span class="token punctuation">></span></span></code></pre>
<p id="code-skip-hello-day-15-1">Ok, back to SaaS. What's going on there?</p>
<p>Oops, forgot to give it a <code>px</code> for the unit type.</p>
<p>Ok. That works now.</p>
<p><a target="_blank" href="https://github.com/AramZS/devblog/commit/e09597eb8e2539dbdfb2dd861fa5356886296eb3" class="git-commit-link"><code>git commit -am &quot;Set up changes to styles and add some additional elements to the design&quot;</code></a></p>
]]></content:encoded>
	</item>
	
	<item>
		<title>Part 14: Project Pages</title>
		<link>https://fightwithtools.dev/posts/projects/devblog/hello-day-14/?source=rss</link>
		<pubDate>Sat, 24 Jul 2021 02:59:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/projects/devblog/hello-day-14/</guid>
		<description>Day 14 of setting up 11ty dev blog.</description>
		<content:encoded><![CDATA[<h2 id="project-scope-and-todos" tabindex="-1">Project Scope and ToDos</h2>
<ol>
<li>Static Site Generator that can build the blog and let me host it on Github Pages</li>
<li>I want to write posts in Markdown because I'm lazy, it's easy, and it is how I take notes now.</li>
<li>I don't want to spend a ton of time doing design work. I'm doing complicated designs for other projects, so I want to pull a theme I like that I can rely on someone else to keep up.</li>
<li>Once it gets going, I want template changes to be easy.</li>
<li>It should be as easy as Jekyll, so I need to be able to build it using GitHub Actions, where I can just commit a template change or Markdown file and away it goes. If I can't figure this out than fk it, just use Jekyll.</li>
<li>I require it to be used by a significant percent of my professional peers so I can get easy answers when something goes wrong.</li>
<li>I want source maps. This is a dev log site which means whatever I do with it should be easy for other developers to read.</li>
</ol>
<ul class="task-list">
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Also <a href="https://www.npmjs.com/package/@quasibit/eleventy-plugin-sitemap" target="_blank">the sitemap plugin</a> looks cool. Should grab that later.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> So does the <a href="https://www.npmjs.com/package/eleventy-plugin-reading-time" target="_blank">reading time one</a>.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Also <a href="https://github.com/jdsteinbach/eleventy-plugin-toc/" target="_blank">this TOC plugin</a> mby?</p>
</li>
<li class="task-list-item">
<p data-wordfix="true"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Use <a href="https://www.11ty.dev/docs/data-deep-merge/" target="_blank">Data Deep Merge</a> in this blog.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Decide if I want to render the CSS fancier than just a base file and do per-template splitting.</p>
</li>
</ul>
<s>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Can I use the template inside of dinky that already exists instead of copy/pasting it?</li>
</ul>
</s>
<ul class="task-list">
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Is there a way to have permalinks to posts contain metadata without organizing them into subfolders?</p>
</li>
<li class="task-list-item">
<p data-wordfix="true"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> How do I cachebreak files on the basis of new build events? Datetime? <code>site.github.build_revision</code> is <a href="https://github.com/jekyll/github-metadata/blob/master/docs/site.github.md" target="_blank">how Jekyll accomplishes this</a>, but is there a way to push <a href="https://docs.github.com/en/actions/reference/context-and-expression-syntax-for-github-actions#github-context" target="_blank">that</a> <a href="https://stackoverflow.com/questions/54310050/how-to-version-build-artifacts-using-github-actions" target="_blank">into the build process</a> for Eleventy?</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Make link text look less shitty. It looks like it is a whole, lighter, font.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Code blocks do not have good syntax highlighting. I want good syntax highlighting.</p>
</li>
<li class="task-list-item">
<p data-wordfix="true"><input disabled="true" type="checkbox" class="markdown-todo" /> Build a Markdown-it plugin to take my typing shortcuts <code>[prob, b/c, ...?]</code> and expand them on build.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> See if we can start Markdown's interpretation of H tags to <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/Heading_Elements#multiple_h1" target="_blank">start at 2, since H1</a> is always pulled from the page title metadata. If it isn't easy, I just have to change my pattern of writing in the MD documents.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Should I <a href="https://www.madebymike.com.au/writing/11ty-filters-data-shortcodes/" target="_blank">explore some shortcodes</a>?</p>
</li>
</ul>
<h2 id="day-14" tabindex="-1">Day 14</h2>
<p>Ok, let's work though making these vertical pages a little more functional. We'll start with the home page. I want to have links to the project pages, so I'm going to need to build a URL for those. To do that I think I'll need to place it into my <code>projects</code> object. I can use the same technique of environment variables I set up for the feeds to have proper absolute links here.</p>
<p>I'll add this to <code>project.js</code>.</p>
<p><code>url: (function(){ return process.env.DOMAIN + &quot;/projects/&quot; + projectDir })(),</code></p>
<p>Then I can use this data property to build the template links that go out to the project pages.</p>
<p>I don't like the lack of headers, I'll add an <code>hlevel</code> argument to my shortcode to allow me to set headers on each post list.</p>
<p>Good list headers now! Time to add links to the other post lists. I also want to format the post titles with the project name. To do that I'm going to create another shortcode that formats the post titles a little differently.</p>
<p>This also seems like a good time to move my posts over to the right folder.</p>
<p>Ok, adding the site name to the non-index pages and now its time to do some css.</p>
<p><a target="_blank" href="https://github.com/AramZS/devblog/commit/a3c97b376a74b52a6b79a1d4e2b33bcbe634d061" class="git-commit-link"><code>git commit -am &quot;Done with setting up vertical content, on to vertical styles.&quot;</code></a></p>
<h3 id="better-styles-ready-for-reuse" tabindex="-1">Better styles, ready for reuse</h3>
<p>Ok, to get the layouts the way I want while still having the base template be very reusable, I need to have some custom CSS that applies only to specific pages. I can handle that by adding an ID with the template name to the <code>body</code> HTML tag. That's easy. But I don't want to load down the CSS file with these file specific rules where I don't need them. So let's accomplish one of my early goals and split the CSS into smaller files.</p>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Decide if I want to render the CSS fancier than just a base file and do per-template splitting.</li>
</ul>
<p><a target="_blank" href="https://github.com/AramZS/devblog/commit/1b54c1065efece52cc16ad263a139c94b88f34f8" class="git-commit-link"><code>git commit -am &quot;Set up SASS &gt; CSS Code spliting with template selection&quot;</code></a></p>
<p>Very annoying that SASS changes don't cause a watch trigger. I'll need to handle that.</p>
<p><code>eleventyConfig.addWatchTarget(&quot;./src/_sass&quot;);</code></p>
<p>Ok. It's looking good now. A basic grid layout that can fit inside the 650px wide main body. I'll need to add some media queries too, but it's the direction I want to go.</p>
<p>Dinner time!</p>
<p><a target="_blank" href="https://github.com/AramZS/devblog/commit/c4b46a5ddf48381abd857df2be689252bcec001d" class="git-commit-link"><code>git commit -am &quot;Add front page styles&quot;</code></a></p>
]]></content:encoded>
	</item>
	
	<item>
		<title>Part 13: Building new Eleventy Taxonomies</title>
		<link>https://fightwithtools.dev/posts/projects/devblog/hello-day-13/?source=rss</link>
		<pubDate>Fri, 23 Jul 2021 02:59:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/projects/devblog/hello-day-13/</guid>
		<description>Day 13 of setting up 11ty dev blog.</description>
		<content:encoded><![CDATA[<h2 id="project-scope-and-todos" tabindex="-1">Project Scope and ToDos</h2>
<ol>
<li>Static Site Generator that can build the blog and let me host it on Github Pages</li>
<li>I want to write posts in Markdown because I'm lazy, it's easy, and it is how I take notes now.</li>
<li>I don't want to spend a ton of time doing design work. I'm doing complicated designs for other projects, so I want to pull a theme I like that I can rely on someone else to keep up.</li>
<li>Once it gets going, I want template changes to be easy.</li>
<li>It should be as easy as Jekyll, so I need to be able to build it using GitHub Actions, where I can just commit a template change or Markdown file and away it goes. If I can't figure this out than fk it, just use Jekyll.</li>
<li>I require it to be used by a significant percent of my professional peers so I can get easy answers when something goes wrong.</li>
<li>I want source maps. This is a dev log site which means whatever I do with it should be easy for other developers to read.</li>
</ol>
<ul class="task-list">
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Also <a href="https://www.npmjs.com/package/@quasibit/eleventy-plugin-sitemap" target="_blank">the sitemap plugin</a> looks cool. Should grab that later.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> So does the <a href="https://www.npmjs.com/package/eleventy-plugin-reading-time" target="_blank">reading time one</a>.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Also <a href="https://github.com/jdsteinbach/eleventy-plugin-toc/" target="_blank">this TOC plugin</a> mby?</p>
</li>
<li class="task-list-item">
<p data-wordfix="true"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Use <a href="https://www.11ty.dev/docs/data-deep-merge/" target="_blank">Data Deep Merge</a> in this blog.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Decide if I want to render the CSS fancier than just a base file and do per-template splitting.</p>
</li>
</ul>
<s>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Can I use the template inside of dinky that already exists instead of copy/pasting it?</li>
</ul>
</s>
<ul class="task-list">
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Is there a way to have permalinks to posts contain metadata without organizing them into subfolders?</p>
</li>
<li class="task-list-item">
<p data-wordfix="true"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> How do I cachebreak files on the basis of new build events? Datetime? <code>site.github.build_revision</code> is <a href="https://github.com/jekyll/github-metadata/blob/master/docs/site.github.md" target="_blank">how Jekyll accomplishes this</a>, but is there a way to push <a href="https://docs.github.com/en/actions/reference/context-and-expression-syntax-for-github-actions#github-context" target="_blank">that</a> <a href="https://stackoverflow.com/questions/54310050/how-to-version-build-artifacts-using-github-actions" target="_blank">into the build process</a> for Eleventy?</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Make link text look less shitty. It looks like it is a whole, lighter, font.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Code blocks do not have good syntax highlighting. I want good syntax highlighting.</p>
</li>
<li class="task-list-item">
<p data-wordfix="true"><input disabled="true" type="checkbox" class="markdown-todo" /> Build a Markdown-it plugin to take my typing shortcuts <code>[prob, b/c, ...?]</code> and expand them on build.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> See if we can start Markdown's interpretation of H tags to <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/Heading_Elements#multiple_h1" target="_blank">start at 2, since H1</a> is always pulled from the page title metadata. If it isn't easy, I just have to change my pattern of writing in the MD documents.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Should I <a href="https://www.madebymike.com.au/writing/11ty-filters-data-shortcodes/" target="_blank">explore some shortcodes</a>?</p>
</li>
</ul>
<h2 id="day-13" tabindex="-1">Day 13</h2>
<p data-wordfix="true">Ok, I'm trying to create a taxonomy that queries projects so I can list posts by their parent project. I tried to do it with <code>addGlobalData</code> but that's apparently a future feature of Eleventy. So I'm headed back from DC now on the Acela (it's been a long time since the last time that was true) so it's coooooooooooooooode time.</p>
<p>The main thing to note here is I want to be able to get:</p>
<ol>
<li>A list of &quot;projects&quot;</li>
<li>A list of posts under each Project.</li>
</ol>
<h3 id="global-data-and-new-taxonomies" tabindex="-1">Global Data and new Taxonomies</h3>
<p>So instead I'm going to use the global data folder <code>_data</code> and move my operation over there.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-13/#code-skip-hello-day-13-6" id="skip-to-code-skip-hello-day-13-6" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript"><span class="token comment">// In src/_data/projects.js</span><br /><span class="token keyword">const</span> <span class="token punctuation">{</span> readdirSync <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'fs'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br /><span class="token keyword">const</span> <span class="token function-variable function">getDirectories</span> <span class="token operator">=</span> <span class="token parameter">source</span> <span class="token operator">=></span><br /><span class="token function">readdirSync</span><span class="token punctuation">(</span>source<span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">withFileTypes</span><span class="token operator">:</span> <span class="token boolean">true</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><br />	<span class="token punctuation">.</span><span class="token function">filter</span><span class="token punctuation">(</span><span class="token parameter">dirent</span> <span class="token operator">=></span> dirent<span class="token punctuation">.</span><span class="token function">isDirectory</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><br />	<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token parameter">dirent</span> <span class="token operator">=></span> dirent<span class="token punctuation">.</span>name<span class="token punctuation">)</span><br /><br />console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token function">getDirectories</span><span class="token punctuation">(</span><span class="token string">'src/posts/projects/'</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br />module<span class="token punctuation">.</span>exports <span class="token operator">=</span> <span class="token function">getDirectories</span><span class="token punctuation">(</span><span class="token string">'src/posts/projects/'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p id="code-skip-hello-day-13-6">And now I have a global data object I can iterate over. Sweet!</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-13/#code-skip-hello-day-13-5" id="skip-to-code-skip-hello-day-13-5" class="skip-link">Skip code block ▼</a></p>
<pre class="language-liquid"><code class="language-liquid">		{%<span class="token templateTag"><span class="token operator">-</span> <span class="token keyword">for</span> project <span class="token keyword">in</span> projects </span>%}<br />			<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>li</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>capitalize-first<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>{{project}}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>li</span><span class="token punctuation">></span></span><br />		{%<span class="token templateTag"><span class="token operator">-</span> endfor </span>%}</code></pre>
<p id="code-skip-hello-day-13-5">Ok, now that I have the list of projects. I need to do something with them. Basically these should link to project pages that work like category pages in WordPress.</p>
<p>But before I get to that, every time I go through a tunnel my local environment dies because it is loading a remote URL for my Prism styles. Let's fix that. I'm going to copy it locally and set up a passthrough.</p>
<p>Ok, and while I'm here, let me add proper categories for the home page.</p>
<p>Oh wait, that didn't work. It doesn't have the capacity to handle empty collections. I thought I'd get an empty array, but apparently not. Ok, I'll write some checks in to my shortcode.</p>
<p><code>git commit -m &quot;Setting up home page structure with local prism css&quot;</code></p>
<p data-wordfix="true">Ok. That worked. Time to read about <a href="https://www.11ty.dev/docs/pages-from-data/" target="_blank">building Pages from Data with Eleventy</a>.</p>
<h3 id="implementing-tag-data-for-new-templates" tabindex="-1">Implementing Tag Data for New Templates</h3>
<p>Ok so, let's build it out at <code>project-pages.njk</code>.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-13/#code-skip-hello-day-13-4" id="skip-to-code-skip-hello-day-13-4" class="skip-link">Skip code block ▼</a></p>
<pre class="language-liquid"><code class="language-liquid">---<br />pagination:<br />    data: projects<br />    size: 1<br />    alias: project<br />permalink: "projects/{{ project | slug }}/"<br />title: "Project: {{ project | slug }}"<br />---<br /><br />{%<span class="token templateTag"> block postcontent </span>%}<br />	<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h3</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>capitalize-first<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>{{project}}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h3</span><span class="token punctuation">></span></span><br /><br />	<span class="token comment">&lt;!-- post list: --></span><br />{%<span class="token templateTag"> endblock </span>%}</code></pre>
<p id="code-skip-hello-day-13-4">Alright, the page is getting built, but the title meta isn't populated. How to fix?</p>
<p>Ok, <a href="https://github.com/11ty/eleventy/issues/1061#issuecomment-606217361" target="_blank">it doesn't appear to be clearly documented, but I need to use</a> <code>eleventyComputed</code></p>
<p>So I replace the <code>title</code> property as follows:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-13/#code-skip-hello-day-13-3" id="skip-to-code-skip-hello-day-13-3" class="skip-link">Skip code block ▼</a></p>
<pre class="language-liquid"><code class="language-liquid">---<br />pagination:<br />    data: projects<br />    size: 1<br />    alias: project<br />permalink: "projects/{{ project | slug }}/"<br />eleventyComputed:<br />  title: "Project: {{ project.title }}"<br />---</code></pre>
<p id="code-skip-hello-day-13-3">Ok, I'm getting the title now. But I want to filter the list of project posts by the project metadata.</p>
<p>This is more complicated.</p>
<p>But ok, here's what I ended up doing</p>
<h3 id="folder-based-tags" tabindex="-1">Folder Based Tags</h3>
<p>First, I needed to make the project global data object even more complicated. It now needs a Title, a slug and a <code>projectName</code>.</p>
<p data-wordfix="true">To fill out that projectName I need to stop putting the project data in the blog post and instead put it in the<br />
<a href="https://www.11ty.dev/docs/data-template-dir/" target="_blank">directory's data file</a>.</p>
<p>Then I need to pull the content of that data file into my new global object's <code>projectName</code> like so:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-13/#code-skip-hello-day-13-2" id="skip-to-code-skip-hello-day-13-2" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> <span class="token punctuation">{</span> readdirSync <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'fs'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token keyword">const</span> path <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'path'</span><span class="token punctuation">)</span><br /><br /><span class="token keyword">const</span> <span class="token function-variable function">getDirectories</span> <span class="token operator">=</span> <span class="token parameter">source</span> <span class="token operator">=></span><br /><span class="token function">readdirSync</span><span class="token punctuation">(</span>source<span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">withFileTypes</span><span class="token operator">:</span> <span class="token boolean">true</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><br />	<span class="token punctuation">.</span><span class="token function">filter</span><span class="token punctuation">(</span><span class="token parameter">dirent</span> <span class="token operator">=></span> dirent<span class="token punctuation">.</span><span class="token function">isDirectory</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><br />	<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token parameter">dirent</span> <span class="token operator">=></span> dirent<span class="token punctuation">.</span>name<span class="token punctuation">)</span><br /><br /><span class="token keyword">const</span> directorySet <span class="token operator">=</span> <span class="token function">getDirectories</span><span class="token punctuation">(</span><span class="token string">'src/posts/projects/'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><br />	<span class="token punctuation">(</span><span class="token parameter">projectDir</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />		<span class="token keyword">return</span> <span class="token punctuation">{</span><br />			<span class="token literal-property property">title</span><span class="token operator">:</span> projectDir<span class="token punctuation">.</span><span class="token function">charAt</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toUpperCase</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">+</span> projectDir<span class="token punctuation">.</span><span class="token function">slice</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br />			<span class="token literal-property property">slug</span><span class="token operator">:</span> projectDir<span class="token punctuation">,</span><br />			<span class="token literal-property property">projectName</span><span class="token operator">:</span> <span class="token function">require</span><span class="token punctuation">(</span>path<span class="token punctuation">.</span><span class="token function">resolve</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">./src/posts/projects/</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>projectDir<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">/</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>projectDir<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">.json</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">.</span>project<br />		<span class="token punctuation">}</span><br />	<span class="token punctuation">}</span><br /><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p id="code-skip-hello-day-13-2">Now the pages that I'm generating for individual projects can filter by that value:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-13/#code-skip-hello-day-13-1" id="skip-to-code-skip-hello-day-13-1" class="skip-link">Skip code block ▼</a></p>
<pre class="language-liquid"><code class="language-liquid">	<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>ul</span><span class="token punctuation">></span></span><br />		{%<span class="token templateTag"><span class="token operator">-</span> <span class="token keyword">for</span> post <span class="token keyword">in</span> collections<span class="token punctuation">.</span>projects <span class="token operator">-</span></span>%}<br />			{%<span class="token templateTag"> <span class="token keyword">if</span> post<span class="token punctuation">.</span>data<span class="token punctuation">.</span>project <span class="token operator">==</span> project<span class="token punctuation">.</span>projectName </span>%}<br />				<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>li</span><span class="token punctuation">></span></span><br />					<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>{{ post.url }}<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>{{ post.data.title }}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>a</span><span class="token punctuation">></span></span><br />				<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>li</span><span class="token punctuation">></span></span><br />			{%<span class="token templateTag"> endif </span>%}<br />		{%<span class="token templateTag"><span class="token operator">-</span> endfor <span class="token operator">-</span></span>%}<br />	<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>ul</span><span class="token punctuation">></span></span></code></pre>
<p id="code-skip-hello-day-13-1">Ok, it works!</p>
<p><a target="_blank" href="https://github.com/AramZS/devblog/commit/61cfcbae41c8366fca24541455faf5a571421bc4" class="git-commit-link"><code>git commit -am &quot;Project pages&quot;</code></a></p>
<p>Ok, I'm going to add a description for the overall project and make it available the same way. Looks good.</p>
<p>I want to show tags in the sidebar/footer but the current layout isn't great. I'll have to add CSS to handle it.</p>
<p>Ok, train ride is over!</p>
<p><a target="_blank" href="https://github.com/AramZS/devblog/commit/dd017c18b47f501a7a06b179b1788f81019bc487" class="git-commit-link"><code>git commit -am &quot;Finishing project pages&quot;</code></a></p>
]]></content:encoded>
	</item>
	
	<item>
		<title>Part 12: How to make a collection?</title>
		<link>https://fightwithtools.dev/posts/projects/devblog/hello-day-12/?source=rss</link>
		<pubDate>Tue, 06 Jul 2021 02:59:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/projects/devblog/hello-day-12/</guid>
		<description>Day 12 of setting up 11ty dev blog.</description>
		<content:encoded><![CDATA[<h2 id="project-scope-and-todos" tabindex="-1">Project Scope and ToDos</h2>
<ol>
<li>Static Site Generator that can build the blog and let me host it on Github Pages</li>
<li>I want to write posts in Markdown because I'm lazy, it's easy, and it is how I take notes now.</li>
<li>I don't want to spend a ton of time doing design work. I'm doing complicated designs for other projects, so I want to pull a theme I like that I can rely on someone else to keep up.</li>
<li>Once it gets going, I want template changes to be easy.</li>
<li>It should be as easy as Jekyll, so I need to be able to build it using GitHub Actions, where I can just commit a template change or Markdown file and away it goes. If I can't figure this out than fk it, just use Jekyll.</li>
<li>I require it to be used by a significant percent of my professional peers so I can get easy answers when something goes wrong.</li>
<li>I want source maps. This is a dev log site which means whatever I do with it should be easy for other developers to read.</li>
</ol>
<ul class="task-list">
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Also <a href="https://www.npmjs.com/package/@quasibit/eleventy-plugin-sitemap" target="_blank">the sitemap plugin</a> looks cool. Should grab that later.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> So does the <a href="https://www.npmjs.com/package/eleventy-plugin-reading-time" target="_blank">reading time one</a>.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Also <a href="https://github.com/jdsteinbach/eleventy-plugin-toc/" target="_blank">this TOC plugin</a> mby?</p>
</li>
<li class="task-list-item">
<p data-wordfix="true"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Use <a href="https://www.11ty.dev/docs/data-deep-merge/" target="_blank">Data Deep Merge</a> in this blog.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Decide if I want to render the CSS fancier than just a base file and do per-template splitting.</p>
</li>
</ul>
<s>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Can I use the template inside of dinky that already exists instead of copy/pasting it?</li>
</ul>
</s>
<ul class="task-list">
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Is there a way to have permalinks to posts contain metadata without organizing them into subfolders?</p>
</li>
<li class="task-list-item">
<p data-wordfix="true"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> How do I cachebreak files on the basis of new build events? Datetime? <code>site.github.build_revision</code> is <a href="https://github.com/jekyll/github-metadata/blob/master/docs/site.github.md" target="_blank">how Jekyll accomplishes this</a>, but is there a way to push <a href="https://docs.github.com/en/actions/reference/context-and-expression-syntax-for-github-actions#github-context" target="_blank">that</a> <a href="https://stackoverflow.com/questions/54310050/how-to-version-build-artifacts-using-github-actions" target="_blank">into the build process</a> for Eleventy?</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Make link text look less shitty. It looks like it is a whole, lighter, font.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Code blocks do not have good syntax highlighting. I want good syntax highlighting.</p>
</li>
<li class="task-list-item">
<p data-wordfix="true"><input disabled="true" type="checkbox" class="markdown-todo" /> Build a Markdown-it plugin to take my typing shortcuts <code>[prob, b/c, ...?]</code> and expand them on build.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> See if we can start Markdown's interpretation of H tags to <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/Heading_Elements#multiple_h1" target="_blank">start at 2, since H1</a> is always pulled from the page title metadata. If it isn't easy, I just have to change my pattern of writing in the MD documents.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Should I <a href="https://www.madebymike.com.au/writing/11ty-filters-data-shortcodes/" target="_blank">explore some shortcodes</a>?</p>
</li>
</ul>
<h2 id="day-12" tabindex="-1">Day 12</h2>
<p>Ok, I'd like to have a custom collection so I can get a list of project names. So is there a way to add a collection API that's an entirely different collection? Something I can use instead of <code>tags</code> in other words</p>
<ul class="task-list">
<li class="task-list-item">
<p data-wordfix="true"><input disabled="true" type="checkbox" class="markdown-todo" /> Not what I want, but I should probably do this <a href="https://www.11ty.dev/docs/quicktips/tag-pages/" target="_blank">https://www.Eleventy.dev/docs/quicktips/tag-pages/</a></p>
</li>
<li class="task-list-item">
<p data-wordfix="true"><input disabled="true" type="checkbox" class="markdown-todo" /> This will be good to have on the bottom of these posts - <a href="https://www.11ty.dev/docs/filters/collection-items/" target="_blank">https://www.Eleventy.dev/docs/filters/collection-items/</a></p>
</li>
</ul>
<p data-wordfix="true">Feels a little hacky, but it looks like <a href="https://stackoverflow.com/questions/66083103/how-to-generate-a-list-of-all-collections-in-11ty" target="_blank">the way to do this is to create a global object and filter the output I want into there</a>.</p>
<p>There's another way I could potentially handle this, and that's by folder structure. I think it makes sense to try that first and see what we can do with it. First we'll move a post into this new folder structure to try and see if we can query the path usefuly.</p>
<p>I'll move my hello-day-1 post into <code>src/posts/projects/devblog</code>.</p>
<p>Now can I get a list of paths under a particular path? I'm not seeing a way actually. It seems like the sort of thing that it would make sense to be easy to do. Yet, no clear sign of how to do it.</p>
<p>I thought this might work, but no go:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-12/#code-skip-hello-day-12-1" id="skip-to-code-skip-hello-day-12-1" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript">	eleventyConfig<span class="token punctuation">.</span><span class="token function">addCollection</span><span class="token punctuation">(</span><span class="token string">'projects'</span><span class="token punctuation">,</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">collectionApi</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />        <span class="token keyword">return</span> collectionApi<span class="token punctuation">.</span><span class="token function">getFilteredByGlob</span><span class="token punctuation">(</span><span class="token string">'src/projects/*'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p id="code-skip-hello-day-12-1">Ok, looks like I'm going to have to do something a little more complex.</p>
<p><a target="_blank" href="https://github.com/AramZS/devblog/commit/bedec5a5301db8eb0bd8bf6f5f9456ef1c8bc8b1" class="git-commit-link"><code>git commit -am &quot;First attempt at setting up projects list&quot;</code></a></p>
]]></content:encoded>
	</item>
	
	<item>
		<title>Part 11: Nunjucks and Shortcodes</title>
		<link>https://fightwithtools.dev/posts/projects/devblog/hello-day-11/?source=rss</link>
		<pubDate>Tue, 06 Jul 2021 02:59:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/projects/devblog/hello-day-11/</guid>
		<description>Day 8 of setting up 11ty dev blog.</description>
		<content:encoded><![CDATA[<h2 id="project-scope-and-todos" tabindex="-1">Project Scope and ToDos</h2>
<ol>
<li>Static Site Generator that can build the blog and let me host it on Github Pages</li>
<li>I want to write posts in Markdown because I'm lazy, it's easy, and it is how I take notes now.</li>
<li>I don't want to spend a ton of time doing design work. I'm doing complicated designs for other projects, so I want to pull a theme I like that I can rely on someone else to keep up.</li>
<li>Once it gets going, I want template changes to be easy.</li>
<li>It should be as easy as Jekyll, so I need to be able to build it using GitHub Actions, where I can just commit a template change or Markdown file and away it goes. If I can't figure this out than fk it, just use Jekyll.</li>
<li>I require it to be used by a significant percent of my professional peers so I can get easy answers when something goes wrong.</li>
<li>I want source maps. This is a dev log site which means whatever I do with it should be easy for other developers to read.</li>
</ol>
<ul class="task-list">
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Also <a href="https://www.npmjs.com/package/@quasibit/eleventy-plugin-sitemap" target="_blank">the sitemap plugin</a> looks cool. Should grab that later.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> So does the <a href="https://www.npmjs.com/package/eleventy-plugin-reading-time" target="_blank">reading time one</a>.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Also <a href="https://github.com/jdsteinbach/eleventy-plugin-toc/" target="_blank">this TOC plugin</a> mby?</p>
</li>
<li class="task-list-item">
<p data-wordfix="true"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Use <a href="https://www.11ty.dev/docs/data-deep-merge/" target="_blank">Data Deep Merge</a> in this blog.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Decide if I want to render the CSS fancier than just a base file and do per-template splitting.</p>
</li>
</ul>
<s>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Can I use the template inside of dinky that already exists instead of copy/pasting it?</li>
</ul>
</s>
<ul class="task-list">
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Is there a way to have permalinks to posts contain metadata without organizing them into subfolders?</p>
</li>
<li class="task-list-item">
<p data-wordfix="true"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> How do I cachebreak files on the basis of new build events? Datetime? <code>site.github.build_revision</code> is <a href="https://github.com/jekyll/github-metadata/blob/master/docs/site.github.md" target="_blank">how Jekyll accomplishes this</a>, but is there a way to push <a href="https://docs.github.com/en/actions/reference/context-and-expression-syntax-for-github-actions#github-context" target="_blank">that</a> <a href="https://stackoverflow.com/questions/54310050/how-to-version-build-artifacts-using-github-actions" target="_blank">into the build process</a> for Eleventy?</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Make link text look less shitty. It looks like it is a whole, lighter, font.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Code blocks do not have good syntax highlighting. I want good syntax highlighting.</p>
</li>
<li class="task-list-item">
<p data-wordfix="true"><input disabled="true" type="checkbox" class="markdown-todo" /> Build a Markdown-it plugin to take my typing shortcuts <code>[prob, b/c, ...?]</code> and expand them on build.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> See if we can start Markdown's interpretation of H tags to <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/Heading_Elements#multiple_h1" target="_blank">start at 2, since H1</a> is always pulled from the page title metadata. If it isn't easy, I just have to change my pattern of writing in the MD documents.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Should I <a href="https://www.madebymike.com.au/writing/11ty-filters-data-shortcodes/" target="_blank">explore some shortcodes</a>?</p>
</li>
</ul>
<h2 id="day-11" tabindex="-1">Day 11</h2>
<p data-wordfix="true">Ok, still not getting Macros working exactly the way I wanted. It would be really useful to have Eleventy throw actual errors as part of this, but when I tried to set my own version of the Nunjucks Environment I kept hitting against undocumented settings that Eleventy apparently sets up. This is getting way off the main thing I was trying to build. I could dive deeper in, but this site still isn't live and I would like to get it to that point first. So, for now, I'm going to just drop it.</p>
<p>But before I do, I do think this is a major problem and would be useful for eleventy to fix. So, let's check issues one last time, and check if there is something for me to file.</p>
<p>It looks like <a href="https://github.com/11ty/eleventy/issues/895" target="_blank">there is an issue in the right space</a>, but the suggested solution on the issue doesn't work. If I <a href="https://github.com/pdehaan/11ty-blog-ideas/issues/7" target="_blank">follow through the tickets</a> a little more I can <a href="https://github.com/pdehaan/11ty-nunjucks-config/blob/master/.eleventy.js" target="_blank">see another suggested solution</a>. But it doesn't solve the issue with the raw tags no longer working either.</p>
<h3 id="difficulties-with-nunjucks-library-setup" tabindex="-1">Difficulties with Nunjucks Library Setup</h3>
<p>I don't understand. <a href="https://github.com/11ty/eleventy/blob/master/src/Engines/Nunjucks.js#L128" target="_blank">This</a> <em>should</em> work. I even checked to make sure my version of Nunjucks is the same! I even tried removing one of the files, but now my Nunjucks execution is failing on a different chunk of JS in the <code>js</code> front matter block in <code>rss2-feed.njk</code>.</p>
<p>So let's add my voice.</p>
<p><a target="_blank" href="https://github.com/AramZS/devblog/commit/f8732c00f54cbf1bf2b50e258b0bb8500af58487" class="git-commit-link"><code>git commit -am &quot;Bookmarking attempt to set custom NJK library.&quot;</code></a></p>
<p>A quick bookmark of the current state of the site to help the Eleventy folks with debugging my issue!</p>
<p>And now <a href="https://github.com/11ty/eleventy/issues/1879" target="_blank">a write up</a>!</p>
<p>Ok, let's move on!</p>
<h3 id="shortcodes" tabindex="-1">Shortcodes</h3>
<p data-wordfix="true">I'm going to give up on Macros for now and instead I'll <a href="https://www.11ty.dev/docs/languages/nunjucks/#single-shortcode" target="_blank">use a Shortcode</a>.</p>
<p>Ok, honestly this is a <strong>ton</strong> easier. I should have just gone this direction in the first place.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-11/#code-skip-hello-day-11-4" id="skip-to-code-skip-hello-day-11-4" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript">	eleventyConfig<span class="token punctuation">.</span><span class="token function">addShortcode</span><span class="token punctuation">(</span><span class="token string">"postList"</span><span class="token punctuation">,</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">collectionName<span class="token punctuation">,</span> collectionOfPosts</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />		<span class="token keyword">let</span> postList <span class="token operator">=</span> collectionOfPosts<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">post</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />			<span class="token keyword">return</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">&lt;li></span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>post<span class="token punctuation">.</span>data<span class="token punctuation">.</span>title<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">&lt;/li></span><span class="token template-punctuation string">`</span></span><br />		<span class="token punctuation">}</span><span class="token punctuation">)</span><br />		<span class="token keyword">return</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">&lt;p></span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>collectionName<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">&lt;/p><br />		&lt;ul><br />			&lt;!-- Collection: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>collectionName<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> --><br />			</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>postList<span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span><span class="token string">'\n'</span><span class="token punctuation">)</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"><br />		&lt;/ul><br />		</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span><br />	<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p data-wordfix="true" id="code-skip-hello-day-11-4">and then I can call it easily with Eleventy data like this:</p>
<p><code>{% postList &quot;WiP&quot;, collections[&quot;WiP&quot;] %}</code></p>
<p><a target="_blank" href="https://github.com/AramZS/devblog/commit/909ea707e6297787a6dc7508458be964addfac97" class="git-commit-link"><code>git commit -am &quot;Set up a shortcode for postlist&quot;</code></a></p>
<p>Ok, now I want to be able to pass the post type I want to list in the Markdown file.</p>
<p>New markdown front matter to make that work:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-11/#code-skip-hello-day-11-3" id="skip-to-code-skip-hello-day-11-3" class="skip-link">Skip code block ▼</a></p>
<pre class="language-yaml"><code class="language-yaml"><span class="token punctuation">---</span><br /><span class="token key atrule">layout</span><span class="token punctuation">:</span> index<br /><span class="token key atrule">eleventyExcludeFromCollections</span><span class="token punctuation">:</span> <span class="token boolean important">true</span><br /><span class="token key atrule">internalPageTypes</span><span class="token punctuation">:</span> <span class="token punctuation">[</span> <span class="token string">'home'</span> <span class="token punctuation">]</span><br /><span class="token key atrule">postLists</span><span class="token punctuation">:</span> <span class="token punctuation">[</span><br />	<span class="token punctuation">{</span><span class="token key atrule">name</span><span class="token punctuation">:</span> <span class="token string">"WiP"</span><span class="token punctuation">,</span> <span class="token key atrule">collection</span><span class="token punctuation">:</span> <span class="token string">"WiP"</span><span class="token punctuation">,</span> <span class="token key atrule">order</span><span class="token punctuation">:</span> <span class="token string">"date"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span><br />	<span class="token punctuation">{</span><span class="token key atrule">name</span><span class="token punctuation">:</span> <span class="token string">"Posts"</span><span class="token punctuation">,</span> <span class="token key atrule">collection</span><span class="token punctuation">:</span> <span class="token string">"posts"</span><span class="token punctuation">,</span> <span class="token key atrule">order</span><span class="token punctuation">:</span> <span class="token string">"reverse"</span> <span class="token punctuation">}</span><br />	<span class="token punctuation">]</span><br /><span class="token punctuation">---</span></code></pre>
<p id="code-skip-hello-day-11-3">and I'll alter the shortcode to use the new arguments.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-11/#code-skip-hello-day-11-2" id="skip-to-code-skip-hello-day-11-2" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript">	eleventyConfig<span class="token punctuation">.</span><span class="token function">addShortcode</span><span class="token punctuation">(</span><span class="token string">"postList"</span><span class="token punctuation">,</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">collectionName<span class="token punctuation">,</span> collectionOfPosts<span class="token punctuation">,</span> order</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />		<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span><span class="token operator">!</span><span class="token operator">!</span>order<span class="token punctuation">)</span><span class="token punctuation">{</span><br />			order <span class="token operator">=</span> <span class="token string">"reverse"</span><br />		<span class="token punctuation">}</span><br />		<span class="token keyword">if</span> <span class="token punctuation">(</span>order <span class="token operator">===</span> <span class="token string">"reverse"</span><span class="token punctuation">)</span><span class="token punctuation">{</span><br />			collectionOfPosts<span class="token punctuation">.</span><span class="token function">reverse</span><span class="token punctuation">(</span><span class="token punctuation">)</span><br />		<span class="token punctuation">}</span><br />		<span class="token keyword">let</span> postList <span class="token operator">=</span> collectionOfPosts<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">post</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />			<span class="token keyword">return</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">&lt;li></span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>post<span class="token punctuation">.</span>data<span class="token punctuation">.</span>title<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">&lt;/li></span><span class="token template-punctuation string">`</span></span><br />		<span class="token punctuation">}</span><span class="token punctuation">)</span><br />		<span class="token keyword">return</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">&lt;p></span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>collectionName<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">&lt;/p><br />		&lt;ul><br />			&lt;!-- Collection: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>collectionName<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> --><br />			</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>postList<span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span><span class="token string">'\n'</span><span class="token punctuation">)</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"><br />		&lt;/ul><br />		</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span><br />	<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p id="code-skip-hello-day-11-2">and now my <code>index.njk</code> file is reusable for any vertical file I wish to reuse it with.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-11/#code-skip-hello-day-11-1" id="skip-to-code-skip-hello-day-11-1" class="skip-link">Skip code block ▼</a></p>
<pre class="language-liquid"><code class="language-liquid">{%<span class="token templateTag"> <span class="token keyword">extends</span> <span class="token string">"base.njk"</span> </span>%}<br /><br />{%<span class="token templateTag"> block postcontent </span>%}<br />	<span class="token comment">&lt;!-- post list: --></span><br />	{%<span class="token templateTag"><span class="token operator">-</span> <span class="token keyword">for</span> postType <span class="token keyword">in</span> postLists </span>%}<br />		{% postList postType.name,<br />		collections[postType.collection],<br />		postType.order %}<br />	{%<span class="token templateTag"><span class="token operator">-</span> endfor </span>%}<br />{%<span class="token templateTag"> endblock </span>%}</code></pre>
<p id="code-skip-hello-day-11-1"><a target="_blank" href="https://github.com/AramZS/devblog/commit/16489980c08be5ebaab225ed4178fb314d8f80f9" class="git-commit-link"><code>git commit -am &quot;Got shortcode + vertical layout template working&quot;</code></a></p>
]]></content:encoded>
	</item>
	
	<item>
		<title>Part 11: Nunjucks and Macros</title>
		<link>https://fightwithtools.dev/posts/projects/devblog/hello-day-10/?source=rss</link>
		<pubDate>Mon, 05 Jul 2021 02:59:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/projects/devblog/hello-day-10/</guid>
		<description>Day 10 of setting up 11ty dev blog.</description>
		<content:encoded><![CDATA[<h2 id="project-scope-and-todos" tabindex="-1">Project Scope and ToDos</h2>
<ol>
<li>Static Site Generator that can build the blog and let me host it on Github Pages</li>
<li>I want to write posts in Markdown because I'm lazy, it's easy, and it is how I take notes now.</li>
<li>I don't want to spend a ton of time doing design work. I'm doing complicated designs for other projects, so I want to pull a theme I like that I can rely on someone else to keep up.</li>
<li>Once it gets going, I want template changes to be easy.</li>
<li>It should be as easy as Jekyll, so I need to be able to build it using GitHub Actions, where I can just commit a template change or Markdown file and away it goes. If I can't figure this out than fk it, just use Jekyll.</li>
<li>I require it to be used by a significant percent of my professional peers so I can get easy answers when something goes wrong.</li>
<li>I want source maps. This is a dev log site which means whatever I do with it should be easy for other developers to read.</li>
</ol>
<ul class="task-list">
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Also <a href="https://www.npmjs.com/package/@quasibit/eleventy-plugin-sitemap" target="_blank">the sitemap plugin</a> looks cool. Should grab that later.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> So does the <a href="https://www.npmjs.com/package/eleventy-plugin-reading-time" target="_blank">reading time one</a>.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Also <a href="https://github.com/jdsteinbach/eleventy-plugin-toc/" target="_blank">this TOC plugin</a> mby?</p>
</li>
<li class="task-list-item">
<p data-wordfix="true"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Use <a href="https://www.11ty.dev/docs/data-deep-merge/" target="_blank">Data Deep Merge</a> in this blog.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Decide if I want to render the CSS fancier than just a base file and do per-template splitting.</p>
</li>
</ul>
<s>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Can I use the template inside of dinky that already exists instead of copy/pasting it?</li>
</ul>
</s>
<ul class="task-list">
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Is there a way to have permalinks to posts contain metadata without organizing them into subfolders?</p>
</li>
<li class="task-list-item">
<p data-wordfix="true"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> How do I cachebreak files on the basis of new build events? Datetime? <code>site.github.build_revision</code> is <a href="https://github.com/jekyll/github-metadata/blob/master/docs/site.github.md" target="_blank">how Jekyll accomplishes this</a>, but is there a way to push <a href="https://docs.github.com/en/actions/reference/context-and-expression-syntax-for-github-actions#github-context" target="_blank">that</a> <a href="https://stackoverflow.com/questions/54310050/how-to-version-build-artifacts-using-github-actions" target="_blank">into the build process</a> for Eleventy?</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Make link text look less shitty. It looks like it is a whole, lighter, font.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Code blocks do not have good syntax highlighting. I want good syntax highlighting.</p>
</li>
<li class="task-list-item">
<p data-wordfix="true"><input disabled="true" type="checkbox" class="markdown-todo" /> Build a Markdown-it plugin to take my typing shortcuts <code>[prob, b/c, ...?]</code> and expand them on build.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> See if we can start Markdown's interpretation of H tags to <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/Heading_Elements#multiple_h1" target="_blank">start at 2, since H1</a> is always pulled from the page title metadata. If it isn't easy, I just have to change my pattern of writing in the MD documents.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Should I <a href="https://www.madebymike.com.au/writing/11ty-filters-data-shortcodes/" target="_blank">explore some shortcodes</a>?</p>
</li>
</ul>
<h2 id="day-10" tabindex="-1">Day 10</h2>
<p>Ok, when we left off I had totally failed to build a macro in Nunjucks.</p>
<p>Ok, I forgot to change the argument that was passed in the macros file and when I did that it worked.</p>
<p>So... progress!</p>
<p>Now let's try and figure out how to make it more useful.</p>
<h3 id="macros" tabindex="-1">Macros</h3>
<p>There are some interesting things you can do with Macros! I really would like to get it to work, so before we go the filter route, let's see if we can make my intended methodology work. This seems like it would be a thing people would want to do! So some more web searching may be in order.</p>
<p data-wordfix="true">Ok, after trying a few different search terms <a href="https://stackoverflow.com/questions/50685814/nunjucks-nested-variables" target="_blank">I've found a useful middle ground</a>. But I know that <a href="https://www.11ty.dev/docs/languages/nunjucks/#filters" target="_blank">Nunjucks applies filters in a specific way in Eleventy</a>.</p>
<p data-wordfix="true">Hmmm, apparently part of the issue <a href="https://github.com/11ty/eleventy/issues/354#issuecomment-449904901" target="_blank">is that Nunjucks fails silently on rendering stuff</a>. Is there a way to turn it off? Looks like first <a href="https://www.11ty.dev/docs/languages/nunjucks/#optional-use-your-nunjucks-environment" target="_blank">I'll have to redefine the Nunjucks rendering environment</a>.</p>
<p data-wordfix="true">The Nunjucks page on Eleventy suggests we pass in the <code>_includes</code> folder name as a string: <code>new Nunjucks.FileSystemLoader(&quot;_includes&quot;)</code>. But that's an extra instance of that string to keep track of. Better to use my Eleventy config object instead. I also want to switch <code>throwOnUndefined</code> to <code>true</code>, but only in the local environment. Another good use for <code>process.env.DOMAIN</code>.</p>
<p>Now at the top of my <code>.eleventy.js</code> file I have</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-10/#code-skip-hello-day-10-3" id="skip-to-code-skip-hello-day-10-3" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">let</span> domain_name <span class="token operator">=</span> <span class="token string">"https://fightwithtools.dev"</span><span class="token punctuation">;</span><br /><span class="token keyword">let</span> throwOnUndefinedSetting <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">;</span><br /><br /><span class="token keyword">if</span> <span class="token punctuation">(</span>process<span class="token punctuation">.</span>env<span class="token punctuation">.</span><span class="token constant">IS_LOCAL</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />	domain_name <span class="token operator">=</span> <span class="token string">"http://localhost:8080"</span><span class="token punctuation">;</span><br />	throwOnUndefinedSetting <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span></code></pre>
<p id="code-skip-hello-day-10-3">And I have a new section that sets up my own Nunjucks filter:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-10/#code-skip-hello-day-10-2" id="skip-to-code-skip-hello-day-10-2" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript">	<span class="token keyword">let</span> nunjucksEnvironment <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Nunjucks<span class="token punctuation">.</span>Environment</span><span class="token punctuation">(</span><br />		<span class="token keyword">new</span> <span class="token class-name">Nunjucks<span class="token punctuation">.</span>FileSystemLoader</span><span class="token punctuation">(</span>siteConfiguration<span class="token punctuation">.</span>dir<span class="token punctuation">.</span>includes<span class="token punctuation">,</span><br />		<span class="token punctuation">{</span><br />			<span class="token literal-property property">throwOnUndefined</span><span class="token operator">:</span> throwOnUndefinedSetting<br />		<span class="token punctuation">}</span><br />	<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />	eleventyConfig<span class="token punctuation">.</span><span class="token function">setLibrary</span><span class="token punctuation">(</span><span class="token string">"njk"</span><span class="token punctuation">,</span> nunjucksEnvironment<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p data-wordfix="true" id="code-skip-hello-day-10-2">Ok... interesting... when I set it up, it no longer reads the include statement properly, which calls a template located in <code>src/_layouts</code> and passed into the configuration object to Eleventy as <code>dir.layouts</code>:</p>
<p><code>{% extends &quot;base.njk&quot; %}</code></p>
<h3 data-wordfix="true" id="eleventy-and-nunjucks" tabindex="-1">Eleventy and Nunjucks</h3>
<p data-wordfix="true">Hmmmm. Well <a href="https://github.com/11ty/eleventy/blob/master/src/Engines/Nunjucks.js#L124" target="_blank">let's take a look at how Eleventy configures it</a>.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-10/#code-skip-hello-day-10-1" id="skip-to-code-skip-hello-day-10-1" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript">	<span class="token keyword">const</span> normalize <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">"normalize-path"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br />	<span class="token operator">...</span><br /><br />	<span class="token keyword">const</span> <span class="token function-variable function">pathNormalizer</span> <span class="token operator">=</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">pathString</span><span class="token punctuation">)</span><span class="token punctuation">{</span><br />		<span class="token keyword">return</span> <span class="token function">normalize</span><span class="token punctuation">(</span>path<span class="token punctuation">.</span><span class="token function">normalize</span><span class="token punctuation">(</span>path<span class="token punctuation">.</span><span class="token function">resolve</span><span class="token punctuation">(</span><span class="token string">"."</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><br />	<span class="token punctuation">}</span><br /><br />	<span class="token keyword">let</span> nunjucksEnvironment <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Nunjucks<span class="token punctuation">.</span>Environment</span><span class="token punctuation">(</span><br />		<span class="token keyword">new</span> <span class="token class-name">Nunjucks<span class="token punctuation">.</span>FileSystemLoader</span><span class="token punctuation">(</span><span class="token punctuation">[</span><br />			<span class="token function">pathNormalizer</span><span class="token punctuation">(</span>siteConfiguration<span class="token punctuation">.</span>dir<span class="token punctuation">.</span>includes<span class="token punctuation">)</span><span class="token punctuation">,</span><br />			<span class="token function">pathNormalizer</span><span class="token punctuation">(</span>siteConfiguration<span class="token punctuation">.</span>dir<span class="token punctuation">.</span>layouts<span class="token punctuation">)</span><span class="token punctuation">,</span><br />			<span class="token function">pathNormalizer</span><span class="token punctuation">(</span><span class="token string">"."</span><span class="token punctuation">)</span><br />		<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br />		<span class="token punctuation">{</span><br />			<span class="token literal-property property">throwOnUndefined</span><span class="token operator">:</span> throwOnUndefinedSetting<br />		<span class="token punctuation">}</span><br />	<span class="token punctuation">)</span><span class="token punctuation">;</span><br />	eleventyConfig<span class="token punctuation">.</span><span class="token function">setLibrary</span><span class="token punctuation">(</span><span class="token string">"njk"</span><span class="token punctuation">,</span> nunjucksEnvironment<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p data-wordfix="true" id="code-skip-hello-day-10-1">Well, <a href="https://github.com/11ty/eleventy/blob/master/src/Engines/Nunjucks.js#L124" target="_blank">it looks like Eleventy does more to configure the Nunjucks rendering engine than I thought</a>. Let's see if I can try to duplicate how the core Eleventy approach does it.</p>
<p data-wordfix="true">Hmmm, pulled the same configuration, but now it looks like one of my posts isn't working. It looks like Nunjucks is adding some secret juice to the <code>raw</code> tag for escaping stuff. Hmmm, ok, there is a lot of badly documented stuff that Eleventy is doing with the Nunjucks engine and modifying it. Perhaps it is time to step back from attempting to mod it and take a different approach.</p>
<p>Maybe I should go for the custom filter method instead. Let's step back.</p>
<p data-wordfix="true"><a target="_blank" href="https://github.com/AramZS/devblog/commit/0fdca3ba87195cddd06f16a0c7b909c9ed838018" class="git-commit-link"><code>git commit -am &quot;Trying to get variable variables working and 11ty to set throwOnUndefined for nunjucks&quot;</code></a></p>
]]></content:encoded>
	</item>
	
	<item>
		<title>Part 9: Post Data in Templates</title>
		<link>https://fightwithtools.dev/posts/projects/devblog/hello-day-9/?source=rss</link>
		<pubDate>Tue, 29 Jun 2021 02:59:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/projects/devblog/hello-day-9/</guid>
		<description>Day 9 of setting up 11ty dev blog.</description>
		<content:encoded><![CDATA[<h2 id="project-scope-and-todos" tabindex="-1">Project Scope and ToDos</h2>
<ol>
<li>Static Site Generator that can build the blog and let me host it on Github Pages</li>
<li>I want to write posts in Markdown because I'm lazy, it's easy, and it is how I take notes now.</li>
<li>I don't want to spend a ton of time doing design work. I'm doing complicated designs for other projects, so I want to pull a theme I like that I can rely on someone else to keep up.</li>
<li>Once it gets going, I want template changes to be easy.</li>
<li>It should be as easy as Jekyll, so I need to be able to build it using GitHub Actions, where I can just commit a template change or Markdown file and away it goes. If I can't figure this out than fk it, just use Jekyll.</li>
<li>I require it to be used by a significant percent of my professional peers so I can get easy answers when something goes wrong.</li>
<li>I want source maps. This is a dev log site which means whatever I do with it should be easy for other developers to read.</li>
</ol>
<ul class="task-list">
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Also <a href="https://www.npmjs.com/package/@quasibit/eleventy-plugin-sitemap" target="_blank">the sitemap plugin</a> looks cool. Should grab that later.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> So does the <a href="https://www.npmjs.com/package/eleventy-plugin-reading-time" target="_blank">reading time one</a>.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Also <a href="https://github.com/jdsteinbach/eleventy-plugin-toc/" target="_blank">this TOC plugin</a> mby?</p>
</li>
<li class="task-list-item">
<p data-wordfix="true"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Use <a href="https://www.11ty.dev/docs/data-deep-merge/" target="_blank">Data Deep Merge</a> in this blog.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Decide if I want to render the CSS fancier than just a base file and do per-template splitting.</p>
</li>
</ul>
<s>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Can I use the template inside of dinky that already exists instead of copy/pasting it?</li>
</ul>
</s>
<ul class="task-list">
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Is there a way to have permalinks to posts contain metadata without organizing them into subfolders?</p>
</li>
<li class="task-list-item">
<p data-wordfix="true"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> How do I cachebreak files on the basis of new build events? Datetime? <code>site.github.build_revision</code> is <a href="https://github.com/jekyll/github-metadata/blob/master/docs/site.github.md" target="_blank">how Jekyll accomplishes this</a>, but is there a way to push <a href="https://docs.github.com/en/actions/reference/context-and-expression-syntax-for-github-actions#github-context" target="_blank">that</a> <a href="https://stackoverflow.com/questions/54310050/how-to-version-build-artifacts-using-github-actions" target="_blank">into the build process</a> for Eleventy?</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Make link text look less shitty. It looks like it is a whole, lighter, font.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Code blocks do not have good syntax highlighting. I want good syntax highlighting.</p>
</li>
<li class="task-list-item">
<p data-wordfix="true"><input disabled="true" type="checkbox" class="markdown-todo" /> Build a Markdown-it plugin to take my typing shortcuts <code>[prob, b/c, ...?]</code> and expand them on build.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> See if we can start Markdown's interpretation of H tags to <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/Heading_Elements#multiple_h1" target="_blank">start at 2, since H1</a> is always pulled from the page title metadata. If it isn't easy, I just have to change my pattern of writing in the MD documents.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Should I <a href="https://www.madebymike.com.au/writing/11ty-filters-data-shortcodes/" target="_blank">explore some shortcodes</a>?</p>
</li>
</ul>
<h2 id="day-9" tabindex="-1">Day 9</h2>
<h3 id="rss-feed-and-file-type-on-github" tabindex="-1">RSS Feed and File Type on GitHub</h3>
<p>Looks like the RSS feed is correct but being served from Github Pages as &quot;application/octet-stream&quot;. I found a Stack Overflow that said it needs a trailing slash. But now that serves it as text/html. Apparently it needs to have an xml ending, but if we want to keep <code>/rss/</code> <a href="https://luosky.com/2012/07/24/create-custom-rss-feed-for-octopress/" target="_blank">we need to create an xml file</a>.</p>
<p><a target="_blank" href="https://github.com/AramZS/devblog/commit/03e5122bbc07fd0a51d777087c7162a96954beca" class="git-commit-link"><code>git commit -am &quot;Set an xml index for the rss path&quot;</code></a></p>
<p>That did it! Good to know that Github Pages is <em>very</em> dependent on file endings, and if it doesn't get them it defaults <code>/path-with-no-ending-slash</code> to a downloadable octet-stream and <code>/path-with-ending-slash/</code> to HTML.</p>
<h3 id="filling-in-post-data-and-templates" tabindex="-1">Filling in Post Data and Templates</h3>
<p>I want to build some post-only conditionals into a common base template. The goal here is to make my templates as DRY as possible. No code should have to be repeated. Looks like there <a href="https://bryanlrobinson.com/blog/using-nunjucks-if-expressions-to-create-an-active-navigation-state-in-11ty/" target="_blank">are some tools to do that in Nunjucks</a>.</p>
<p>Ok, so I'm going to split this into a few chunks.</p>
<p>First I'm going to establish a base template, one that all the others can pull off of. This can set up the basic HTML structure, my HTML, HEAD and BODY tags. It can also establish the baseline HTML to make the template work, like the wrapper-classed div and the semantic HTML5 tags within.</p>
<p><a target="_blank" href="https://github.com/AramZS/devblog/commit/c5393b66b174dea6da6a5487ba85488b974cd3b6" class="git-commit-link"><code>git commit -am &quot;Setting up some templates to inheret from.&quot;</code></a></p>
<p>Then I'll want to define the areas that the layouts that pull off the base can pull from. Nunjucks seems to do this with <code>block</code> tags. So I'll set up some of these block tags in the <code>&lt;main&gt;</code> area to start with.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-9/#code-skip-hello-day-9-4" id="skip-to-code-skip-hello-day-9-4" class="skip-link">Skip code block ▼</a></p>
<pre class="language-liquid"><code class="language-liquid">		<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>main</span><span class="token punctuation">></span></span><br />			{%<span class="token templateTag"> block precontent </span>%}<br />			{%<span class="token templateTag"> endblock </span>%}<br />			<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>section</span><span class="token punctuation">></span></span><br />				{%<span class="token templateTag"> block content </span>%}<br />				{{ content | safe }}<br />				{%<span class="token templateTag"> endblock </span>%}<br />			<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>section</span><span class="token punctuation">></span></span><br />			{%<span class="token templateTag"> block postcontent </span>%}<br />			{%<span class="token templateTag"> endblock </span>%}<br />		<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>main</span><span class="token punctuation">></span></span></code></pre>
<p id="code-skip-hello-day-9-4">With the basics in place, I can actually drop the entire content of <code>post.njk</code> and replace it with an <code>extends</code> statement.</p>
<p>{% extends &quot;base.njk&quot; %}</p>
<p>The original dinky template was designed for single page sites. So the post template works pretty much unchanged with no issues. But what about my index page? I'm going to want to add stuff to there.</p>
<h3 id="post-lists" tabindex="-1">Post Lists</h3>
<p data-wordfix="true">First of all, I want a chunk of that page that shows my various Work in Progress posts. I've tagged the posts themselves correctly <a href="https://www.11ty.dev/docs/collections/" target="_blank">to create an Eleventy collection</a>, but I need to figure out how to call it. And I may want to display it elsewhere, so I'm going to create a component I can easily include that walks through the WiP tag.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-9/#code-skip-hello-day-9-3" id="skip-to-code-skip-hello-day-9-3" class="skip-link">Skip code block ▼</a></p>
<pre class="language-liquid"><code class="language-liquid"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>ul</span><span class="token punctuation">></span></span><br />    {%<span class="token templateTag"> <span class="token keyword">for</span> post <span class="token keyword">in</span> collections<span class="token punctuation">.</span>WiP </span>%}<br />	<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>li</span><span class="token punctuation">></span></span>{{post.data.title}}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>li</span><span class="token punctuation">></span></span><br />	{%<span class="token templateTag"> endfor </span>%}<br /><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>ul</span><span class="token punctuation">></span></span></code></pre>
<p id="code-skip-hello-day-9-3">This is a good start, but what if I only want one category of WiP? Or if I want to separate it out into projects? I need to make this more reusable.</p>
<p>But what about sorting? I may need to sort by date and dates are always messy. To make sure I can get them work right, I should start by adding a date to all post templates. I could add it in the post template itself, but I suspect there may be other pages I want to have the date on, so I'm going to handle it with an if/else chain at the base template.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-9/#code-skip-hello-day-9-2" id="skip-to-code-skip-hello-day-9-2" class="skip-link">Skip code block ▼</a></p>
<pre class="language-liquid"><code class="language-liquid">	<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>header</span><span class="token punctuation">></span></span><br />	<br /><br />		<br />		<span class="token comment">&lt;!-- post mode --></span><br />		<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>time</span><span class="token punctuation">></span></span>Tue Jun 29 2021<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>time</span><span class="token punctuation">></span></span><br />		<br />		<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h1</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>header<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Part 9: Post Data in Templates<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h1</span><span class="token punctuation">></span></span><br />		<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>header<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Day 9 of setting up 11ty dev blog.<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">></span></span><br /><br />	<br />	<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>header</span><span class="token punctuation">></span></span></code></pre>
<p data-wordfix="true" id="code-skip-hello-day-9-2">Oh, these dates aren't great, they seem to be pulling from some info that isn't totally accurate via the Eleventy defaults</p>
<p data-wordfix="true">Surprising no one, dates are a <a href="https://www.11ty.dev/docs/pitfalls/" target="_blank">Common Pitfall</a>. <a href="https://www.11ty.dev/docs/dates/" target="_blank">Eleventy documentation advises to directly set the date</a>. And I can't just set them any which way, I need to set them <a href="https://yaml.org/type/timestamp.html" target="_blank">via the YAML date format</a>. Once that's done, I can display them using that built-in toDateString function in a way that makes the dates more human readable.</p>
<p><a target="_blank" href="https://github.com/AramZS/devblog/commit/e59d4078e5fc07346e15ecc897922e9f583209cc" class="git-commit-link"><code>git commit -am &quot;Adding template parts&quot;</code></a></p>
<p>Ok back to my reusable post list. I started with a pretty basic version, but it looks to me like <a href="https://www.trysmudford.com/blog/encapsulated-11ty-components/" target="_blank">the right approach is Macros</a>.</p>
<p>Huh... that didn't work.</p>
<p>Ok maybe this:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-9/#code-skip-hello-day-9-1" id="skip-to-code-skip-hello-day-9-1" class="skip-link">Skip code block ▼</a></p>
<pre class="language-liquid"><code class="language-liquid"><span class="token comment">&lt;!-- https://www.11ty.dev/docs/collections/ --></span><br /><span class="token comment">&lt;!-- Should I use {{ "abcdef" | reverse }} --></span><br /><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>ul</span><span class="token punctuation">></span></span><br />	<span class="token comment">&lt;!-- Collection: {{collectionName}} --></span><br />    {%<span class="token templateTag"> <span class="token keyword">for</span> post <span class="token keyword">in</span> collections<span class="token punctuation">.</span><span class="token punctuation">{</span><span class="token punctuation">{</span>collectionName<span class="token punctuation">}</span><span class="token punctuation">}</span> </span>%}<br />	<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>li</span><span class="token punctuation">></span></span>{{post.data.title}}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>li</span><span class="token punctuation">></span></span><br />	{%<span class="token templateTag"> endfor </span>%}<br /><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>ul</span><span class="token punctuation">></span></span><br /></code></pre>
<p data-wordfix="true" id="code-skip-hello-day-9-1">Especially with the variable name in the <code>for</code> deceleration? I don't know if that works the way I think it does and I may even just need <a href="https://www.11ty.dev/docs/languages/nunjucks/#shortcodes" target="_blank">a shortcode instead</a>. But I'd like to get it working. Let's try just echoing out the passed in value first.</p>
<p>Damn, still no go.</p>
<p><a target="_blank" href="https://github.com/AramZS/devblog/commit/b67b72c0a011aecb0fd6bf070fed41ddcbf9ed2e" class="git-commit-link"><code>git commit -am &quot;Get macros in the mix.&quot;</code></a></p>
]]></content:encoded>
	</item>
	
	<item>
		<title>Source Maps, Site Paths and GitHub Actions</title>
		<link>https://fightwithtools.dev/posts/projects/devblog/hello-day-8/?source=rss</link>
		<pubDate>Wed, 23 Jun 2021 02:59:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/projects/devblog/hello-day-8/</guid>
		<description>Part 8 of setting up 11ty dev blog.</description>
		<content:encoded><![CDATA[<h2 id="project-scope-and-todos" tabindex="-1">Project Scope and ToDos</h2>
<ol>
<li>Static Site Generator that can build the blog and let me host it on Github Pages</li>
<li>I want to write posts in Markdown because I'm lazy, it's easy, and it is how I take notes now.</li>
<li>I don't want to spend a ton of time doing design work. I'm doing complicated designs for other projects, so I want to pull a theme I like that I can rely on someone else to keep up.</li>
<li>Once it gets going, I want template changes to be easy.</li>
<li>It should be as easy as Jekyll, so I need to be able to build it using GitHub Actions, where I can just commit a template change or Markdown file and away it goes. If I can't figure this out than fk it, just use Jekyll.</li>
<li>I require it to be used by a significant percent of my professional peers so I can get easy answers when something goes wrong.</li>
<li>I want source maps. This is a dev log site which means whatever I do with it should be easy for other developers to read.</li>
</ol>
<ul class="task-list">
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Also <a href="https://www.npmjs.com/package/@quasibit/eleventy-plugin-sitemap" target="_blank">the sitemap plugin</a> looks cool. Should grab that later.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> So does the <a href="https://www.npmjs.com/package/eleventy-plugin-reading-time" target="_blank">reading time one</a>.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Also <a href="https://github.com/jdsteinbach/eleventy-plugin-toc/blob/master/src/BuildTOC.js" target="_blank">this TOC plugin</a> mby?</p>
</li>
<li class="task-list-item">
<p data-wordfix="true"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Use <a href="https://www.11ty.dev/docs/data-deep-merge/" target="_blank">Data Deep Merge</a> in this blog.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Decide if I want to render the CSS fancier than just a base file and do per-template splitting.</p>
</li>
</ul>
<s>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Can I use the template inside of dinky that already exists instead of copy/pasting it?</li>
</ul>
</s>
<ul class="task-list">
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Is there a way to have permalinks to posts contain metadata without organizing them into subfolders?</p>
</li>
<li class="task-list-item">
<p data-wordfix="true"><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> How do I cachebreak files on the basis of new build events? Datetime? <code>site.github.build_revision</code> is <a href="https://github.com/jekyll/github-metadata/blob/master/docs/site.github.md" target="_blank">how Jekyll accomplishes this</a>, but is there a way to push <a href="https://docs.github.com/en/actions/reference/context-and-expression-syntax-for-github-actions#github-context" target="_blank">that</a> <a href="https://stackoverflow.com/questions/54310050/how-to-version-build-artifacts-using-github-actions" target="_blank">into the build process</a> for Eleventy?</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Make link text look less shitty. It looks like it is a whole, lighter, font.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Code blocks do not have good syntax highlighting. I want good syntax highlighting.</p>
</li>
<li class="task-list-item">
<p data-wordfix="true"><input disabled="true" type="checkbox" class="markdown-todo" /> Build a Markdown-it plugin to take my typing shortcuts <code>[prob, b/c, ...?]</code> and expand them on build.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> See if we can start Markdown's interpretation of H tags to <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/Heading_Elements#multiple_h1" target="_blank">start at 2, since H1</a> is always pulled from the page title metadata. If it isn't easy, I just have to change my pattern of writing in the MD documents.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Should I <a href="https://www.madebymike.com.au/writing/11ty-filters-data-shortcodes/" target="_blank">explore some shortcodes</a>?</p>
</li>
</ul>
<h2 id="day-8" tabindex="-1">Day 8</h2>
<h3 id="source-maps" tabindex="-1">Source Maps</h3>
<p>So, the Sass source-map is still giving me file:// URLs. This is apparently some sort of weird error in the dart-sass implementation? I found a few issues, all of which seem to point at <a href="https://github.com/sass/libsass/issues/908#issuecomment-76452477" target="_blank">one issue's set of solutions</a>. But none of these worked for me. I'm not really sure why. I think because dart-sass assumes source maps are only used for local development, not also for public-facing examples like I want. But the top of that thread pointed me <a href="https://github.com/joliss/node-sass-source-map-example/blob/master/better-output.js" target="_blank">at a useful build script example</a>.</p>
<h4 id="filename-fixes" tabindex="-1">Filename Fixes</h4>
<p>On the basis of that (which still uses dirname for local file paths) I altered it to match my reality of running a local server&quot;</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-8/#code-skip-hello-day-8-9" id="skip-to-code-skip-hello-day-8-9" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript">	<span class="token keyword">const</span> outFile <span class="token operator">=</span> <span class="token string">"/assets/css/style.css"</span><span class="token punctuation">;</span><br />	<span class="token keyword">var</span> result <span class="token operator">=</span> sass<span class="token punctuation">.</span><span class="token function">renderSync</span><span class="token punctuation">(</span><span class="token punctuation">{</span><br />		<span class="token literal-property property">includePaths</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">"**/*.{scss,sass}"</span><span class="token punctuation">,</span> <span class="token string">"!node_modules/**"</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br />		<span class="token literal-property property">file</span><span class="token operator">:</span> <span class="token string">"src/_sass/_index.sass"</span><span class="token punctuation">,</span><br />		<span class="token literal-property property">outputStyle</span><span class="token operator">:</span> <span class="token string">"compressed"</span><span class="token punctuation">,</span><br />		<span class="token literal-property property">sourceMap</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span><br />		<span class="token literal-property property">sourceMapContents</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span><br />		<span class="token literal-property property">outFile</span><span class="token operator">:</span> path<span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span>process<span class="token punctuation">.</span><span class="token function">cwd</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> path<span class="token punctuation">.</span><span class="token function">basename</span><span class="token punctuation">(</span>outFile<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br />	<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />	console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">"Sass renderSync result"</span><span class="token punctuation">,</span> result<span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token keyword">var</span> fullCSS <span class="token operator">=</span> result<span class="token punctuation">.</span>css<span class="token punctuation">.</span><span class="token function">toString</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token keyword">var</span> map <span class="token operator">=</span> <span class="token constant">JSON</span><span class="token punctuation">.</span><span class="token function">parse</span><span class="token punctuation">(</span>result<span class="token punctuation">.</span>map<span class="token punctuation">)</span><span class="token punctuation">;</span><br />	map<span class="token punctuation">.</span>sourceRoot <span class="token operator">=</span> domain<span class="token punctuation">;</span><br />	result<span class="token punctuation">.</span>map <span class="token operator">=</span> <span class="token constant">JSON</span><span class="token punctuation">.</span><span class="token function">stringify</span><span class="token punctuation">(</span>map<span class="token punctuation">,</span> <span class="token keyword">null</span><span class="token punctuation">,</span> <span class="token string">"\t"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />	<span class="token keyword">var</span> fullMap <span class="token operator">=</span> result<span class="token punctuation">.</span>map<span class="token punctuation">.</span><span class="token function">toString</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p id="code-skip-hello-day-8-9">I understand everything that my code is doing here, but the use of <code>process.cwd</code> here is very confusing. It works, for sure! I now have:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-8/#code-skip-hello-day-8-8" id="skip-to-code-skip-hello-day-8-8" class="skip-link">Skip code block ▼</a></p>
<pre class="language-json"><code class="language-json">	<span class="token property">"version"</span><span class="token operator">:</span> <span class="token number">3</span><span class="token punctuation">,</span><br />	<span class="token property">"sourceRoot"</span><span class="token operator">:</span> <span class="token string">"http://localhost:8080"</span><span class="token punctuation">,</span><br />	<span class="token property">"sources"</span><span class="token operator">:</span> <span class="token punctuation">[</span><br />		<span class="token string">"dinky/_sass/jekyll-theme-dinky.scss"</span><span class="token punctuation">,</span><br />		<span class="token string">"dinky/_sass/rouge-github.scss"</span><span class="token punctuation">,</span><br />		<span class="token string">"src/_sass/base-syntax-highlighting.scss"</span><span class="token punctuation">,</span><br />		<span class="token string">"src/_sass/syntax-highlighting.scss"</span><span class="token punctuation">,</span><br />		<span class="token string">"src/_sass/user.sass"</span><br />	<span class="token punctuation">]</span><span class="token punctuation">,</span></code></pre>
<p id="code-skip-hello-day-8-8">The code sample says &quot;HACK 1: Force all &quot;sources&quot; to be relative to project root&quot; but it apparently does this so that dart-sass... gets rid of the project root? I find this process very confusing, I'm adding the project root so Sass can remove the project root? This is fking baffling to me and apparently hits some process that is very badly documented in dart-sass. The other hack &quot;node-sass does not support sourceRoot, but we can add it&quot; at least makes sense. Seems like something you should support! It looks like some iteration of Node-based Sass takes the <code>sourceMapRoot</code> configuration property, but not dart-sass. The documentation and debugging process is very confusing for this because dart-sass links to node-sass for most of its documentation, but node-sass clearly has some features that dart-sass does not, and the fact that issues are often in node-sass that are actually about dart-sass is just a <em>mess</em>.</p>
<p>Anyway, this works now... and it gives me a really useful insight into how the source map is built. I can hack better paths for sources! The paths themselves are useful for the project, but having them at the base of the website sort of irks me. Now I can put them all in a nice <code>sass</code> folder, makes it neat.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-8/#code-skip-hello-day-8-7" id="skip-to-code-skip-hello-day-8-7" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript">	<span class="token keyword">var</span> newSources <span class="token operator">=</span> map<span class="token punctuation">.</span>sources<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">source</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />		<span class="token keyword">return</span> <span class="token string">"sass/"</span> <span class="token operator">+</span> source<span class="token punctuation">;</span><br />	<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />	map<span class="token punctuation">.</span>sources <span class="token operator">=</span> newSources<span class="token punctuation">;</span></code></pre>
<p id="code-skip-hello-day-8-7">And I can also change my passthroughs in <code>.eleventy.js</code>.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-8/#code-skip-hello-day-8-6" id="skip-to-code-skip-hello-day-8-6" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript">	eleventyConfig<span class="token punctuation">.</span><span class="token function">addPassthroughCopy</span><span class="token punctuation">(</span><span class="token punctuation">{</span><br />		<span class="token string-property property">"dinky/_sass"</span><span class="token operator">:</span> <span class="token string">"sass/dinky/_sass"</span><span class="token punctuation">,</span><br />	<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />	eleventyConfig<span class="token punctuation">.</span><span class="token function">addPassthroughCopy</span><span class="token punctuation">(</span><span class="token punctuation">{</span><br />		<span class="token string-property property">"src/_sass"</span><span class="token operator">:</span> <span class="token string">"sass/src/_sass"</span><span class="token punctuation">,</span><br />	<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p id="code-skip-hello-day-8-6">If this works correctly on publish, it will resolve the last of my base requirements!</p>
<h3 id="cache-break-with-github" tabindex="-1">Cache Break with GitHub</h3>
<p>Ok, I was thinking about how to handle build-time cache-breaking and realized that there's likely a way to handle getting a cache-break variable at the build stage. There's <a href="https://github.com/jekyll/github-metadata" target="_blank">a plugin for Jekyll to do it</a>, it looks like <a href="https://github.com/jekyll/github-metadata/blob/master/docs/authentication.md" target="_blank">it does so at least partially via the Github API</a>. It gets <a href="https://github.com/jekyll/github-metadata/blob/master/docs/site.github.md" target="_blank">a pretty good list of data too</a>. There's also <a href="https://docs.github.com/en/actions/reference/context-and-expression-syntax-for-github-actions#github-context" target="_blank">the &quot;Github Context&quot; which is available to GitHub actions</a>. I could call the API during build time, which is what it appears that Jekyll is doing (I didn't really look too deeply into the plugin). But if this data is available in the Actions context... couldn't I export it as a environment variable? Why not try adding that to the Github Actions script?</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-8/#code-skip-hello-day-8-5" id="skip-to-code-skip-hello-day-8-5" class="skip-link">Skip code block ▼</a></p>
<pre class="language-yaml"><code class="language-yaml">        <span class="token punctuation">-</span> <span class="token key atrule">run</span><span class="token punctuation">:</span> export GITHUB_HEAD_SHA=$<span class="token punctuation">{</span><span class="token punctuation">{</span> github.run_id <span class="token punctuation">}</span><span class="token punctuation">}</span></code></pre>
<p id="code-skip-hello-day-8-5">Now I should be able to call this in my site data, right? So I'll update the file at <code>src/_data/site.js</code>.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-8/#code-skip-hello-day-8-4" id="skip-to-code-skip-hello-day-8-4" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript">module<span class="token punctuation">.</span><span class="token function-variable function">exports</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">info</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br />	<span class="token keyword">return</span> <span class="token punctuation">{</span><br />		<span class="token literal-property property">lang</span><span class="token operator">:</span> <span class="token string">"en-US"</span><span class="token punctuation">,</span><br />		<span class="token literal-property property">github</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />			<span class="token literal-property property">build_revision</span><span class="token operator">:</span> process<span class="token punctuation">.</span>env<span class="token punctuation">.</span><span class="token constant">GITHUB_HEAD_SHA</span> <span class="token operator">||</span> <span class="token number">1.0</span><span class="token punctuation">,</span><br />		<span class="token punctuation">}</span><span class="token punctuation">,</span><br />		<span class="token literal-property property">site_url</span><span class="token operator">:</span> process<span class="token punctuation">.</span>env<span class="token punctuation">.</span><span class="token constant">DOMAIN</span><span class="token punctuation">,</span><br />	<span class="token punctuation">}</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
<p id="code-skip-hello-day-8-4">Huh... about to try this but a thought occurs... should I just export the whole <code>github</code> object? Would that work? Wait... <a href="https://docs.github.com/en/actions/reference/environment-variables" target="_blank">is it already there</a>? Let me try that both ways and see what I get.</p>
<p><a target="_blank" href="https://github.com/AramZS/devblog/commit/e25ca3229277e2348f288607e48322d1ee66fef1" class="git-commit-link"><code>git commit -am &quot;Set up new Sass build process and new build vars in use&quot; </code></a></p>
<p>Well... the Sass sitemaps built properly, but none of the Github Actions env stuff seemed to have gone off. For some reason calling <code>process.env.GITHUB_JOB</code> just got me <code>deploy</code>. Which is the job name, not a job-run ID. But a step in the right direction, just me mistakenly reading the docs.</p>
<p data-wordfix="true">What if I set the <code>env</code> at the level of job? I think this means I could probably use <code>GITHUB_SHA</code>, but I want to see what works.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-8/#code-skip-hello-day-8-3" id="skip-to-code-skip-hello-day-8-3" class="skip-link">Skip code block ▼</a></p>
<pre class="language-yaml"><code class="language-yaml"><span class="token key atrule">jobs</span><span class="token punctuation">:</span><br />  <span class="token key atrule">deploy</span><span class="token punctuation">:</span><br />    <span class="token key atrule">runs-on</span><span class="token punctuation">:</span> ubuntu<span class="token punctuation">-</span>latest<br />    <span class="token key atrule">env</span><span class="token punctuation">:</span><br />      <span class="token key atrule">MY_GITHUB_RUN_ID</span><span class="token punctuation">:</span> $<span class="token punctuation">{</span><span class="token punctuation">{</span> github.run_id <span class="token punctuation">}</span><span class="token punctuation">}</span></code></pre>
<p id="code-skip-hello-day-8-3">Ah, that did it, so now I know how to use both!</p>
<h3 id="site-maps" tabindex="-1">Site Maps</h3>
<p>The sitemap plugin looks easy to implement. Let's try that!</p>
<p>Looks good! A little basic as sitemaps go, and if this site gets extensive I may have to figure out file splitting, but there's a lot of flexibility and options in the plugin so I'm not too worried.</p>
<p><a target="_blank" href="https://github.com/AramZS/devblog/commit/e527c030ea5012de9b0d77fb1d8abeaf92f51bf8" class="git-commit-link"><code>git commit -am &quot;Set up sitemap&quot;</code></a></p>
<p>Just checking off stuff in this post!</p>
<p>Looks like the Deep Data Merge is up and running already. I'll do a quick double check and it does appear to work fine!</p>
<h3 id="managing-page-data" tabindex="-1">Managing Page Data</h3>
<p>RSS feed next. Need to add the collection tag to my <code>posts.json</code> in <code>src/posts</code> in order to have it properly in a <code>posts</code> collection.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-8/#code-skip-hello-day-8-2" id="skip-to-code-skip-hello-day-8-2" class="skip-link">Skip code block ▼</a></p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span><br />	<span class="token property">"layout"</span><span class="token operator">:</span> <span class="token string">"post.njk"</span><span class="token punctuation">,</span><br />	<span class="token property">"description"</span><span class="token operator">:</span> <span class="token string">"Aram is talking about code"</span><span class="token punctuation">,</span><br />	<span class="token property">"tags"</span><span class="token operator">:</span> <span class="token punctuation">[</span> <span class="token string">"posts"</span> <span class="token punctuation">]</span><br /><span class="token punctuation">}</span></code></pre>
<p id="code-skip-hello-day-8-2">Huh, I'm getting this in the output now: <code>Benchmark (Configuration): &quot;htmlToAbsoluteUrls&quot; Nunjucks Async Filter took 40ms (8.9%, called 8×, 5.0ms each)</code> and the domain name is wrong in the RSS feed. Found some info on building permalinks that may be useful for my more dynamic link urls, but doesn't seem to be for this. Huh, looks like this generates an Atom feed, not an RSS standard one. Going to rename the file accordingly.</p>
<p>Still no go on getting those URLs set up properly. I need to pass the calculated domain in to the page metadata, but using template tags or JS functions doesn't seem to be doing it. The domain data just isn't going through.</p>
<p>Ok, I had thought the functions in the <code>js</code> layout-based front matter would execute themselves, but it looks like I have to write them to execute in the context of the front matter itself. So now the front matter looks like this:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-8/#code-skip-hello-day-8-1" id="skip-to-code-skip-hello-day-8-1" class="skip-link">Skip code block ▼</a></p>
<pre class="language-liquid"><code class="language-liquid">---js<br />{<br />  "permalink": "feed.xml",<br />  "eleventyExcludeFromCollections": true,<br />  "metadata": {<br />    "title": "Feed for Fight With Tools - Aram's Dev Blog",<br />    "subtitle": "Notes on various projects",<br />    "url": (function(){ return process.env.DOMAIN + "/" })(),<br />    "feedUrl": (function(){ return process.env.DOMAIN + "/feed.xml" })(),<br />    "author": {<br />      "name": "Aram Zucker-Scharff",<br />      "email": "aramdevblog@aramzs.me"<br />    }<br />  },<br />  "internalPageTypes": [ "feed" ]<br />}<br />---</code></pre>
<p id="code-skip-hello-day-8-1">Looks like the solution was to use a immediately-invoked function there. Working well now!</p>
<h3 id="robots.txt" tabindex="-1">Robots.txt</h3>
<p>Looks like <a href="https://obsolete29.com/posts/ogp-seo-favicons-eleventy/" target="_blank">there is a straightforward way to handle building a good robots.txt</a> file.</p>
<p>I'll hand build an RSS template so I have an RSS2 feed as well.</p>
<p><a target="_blank" href="https://github.com/AramZS/devblog/commit/016bcea57a7cdde543f314b07b98f4adf544a569" class="git-commit-link"><code>git commit -am &quot;Set up various feeds and crawling tools&quot;</code></a></p>
]]></content:encoded>
	</item>
	
	<item>
		<title>Part 7: Getting GitHub Actions to Publish my Site</title>
		<link>https://fightwithtools.dev/posts/projects/devblog/hello-day-7/?source=rss</link>
		<pubDate>Mon, 21 Jun 2021 02:59:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/projects/devblog/hello-day-7/</guid>
		<description>Day 7 of setting up 11ty dev blog.</description>
		<content:encoded><![CDATA[<h2 id="project-scope-and-todos" tabindex="-1">Project Scope and ToDos</h2>
<ol>
<li>Static Site Generator that can build the blog and let me host it on Github Pages</li>
<li>I want to write posts in Markdown because I'm lazy, it's easy, and it is how I take notes now.</li>
<li>I don't want to spend a ton of time doing design work. I'm doing complicated designs for other projects, so I want to pull a theme I like that I can rely on someone else to keep up.</li>
<li>Once it gets going, I want template changes to be easy.</li>
<li>It should be as easy as Jekyll, so I need to be able to build it using GitHub Actions, where I can just commit a template change or Markdown file and away it goes. If I can't figure this out than fk it, just use Jekyll.</li>
<li>I require it to be used by a significant percent of my professional peers so I can get easy answers when something goes wrong.</li>
<li>I want source maps. This is a dev log site which means whatever I do with it should be easy for other developers to read.</li>
</ol>
<ul class="task-list">
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Also <a href="https://www.npmjs.com/package/@quasibit/eleventy-plugin-sitemap" target="_blank">the sitemap plugin</a> looks cool. Should grab that later.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> So does the <a href="https://www.npmjs.com/package/eleventy-plugin-reading-time" target="_blank">reading time one</a>.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Also <a href="https://github.com/jdsteinbach/eleventy-plugin-toc/blob/master/src/BuildTOC.js" target="_blank">this TOC plugin</a> mby?</p>
</li>
<li class="task-list-item">
<p data-wordfix="true"><input disabled="true" type="checkbox" class="markdown-todo" /> Use <a href="https://www.11ty.dev/docs/data-deep-merge/" target="_blank">Data Deep Merge</a> in this blog.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Decide if I want to render the CSS fancier than just a base file and do per-template splitting.</p>
</li>
</ul>
<s>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Can I use the template inside of dinky that already exists instead of copy/pasting it?</li>
</ul>
</s>
<ul class="task-list">
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Is there a way to have permalinks to posts contain metadata without organizing them into subfolders?</p>
</li>
<li class="task-list-item">
<p data-wordfix="true"><input disabled="true" type="checkbox" class="markdown-todo" /> How do I cachebreak files on the basis of new build events? Datetime? <code>site.github.build_revision</code> is <a href="https://github.com/jekyll/github-metadata/blob/master/docs/site.github.md" target="_blank">how Jekyll accomplishes this</a>, but is there a way to push <a href="https://docs.github.com/en/actions/reference/context-and-expression-syntax-for-github-actions#github-context" target="_blank">that</a> <a href="https://stackoverflow.com/questions/54310050/how-to-version-build-artifacts-using-github-actions" target="_blank">into the build process</a> for Eleventy?</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Make link text look less shitty. It looks like it is a whole, lighter, font.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Code blocks do not have good syntax highlighting. I want good syntax highlighting.</p>
</li>
<li class="task-list-item">
<p data-wordfix="true"><input disabled="true" type="checkbox" class="markdown-todo" /> Build a Markdown-it plugin to take my typing shortcuts <code>[prob, b/c, ...?]</code> and expand them on build.</p>
</li>
</ul>
<h2 id="day-7" tabindex="-1">Day 7</h2>
<p>Ok, after struggling with the plane wifi and spending some time talking to my row-mate about us both being web engineers, I didn't get quite as much as I had planned done on the plane. So we're back with an empty build branch.</p>
<p>Time to get back to it. I think the first thing is to check the various GitHub actions. I'd hoped they'd work right out of the box but no-go (maybe?). The LinkedIn post was helpful, but the fact that the author's project is no longer public makes it a pain to make sure I'm following directions properly.</p>
<h3 id="github-actions-with-node" tabindex="-1">GitHub Actions with Node</h3>
<p>First is <a href="https://github.com/actions/setup-node" target="_blank">setup-node</a>. And some immediate things pop out at me. First I'd set up with Node 15 locally. But it looks like this action is only able to use up to and including Node 14. So, let's use nvm and rebuild the node_modules and package-lock.json files with Node 14. Deleting them both, changing the value in <code>.nvmrc</code> and rebooting my terminal.</p>
<p>Oh, NVM doesn't automatically use the latest node version huh? Ok, I'll specify the version to match the action on Github. Downloading and installing it now.</p>
<p><code>npm install</code></p>
<p>Ok. Everything still works, so that is good!</p>
<p>But what could be the issue, it must be me gitignoring the docs folder, I guess it has to commit the folder? I still don't want the docs folder on my main branch if I can avoid it. What if I just remove the docs gitignore during the build process?</p>
<p>I'll add the line to the top of the commands run, it basically echoes the contents of .gitignore starting at the 2nd line back into the .gitignore file:</p>
<p><code>- run: echo &quot;$(tail -n +2 .gitignore)&quot; &gt; .gitignore</code></p>
<p><a target="_blank" href="https://github.com/AramZS/devblog/commit/6749588d3451a8f787932430adeec07aa72ce567" class="git-commit-link"><code>git commit -am &quot;Update build process and attempt to commit the docs folder in the build process&quot;</code></a></p>
<p>Hmmm still no go. Let's read <a href="https://github.com/peaceiris/actions-gh-pages#github-actions-for-github-pages" target="_blank">the actions-gh-pages docs</a> from zero instead.</p>
<p>It looks like <code>publish_dir:</code> in the build task says is the <em>source</em> folder to publish onto the gh-pages branch. A good lesson to read the docs right here because literally line 2 is</p>
<blockquote>
<p>The next example step will deploy ./public directory to the remote gh-pages branch.</p>
</blockquote>
<p><a target="_blank" href="https://github.com/AramZS/devblog/commit/4301b2aed961f6df305f227ec7ea5429cc65a162" class="git-commit-link"><code>git commit -am &quot;Is the issue the docs directory needs to be the public_dir?&quot;</code></a></p>
<p>Interesting, now the content is properly in the gh-pages branch! I might not even need the gitignore change?</p>
<p><a target="_blank" href="https://github.com/AramZS/devblog/commit/0a5c8daaedff730db83931f989458d8b12fbb02d" class="git-commit-link"><code>git commit -am &quot;Remove the gitignore rewrite&quot;</code></a></p>
<p>I also originally had the folder set for Github Pages to be <code>/docs</code> but that's not how this works, the action publishes the content inside the docs folder to the root of the <code>gh-pages</code> branch. I have to fix that in the repo settings.</p>
<p>Sweet, I see a page now! Just have to fix how the stylesheet works in the build environment!</p>
<h3 id="mapping-the-site" tabindex="-1">Mapping the site</h3>
<p>While I'm here I should <a href="https://docs.github.com/en/pages/configuring-a-custom-domain-for-your-github-pages-site/managing-a-custom-domain-for-your-github-pages-site" target="_blank">map my apex domain to the Github Site</a>. Easy enough, create a bunch of A records in GoDaddy's DNS controls and then direct my <code>www</code> record CNAME to my <a href="http://github.io/" target="_blank">github.io</a> user page.</p>
<p data-wordfix="true">I'll create the correct CNAME file and set up Eleventy to pass it through to the build process.</p>
<p><code>eleventyConfig.addPassthroughCopy(&quot;./CNAME&quot;);</code></p>
<p>And I'm going to set up my site data using <a href="https://www.npmjs.com/package/dotenv" target="_blank">dotenv</a> in order to have my local <code>http://localhost:8080</code> server used for the site domain when local and otherwise have it use my domain.</p>
<p><a target="_blank" href="https://github.com/AramZS/devblog/commit/4d7e6819540e013935077525b0c3274f9f8b8a5c" class="git-commit-link"><code>git commit -am &quot;Setting up dotenv to have proper site data and domain use&quot;</code></a></p>
<p>Oops, swapped my prod and local domains.</p>
<p><a target="_blank" href="https://github.com/AramZS/devblog/commit/d6f84e6d95d1635bec1681e4959fc479ed544e4d" class="git-commit-link"><code>git commit -am &quot;Ooops mixed up my local and prod urls&quot;</code></a></p>
<p>Ok, it looks like it is all working for my my base level requirements 1-6. I still want a source map for my CSS and that isn't done yet, but that is a Sass task.</p>
<p>I still have some other major tasks... like building a real home page, including serious SE/MO and a few other things, but now I can move forward on that work confident that this system hits my baseline requirements and I can invest more time into it.</p>
<p>Finishing off my requirements means handling some Sass to get mapping to work. I can define <code>sourceMap</code> and write the file appropriately, but it looks like I'll need handle two complications, first the relative paths to the source file will have to be passed through so the Sass files can be exposed on the front end. That's easy enough with a few functions in <code>.eleventy.js</code>. But it also apparently will need to have a full, not relative, url.</p>
<p data-wordfix="true">I thought I might be able to use <a href="https://www.11ty.dev/docs/data-global-custom/" target="_blank">global data added at the config level, but it looks like that isn't available yet</a>. Didn't see that on my first run through as it isn't super obviously called out.</p>
<p>I decided to use a combination of dotenv and setting some internal Node-level variables here to set up the domain name once and reuse it elsewhere.</p>
<h3 id="image-and-link-conflicts" tabindex="-1">Image and Link Conflicts</h3>
<p>Hmmm, while trying to debug I noticed my image rewrite method was also applying to all links. Oops. I'll need to pass in a smarter function.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-7/#code-skip-hello-day-7-1" id="skip-to-code-skip-hello-day-7-1" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript">		<span class="token function-variable function">replaceLink</span><span class="token operator">:</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">link<span class="token punctuation">,</span> env</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />			<span class="token comment">// console.log("env:", env);</span><br />			<span class="token keyword">var</span> imageLinkRegex <span class="token operator">=</span> <span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">^..\/img\/</span><span class="token regex-delimiter">/</span></span><span class="token punctuation">;</span><br />			<span class="token keyword">if</span> <span class="token punctuation">(</span>link <span class="token operator">&amp;&amp;</span> imageLinkRegex<span class="token punctuation">.</span><span class="token function">test</span><span class="token punctuation">(</span>link<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />				<span class="token keyword">return</span> <span class="token punctuation">(</span><br />					env<span class="token punctuation">.</span>site<span class="token punctuation">.</span>site_url <span class="token operator">+</span><br />					<span class="token string">"/img/"</span> <span class="token operator">+</span><br />					link<span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span>imageLinkRegex<span class="token punctuation">,</span> <span class="token string">""</span><span class="token punctuation">)</span><br />				<span class="token punctuation">)</span><span class="token punctuation">;</span><br />			<span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span><br />				<span class="token keyword">return</span> link<span class="token punctuation">;</span><br />			<span class="token punctuation">}</span><br />		<span class="token punctuation">}</span></code></pre>
<p id="code-skip-hello-day-7-1">While I'm fiddling with markdown-it, I should also <a href="https://github.com/markdown-it/markdown-it/blob/master/docs/architecture.md#renderer" target="_blank">add <code>target=&quot;_blank&quot;</code> to all my links</a>.</p>
<p>Still looking at how to get <a href="https://developer.mozilla.org/en-US/docs/Tools/Debugger/How_to/Use_a_source_map" target="_blank">sourcemaps</a> working.</p>
<p><a target="_blank" href="https://github.com/AramZS/devblog/commit/ab13317595a5affa40ded39e3fda0926e4687d2e" class="git-commit-link"><code>git commit -am &quot;Fixing a number of path and link issues, still trying to get Sass working with sourcemaps&quot;</code></a></p>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> See if we can start Markdown's interpretation of H tags to <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/Heading_Elements#multiple_h1" target="_blank">start at 2, since H1</a> is always pulled from the page title metadata. If it isn't easy, I just have to change my pattern of writing in the MD documents.</li>
</ul>
]]></content:encoded>
	</item>
	
	<item>
		<title>Part 6: Starting to deal with GitHub Actions</title>
		<link>https://fightwithtools.dev/posts/projects/devblog/hello-day-6/?source=rss</link>
		<pubDate>Sat, 19 Jun 2021 03:59:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/projects/devblog/hello-day-6/</guid>
		<description>Day 6 of setting up 11ty dev blog.</description>
		<content:encoded><![CDATA[<h2 id="project-scope-and-todos" tabindex="-1">Project Scope and ToDos</h2>
<ol>
<li>Static Site Generator that can build the blog and let me host it on Github Pages</li>
<li>I want to write posts in Markdown because I'm lazy, it's easy, and it is how I take notes now.</li>
<li>I don't want to spend a ton of time doing design work. I'm doing complicated designs for other projects, so I want to pull a theme I like that I can rely on someone else to keep up.</li>
<li>Once it gets going, I want template changes to be easy.</li>
<li>It should be as easy as Jekyll, so I need to be able to build it using GitHub Actions, where I can just commit a template change or Markdown file and away it goes. If I can't figure this out than fk it, just use Jekyll.</li>
<li>I require it to be used by a significant percent of my professional peers so I can get easy answers when something goes wrong.</li>
<li>I want source maps. This is a dev log site which means whatever I do with it should be easy for other developers to read.</li>
</ol>
<ul class="task-list">
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Also <a href="https://www.npmjs.com/package/@quasibit/eleventy-plugin-sitemap" target="_blank">the sitemap plugin</a> looks cool. Should grab that later.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> So does the <a href="https://www.npmjs.com/package/eleventy-plugin-reading-time" target="_blank">reading time one</a>.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Also <a href="https://github.com/jdsteinbach/eleventy-plugin-toc/blob/master/src/BuildTOC.js" target="_blank">this TOC plugin</a> mby?</p>
</li>
<li class="task-list-item">
<p data-wordfix="true"><input disabled="true" type="checkbox" class="markdown-todo" /> Use <a href="https://www.11ty.dev/docs/data-deep-merge/" target="_blank">Data Deep Merge</a> in this blog.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Decide if I want to render the CSS fancier than just a base file and do per-template splitting.</p>
</li>
</ul>
<s>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Can I use the template inside of dinky that already exists instead of copy/pasting it?</li>
</ul>
</s>
<ul class="task-list">
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Is there a way to have permalinks to posts contain metadata without organizing them into subfolders?</p>
</li>
<li class="task-list-item">
<p data-wordfix="true"><input disabled="true" type="checkbox" class="markdown-todo" /> How do I cachebreak files on the basis of new build events? Datetime? <code>site.github.build_revision</code> is how Jekyll accomplishes this, but is there a way to push that into the build process for Eleventy?</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Make link text look less shitty. It looks like it is a whole, lighter, font.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Code blocks do not have good syntax highlighting. I want good syntax highlighting.</p>
</li>
</ul>
<h2 id="day-6" tabindex="-1">Day 6</h2>
<p>Ok, here we go on day 6. Today I write code on a Delta flight.</p>
<p data-wordfix="true">I've resolved some of the very basic blockers that were absolute need-to-haves from a design perspective. There is more work to be done on the design side (obviously, I still don't have a home page) but I think I need to answer questions about the GitHub Pages deployment process before I go any further. I know I can make an Eleventy blog that satisfies me now, but can I do so while also satisfying the ease of deployment and management that comes with Jekyll-style Github Pages deployment? Luckily the internet is free today, so I can find out at no added cost to my flight.</p>
<h3 id="looking-at-the-examples" tabindex="-1">Looking at the Examples</h3>
<p>The most upvoted solution I saw for Github Pages deployment was <a href="https://www.linkedin.com/pulse/eleventy-github-pages-lea-tortay/" target="_blank">the LinkedIn post by Lea Tortay</a> I found earlier. While I've managed a number of other deploy approaches, I actually have never written my own Github Pages deployment process, so figuring that out was one of my goals with this project. Let's start with that.</p>
<p>Oh, lol the wifi was only free for the first 5 minutes I guess? Ok, I'll pay.</p>
<p>Hmmmmm Captive Portal problems. Time to reboot.</p>
<p>Had to reboot, find the captive portal URL, cycle my DHCP lease and then pay for the privlige, but on the interwebs again. Payed to get on.</p>
<p>Ok, implimented the Github actions file with a few small changes, I went ahead and updated <code>node-version</code> to match my latest version and switched by branch from master to main. Took care of the keys as specified. The action ran... but no joy. Maybe the problem is a lack of index page? Let's try putting one together.</p>
<p>Huh... it build from the file at <code>src/index.njk</code> once... and now it hasn't again. I made my defaults layout the same as my posts layout, so it should work. But after I wiped it out one time, it hasn't built again.</p>
<p>Is it possible to have the docs content not committed on <code>main</code> but only on <code>gh-pages</code>? That would seem to be a good solution, but let's see.</p>
<p>Ooops, I was fiddling with trying to build a useful gitignore file for docs and passing it through and accidentally deleted all my layouts.</p>
<p>Let me pull those files back in from the last good commit: <code>git checkout 32e6206c0680d9009a316b85e33461479058d81d src/_layouts/*</code></p>
<p>Yup that did it. My Index file is back.</p>
<h3 id="finding-github-actions-log" tabindex="-1">Finding GitHub Actions log</h3>
<p>Build still isn't working. Hmmm where are the logs for this?</p>
<p>Ok, <a href="https://github.com/AramZS/devblog/actions" target="_blank">in the Actions tab</a>, not in settings.</p>
<p>Looks like it isn't pulling in Dinky properly as a submodule because <a href="https://docs.github.com/en/pages/getting-started-with-github-pages/using-submodules-with-github-pages" target="_blank">Github Pages needs the https url for the repo in .gitsubmodules</a>.</p>
<p>Hmmm, still not working.</p>
<h3 id="fixing-submodules" tabindex="-1">Fixing Submodules</h3>
<p>Ah, the issue is that the default configuration of Jekyll github pages pulls in submodules, but <a href="https://github.com/actions/checkout" target="_blank">the default configuration of the checkout action doesn't</a>. I just need to add that property to the yml file.</p>
<p>Oh, and fix my <code>.editorconfig</code> to work better with yml files.</p>
<p><a target="_blank" href="https://github.com/AramZS/devblog/commit/88c0d76e164179a2626941d0e3c1f35113e39326" class="git-commit-link"><code>git commit -am &quot;Get submodules working for github actions hopefully&quot;</code></a></p>
<p>Good news, a new error!</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-6/#code-skip-hello-day-6-1" id="skip-to-code-skip-hello-day-6-1" class="skip-link">Skip code block ▼</a></p>
<pre class="language-bash"><code class="language-bash">Run peaceiris/actions-gh-pages@v3<br /><span class="token punctuation">[</span>INFO<span class="token punctuation">]</span> Usage https://github.com/peaceiris/actions-gh-pages<span class="token comment">#readme</span><br />Dump inputs<br />Setup auth token<br />  Error: Action failed with <span class="token string">"not found deploy key or tokens"</span></code></pre>
<p id="code-skip-hello-day-6-1">Oops, but the secret in a custom environment instead of the <code>github-pages</code> <a href="https://github.com/AramZS/devblog/settings/environments" target="_blank">environment</a>.</p>
<p data-wordfix="true">Hmmm... deploy was a success this time, but no-go on seeing any pages? Looks like it just deleted everything but the nojekyll file? I should probably look a little deeper into what is going on with these GitHub actions.</p>
<p>Ooooh. I should make a markdown code to expand my little typing shortcuts!</p>
<p data-wordfix="true">[ ] Build a Markdown-it plugin to take my typing shortcuts <code>[prob, b/c, ...?]</code> and expand them on build.</p>
<p><a target="_blank" href="https://github.com/AramZS/devblog/commit/74db6c5f65a117b4c8590422703a30317ad6e524" class="git-commit-link"><code>git commit -am &quot;Have I got the secret now?&quot;</code></a></p>
]]></content:encoded>
	</item>
	
	<item>
		<title>Part 5: Image Handling and CSS Improvements</title>
		<link>https://fightwithtools.dev/posts/projects/devblog/hello-day-5/?source=rss</link>
		<pubDate>Thu, 17 Jun 2021 03:59:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/projects/devblog/hello-day-5/</guid>
		<description>Part 5 of setting up 11ty dev blog.</description>
		<content:encoded><![CDATA[<h2 id="project-scope-and-todos" tabindex="-1">Project Scope and ToDos</h2>
<ol>
<li>Static Site Generator that can build the blog and let me host it on Github Pages</li>
<li>I want to write posts in Markdown because I'm lazy, it's easy, and it is how I take notes now.</li>
<li>I don't want to spend a ton of time doing design work. I'm doing complicated designs for other projects, so I want to pull a theme I like that I can rely on someone else to keep up.</li>
<li>Once it gets going, I want template changes to be easy.</li>
<li>It should be as easy as Jekyll, so I need to be able to build it using GitHub Actions, where I can just commit a template change or Markdown file and away it goes. If I can't figure this out than fk it, just use Jekyll.</li>
<li>I require it to be used by a significant percent of my professional peers so I can get easy answers when something goes wrong.</li>
<li>I want source maps. This is a dev log site which means whatever I do with it should be easy for other developers to read.</li>
</ol>
<ul class="task-list">
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Also <a href="https://www.npmjs.com/package/@quasibit/eleventy-plugin-sitemap" target="_blank">the sitemap plugin</a> looks cool. Should grab that later.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> So does the <a href="https://www.npmjs.com/package/eleventy-plugin-reading-time" target="_blank">reading time one</a>.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Also <a href="https://github.com/jdsteinbach/eleventy-plugin-toc/blob/master/src/BuildTOC.js" target="_blank">this TOC plugin</a> mby?</p>
</li>
<li class="task-list-item">
<p data-wordfix="true"><input disabled="true" type="checkbox" class="markdown-todo" /> Use <a href="https://www.11ty.dev/docs/data-deep-merge/" target="_blank">Data Deep Merge</a> in this blog.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Decide if I want to render the CSS fancier than just a base file and do per-template splitting.</p>
</li>
</ul>
<s>
<ul class="task-list">
<li class="task-list-item"><input disabled="true" type="checkbox" class="markdown-todo" /> Can I use the template inside of dinky that already exists instead of copy/pasting it?</li>
</ul>
</s>
<ul class="task-list">
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Is there a way to have permalinks to posts contain metadata without organizing them into subfolders?</p>
</li>
<li class="task-list-item">
<p data-wordfix="true"><input disabled="true" type="checkbox" class="markdown-todo" /> How do I cachebreak files on the basis of new build events? Datetime? <code>site.github.build_revision</code> is how Jekyll accomplishes this, but is there a way to push that into the build process for Eleventy?</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" class="markdown-todo" /> Make link text look less shitty. It looks like it is a whole, lighter, font.</p>
</li>
<li class="task-list-item">
<p><input disabled="true" type="checkbox" checked="true" class="markdown-todo" /> Code blocks do not have good syntax highlighting. I want good syntax highlighting.</p>
</li>
</ul>
<h2 id="day-5" tabindex="-1">Day 5</h2>
<p>Ok, yesterday I didn't have that much time to work, but today I'm feeling as good as I can after having my main battery and a whole bunch of USB sticks, a Yubi key, and my main external Anker power battery robbed out of the back of a rental car in San Antonio yesterday.</p>
<h3 id="figuring-out-the-images" tabindex="-1">Figuring out the Images</h3>
<p>Good news, finally a check mark on my ever-expanding scope list. Some bad news for the task list as well, in that I'm now 99% sure I can't just pull the template from the dinky submodule. I think there are just too significant a set of differences between Jekyll and Nunjucks. I could explore more similar templating languages, but getting better at Nunjucks is part of the point of all this, so I'm going to dismiss that from my work scope for now.</p>
<p>So, since it hasn't been a great 24hs IRL, let's see if I can harvest a few more easy wins.</p>
<p>How do the GitHub variables work for cachebreaking? That seems like a potentially non-obvious but relatively easy win. A-searching we do go.</p>
<p>Interesting to see someone <a href="https://snook.ca/archives/servers/deploying-11ty-to-gh-pages" target="_blank">handling their build via Travis</a>, good to remember.</p>
<p>Ok, that was unexpected. No one seems to have asked this question? Maybe it just works? I guess I'll have to wait to deploy in order to see. Moving on to something entirely in my hands, let's make the links look less shitty.</p>
<p>Let me show you the problem.</p>
<p>Oh, wait, need to get the image folder working first...</p>
<p>Ok, following the pattern of posts the <code>img</code> folder should be inside of <code>src</code>. Gotta fix the passthrough <code>eleventyConfig.addPassthroughCopy(&quot;src/img&quot;, &quot;img&quot;);</code>.</p>
<p data-wordfix="true">Oh, I actually <a href="https://www.11ty.dev/docs/copy/#how-passthrough-file-copy-handles-input-directories" target="_blank">don't need to be that explicit</a>. <code>eleventyConfig.addPassthroughCopy(&quot;src/img&quot;, &quot;img&quot;);</code> works just fine.</p>
<p>Hmmm, I could do full URLs, but this is actually one of the things I hate about Jekyll.</p>
<p>Ugh... <a href="https://github.com/11ty/eleventy/issues/379" target="_blank">it looks like the general strategy in GitHub issues is to copy images to be relative to the folders of the associated posts</a>. That's... meh. I dislike it intensely. What if I want to reuse the image? Now I have multiples. One image, one URL IMHO.</p>
<p>Ok, looks like I'm not the only one fiddling around with this, <a href="https://www.npmjs.com/package/markdown-it-replace-link" target="_blank">someone else wrote all the annoying regexes for me in a markdown-it plugin</a>.</p>
<p data-wordfix="true">There's <a href="https://www.11ty.dev/docs/data-eleventy-supplied/" target="_blank">no way to really get the base URL</a>, but at least I can do it <a href="https://en.wikipedia.org/wiki/Don%27t_repeat_yourself" target="_blank">DRY</a>.</p>
<aside>
<p data-wordfix="true">(I also saw <a href="https://www.11ty.dev/docs/quicktips/eliminate-js/" target="_blank">how Eleventy pulls from the Github API on build</a>, which may be useful if I need to use <a href="https://docs.github.com/en/rest/reference/repos#get" target="_blank">that sort of info</a> for cachebreaking later.)</p>
</aside>
<div style="border: 2px black solid">
<p><img src="https://fightwithtools.dev/img/links-and-not-links.png" alt="Links look bad inside the text." /></p>
</div>
<h3 id="making-links-more-visible" tabindex="-1">Making Links More Visible</h3>
<p>This comes from that whole annoying school of &quot;native link styles are ugly so let's change them as much as possible and try to use some other thing to indicate they are links.&quot;</p>
<p>That school is one I do not attend. Clear and legible UX has to build on top of standards of design the user is familiar with lest a site confuse the reader. I can give any theme some room, you can remove underlines, or change the color to something other than close-to-link-blue, but both?! Nien.</p>
<p>Huh... first things first... that Sass folder should really be in <code>src</code>.</p>
<p>Ok, now to set up a <code>user</code> overwrite to be the last file in the Sass compile process, and t/f the one that overrides general site-level stuff. Let's fix it to a blue color and remove that <em>very</em> annoying light weight on the font.</p>
<p>Much better.</p>
<p>Oh, I want to make those checkboxes show up correctly. Bet there's a markdown-it plugin I can use. It looks like there are 2 possible node modules, <a href="https://www.npmjs.com/package/markdown-it-task-checkbox" target="_blank">a more used one with some unresolved PRs and ignored issues</a> and <a href="https://www.npmjs.com/package/markdown-it-todo" target="_blank">a barely used one that correctly makes checkboxes readonly</a>. It might be less popular, but I'm going with the version that works the way I want right out of the box. It also happens to be a very simple plugin, so if it goes wrong, I can always hack at it.</p>
<p>Looks good!</p>
<p><a target="_blank" href="https://github.com/AramZS/devblog/commit/62f4e132faa143fa7d1a81234018076c594c319c" class="git-commit-link"><code>git commit -am &quot;Adding days 4 and 5 progress and notes&quot;</code></a></p>
]]></content:encoded>
	</item>
	
	<item>
		<title>Part 4: A quick run at syntax highlighting</title>
		<link>https://fightwithtools.dev/posts/projects/devblog/hello-day-4/?source=rss</link>
		<pubDate>Wed, 16 Jun 2021 03:59:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/projects/devblog/hello-day-4/</guid>
		<description>Part 4 of setting up 11ty deb blog.</description>
		<content:encoded><![CDATA[<h2 id="project-scope-and-todos" tabindex="-1">Project Scope and ToDos</h2>
<ol>
<li>Static Site Generator that can build the blog and let me host it on Github Pages</li>
<li>I want to write posts in Markdown because I'm lazy, it's easy, and it is how I take notes now.</li>
<li>I don't want to spend a ton of time doing design work. I'm doing complicated designs for other projects, so I want to pull a theme I like that I can rely on someone else to keep up.</li>
<li>Once it gets going, I want template changes to be easy.</li>
<li>It should be as easy as Jekyll, so I need to be able to build it using GitHub Actions, where I can just commit a template change or Markdown file and away it goes. If I can't figure this out than fk it, just use Jekyll.</li>
<li>I require it to be used by a significant percent of my professional peers so I can get easy answers when something goes wrong.</li>
<li>I want source maps. This is a dev log site which means whatever I do with it should be easy for other developers to read.</li>
</ol>
<p>[ ] Also <a href="https://www.npmjs.com/package/@quasibit/eleventy-plugin-sitemap" target="_blank">the sitemap plugin</a> looks cool. Should grab that later.</p>
<p>[ ] So does the <a href="https://www.npmjs.com/package/eleventy-plugin-reading-time" target="_blank">reading time one</a>.</p>
<p>[ ] Also <a href="https://github.com/jdsteinbach/eleventy-plugin-toc/blob/master/src/BuildTOC.js" target="_blank">this TOC plugin</a> mby?</p>
<p data-wordfix="true">[ ] Use <a href="https://www.11ty.dev/docs/data-deep-merge/" target="_blank">Data Deep Merge</a> in this blog.</p>
<p>[ ] Decide if I want to render the CSS fancier than just a base file and do per-template splitting.</p>
<p>[ ] Can I use the template inside of dinky that already exists instead of copy/pasting it?</p>
<p>[ ] Is there a way to have permalinks to posts contain metadata without organizing them into subfolders?</p>
<p data-wordfix="true">[ ] How do I cachebreak files on the basis of new build events? Datetime? <code>site.github.build_revision</code> is how Jekyll accomplishes this, but is there a way to push that into the build process for Eleventy?</p>
<p>[ ] Make link text look less shitty. It looks like it is a whole, lighter, font.</p>
<p>[ ] Code blocks do not have good syntax highlighting. I want good syntax highlighting.</p>
<h2 id="day-4" tabindex="-1">Day 4</h2>
<p>Ok, don't have a ton of time to work today, but I've been thinking more about the shitty code blocks.</p>
<p>The core of the problem is that I can't even apply styles the way I want because the code is not being broken down properly.</p>
<p>Here's what I'm getting:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-4/#code-skip-hello-day-4-2" id="skip-to-code-skip-hello-day-4-2" class="skip-link">Skip code block ▼</a></p>
<pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>pre</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>language-markdown<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><br />	<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>code</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>language-markdown<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><br />		<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>token front-matter-block<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><br />		<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>token punctuation<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>---<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>br</span><span class="token punctuation">></span></span><br />		<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>token font-matter yaml language-yaml<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>layout: page<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>br</span><span class="token punctuation">></span></span><br />		<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>token punctuation<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>---<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">></span></span><br />	<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>code</span><span class="token punctuation">></span></span><br /><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>pre</span><span class="token punctuation">></span></span></code></pre>
<p id="code-skip-hello-day-4-2">What I want would look like this:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-4/#code-skip-hello-day-4-1" id="skip-to-code-skip-hello-day-4-1" class="skip-link">Skip code block ▼</a></p>
<pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>pre</span><span class="token punctuation">></span></span><br />	<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>code</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>language-markdown<span class="token punctuation">"</span></span> <span class="token attr-name">data-lang</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>markdown<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><br />		<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>nn<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>---<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">></span></span><br />		<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>na<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>layout<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>pi<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>:<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>s<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>post<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">></span></span><br />		<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>nn<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>---<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">></span></span><br />	<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>code</span><span class="token punctuation">></span></span><br /><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>pre</span><span class="token punctuation">></span></span></code></pre>
<p id="code-skip-hello-day-4-1">See the greater level of styling detail available via the additional span tags?</p>
<p data-wordfix="true">Ok. So, like I said, surely a lot of people are using Eleventy to demo code. Why not take a step back?</p>
<p>Instead of trying to get some increasingly complex markdown processor in play to do this, let's see if there is a code block plugin instead? If anyone uses it I bet 11ty's website does?</p>
<p><a href="https://github.com/11ty/11ty-website/blob/master/.eleventy.js#L14" target="_blank">Yup</a>!</p>
<p data-wordfix="true"><a href="https://www.11ty.dev/docs/plugins/syntaxhighlight/" target="_blank">Reading the docs</a>. Looks like it uses Prism, which I'm also familiar with. I'll try to implement like the Eleventy site does.</p>
<p>Ok, that looks a LOT better! I'll have to walk through some examples to make sure it works.</p>
<p><a target="_blank" href="https://github.com/AramZS/devblog/commit/dbc56d6f34a038e210367d60961cc4c0bef34da0" class="git-commit-link">git commit -am &quot;Syntax highlighting actually working now?&quot;</a></p>
]]></content:encoded>
	</item>
	
	<item>
		<title>Part 3: Deciding on a template tool</title>
		<link>https://fightwithtools.dev/posts/projects/devblog/hello-day-3/?source=rss</link>
		<pubDate>Tue, 15 Jun 2021 03:59:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/projects/devblog/hello-day-3/</guid>
		<description>Part 3 of setting up 11ty dev blog.</description>
		<content:encoded><![CDATA[<h2 id="project-scope-and-todos" tabindex="-1">Project Scope and ToDos</h2>
<ol>
<li>Static Site Generator that can build the blog and let me host it on Github Pages</li>
<li>I want to write posts in Markdown because I'm lazy, it's easy, and it is how I take notes now.</li>
<li>I don't want to spend a ton of time doing design work. I'm doing complicated designs for other projects, so I want to pull a theme I like that I can rely on someone else to keep up.</li>
<li>Once it gets going, I want template changes to be easy.</li>
<li>It should be as easy as Jekyll, so I need to be able to build it using GitHub Actions, where I can just commit a template change or Markdown file and away it goes. If I can't figure this out than fk it, just use Jekyll.</li>
<li>I require it to be used by a significant percent of my professional peers so I can get easy answers when something goes wrong.</li>
<li>I want source maps. This is a dev log site which means whatever I do with it should be easy for other developers to read.</li>
</ol>
<p>[ ] Also <a href="https://www.npmjs.com/package/@quasibit/eleventy-plugin-sitemap" target="_blank">the sitemap plugin</a> looks cool. Should grab that later.</p>
<p>[ ] So does the <a href="https://www.npmjs.com/package/eleventy-plugin-reading-time" target="_blank">reading time one</a>.</p>
<p>[ ] Also <a href="https://github.com/jdsteinbach/eleventy-plugin-toc/blob/master/src/BuildTOC.js" target="_blank">this TOC plugin</a> mby?</p>
<p data-wordfix="true">[ ] Use <a href="https://www.11ty.dev/docs/data-deep-merge/" target="_blank">Data Deep Merge</a> in this blog.</p>
<p>[ ] Decide if I want to render the CSS fancier than just a base file and do per-template splitting.</p>
<p>[ ] Can I use the template inside of dinky that already exists instead of copy/pasting it?</p>
<h2 id="day-3" tabindex="-1">Day 3</h2>
<p>Ok, so I'm at day 3 and everything is working at a basic level. I need an index/entry page and some ways to present posts in lists. I also am not a huge fan of the <code>site/posts/post-name</code> structure.</p>
<p>[ ] Is there a way to have permalinks to posts contain metadata without organizing them into subfolders?</p>
<h3 id="nunjucks-vs-mustache" tabindex="-1">Nunjucks vs Mustache</h3>
<p data-wordfix="true">There's also an open question of Why Nunjucks? I'm not the biggest fan of Nunjucks, outside of the Eleventy community that seems to be heavily invested into it, not many people seem to be using it. Documentation is (as we've already seen) sorta iffy and its relatively low adoption makes it harder to get questions answered.</p>
<p>I also haven't quite gotten syntax highlighting to work for <code>njk</code> files in VS Code, which is <em>very</em> frustrating and often turns me off from using something.</p>
<p data-wordfix="true">I could, at this point, switch to Mustache, which I'm <a href="https://glitch.com/edit/#!/thespin?path=server.js" target="_blank">already pretty familiar</a> with. Mustache also has the advantage of having template tags that are more similar to Jekyll and more familiar to Javascript users. But, unless I hit a real bad obstacle I don't think I will, for two reasons. First, the point of this is to learn something new! Second, when I last tried Eleventy to basically generate a few quick pages from a common template, it had terrible trouble rendering with Mustache, even with the instructions from their site. I've got other things to complicate first, can save that for later. If I get everything working, I might come back to this issue.</p>
<h3 id="build-process" tabindex="-1">Build Process</h3>
<p>Ok, <a href="https://marketplace.visualstudio.com/items?itemName=ronnidc.nunjucks" target="_blank">got Nunjucks syntax highlighting to properly work</a> for now!</p>
<p>Stepping back it looks like the rendered site in the <code>docs</code> folder is generally looking ok. There's one issue, my passthrough of assets includes an <code>assets/css</code> folder with an entirely useless sass file that would be public-facing. So I'm going to have to do subdirectories of assets instead. Should be easy enough.</p>
<p>Huh... it doesn't clean up the now defunct <code>css</code> folder. Is there a build tool to clean things up?</p>
<p><a href="https://github.com/11ty/eleventy/issues/19" target="_blank">Looks like it doesn't ship with 11ty</a>. But there <a href="https://github.com/11ty/eleventy/issues/744" target="_blank">are other solutions that people have done</a>.</p>
<p>I like <a href="https://github.com/11ty/eleventy/issues/744#issuecomment-800323968" target="_blank">the solution that defines the site configuration earlier</a>, it seems generally useful. I'll give it a try.</p>
<p>That works! Deleting the whole folder and building it all new seems super inefficient, but there doesn't seem to be another way to handle things.</p>
<h3 id="eleventy-build-and-serve" tabindex="-1">Eleventy Build and Serve</h3>
<p data-wordfix="true">One other throught now occurs. I saw that the dinky template uses some sort of build version number passed by github on build to cachebreak. I'm not sure how that works or if it can work the same way for Eleventy. Perhaps I need to pass a datetime stamp for each build instead? Something to figure out later.</p>
<p data-wordfix="true">[ ] How do I cachebreak files on the basis of new build events? Datetime? <code>site.github.build_revision</code> is how Jekyll accomplishes this, but is there a way to push that into the build process for Eleventy?</p>
<p><a target="_blank" href="https://github.com/AramZS/devblog/commit/27dbbaf47799a901a62857a34742d12418edc0cc" class="git-commit-link"><code>git commit -am &quot;Self-cleaning builds&quot;</code></a></p>
<p data-wordfix="true">Eleventy build is now stable enough that I might be able to develop with <code>npx @11ty/eleventy --serve</code> and check in on it. Let's see what it looks like.</p>
<p>Gotta adjust my CSS output path to match the template file's.</p>
<p>Ok, content is rendering as escaped HTML. That's not right at all.</p>
<p>Ahhh, apparently (here we are at poorly documented Nunjucks again...) my content tag needs to be <code>{{ content | safe }}</code>.</p>
<p>Ok, it's working now! Good signs! Hmmm. I was hoping that 1-space empty brackets would be rendered as a checkbox, as in Github-flavored markdown. But apparently not. How difficult would that be to fix?</p>
<p>Hmmm also some other problems:</p>
<p>[ ] Make link text look less shitty. It looks like it is a whole, lighter, font.<br />
[ ] Code blocks do not have good syntax highlighting. I want good syntax highlighting.</p>
<h3 id="sass-and-syntax-highlighting" tabindex="-1">Sass and Syntax Highlighting</h3>
<p>I <a href="https://github.com/AramZS/aramzs.github.io/blob/master/_sass/_syntax-highlighting.scss" target="_blank">have syntax highlighting styles</a> I like on my Github user Pages site. Let's just reuse it.</p>
<p data-wordfix="true">Huh... why doesn't the plugin for building Sass re-trigger on watch? <a href="https://www.11ty.dev/docs/events/#beforewatch" target="_blank">Looks like there's a way to fix that</a>.</p>
<p>Ugh... apparently the Sass syntax has changed significantly since the last time I used it and also since it was set up in my other site. I'll need to correct.</p>
<p><em>sigh</em></p>
<p>Ok <a href="https://stackoverflow.com/questions/56858150/i-am-gettiing-an-error-expected-new-line-while-compiling-sass" target="_blank">it's changed a lot</a>. And the Sass build tools are dickishly specific about spaces over tabs. Need to add a new section to my <code>.editorconfig</code>.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-3/#code-skip-hello-day-3-5" id="skip-to-code-skip-hello-day-3-5" class="skip-link">Skip code block ▼</a></p>
<pre><code>
[*.sass]
indent_style = space

</code></pre>
<p id="code-skip-hello-day-3-5">Ok, I tried building the extendable <a href="https://sass-lang.com/documentation/style-rules/placeholder-selectors" target="_blank">placeholder</a> into a standalone Sass file and a standalone Scss file and <a href="https://sass-lang.com/documentation/at-rules/extend#placeholder-selectors" target="_blank">it looks right</a>. But <code>@extend %vertical-rhythm</code> still isn't working.</p>
<p>My ordering looks correct!</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-3/#code-skip-hello-day-3-4" id="skip-to-code-skip-hello-day-3-4" class="skip-link">Skip code block ▼</a></p>
<pre class="language-sass"><code class="language-sass"><span class="token atrule-line"><span class="token atrule">@use</span> '_sass/base-syntax-highlighting'</span><br /><span class="token atrule-line"><span class="token atrule">@use</span> '_sass/syntax-highlighting'</span></code></pre>
<p id="code-skip-hello-day-3-4">What's going on?</p>
<p>First error is a depreciation error. It <em>shouldn't</em> be a problem, but let's just get rid of it.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-3/#code-skip-hello-day-3-3" id="skip-to-code-skip-hello-day-3-3" class="skip-link">Skip code block ▼</a></p>
<pre class="language-bash"><code class="language-bash">DEPRECATION WARNING: Using / <span class="token keyword">for</span> division is deprecated and will be removed <span class="token keyword">in</span> Dart Sass <span class="token number">2.0</span>.0.<br /><br />Recommendation: math.div<span class="token punctuation">(</span><span class="token variable">$spacing</span>-unit, <span class="token number">2</span><span class="token punctuation">)</span><br /><br />More info and automated migrator: https://sass-lang.com/d/slash-div</code></pre>
<p id="code-skip-hello-day-3-3">Alrighty. <a href="https://sass-lang.com/documentation/breaking-changes/slash-div" target="_blank">Go to the docs and do what it says</a>. Side comment... this is dumb. Why is it <em>easier</em> to do this type of math with standard CSS (where it would be <code>calc()</code>) than it is with Sass. Why is Sass harder to use now than it was when I got deep into it years ago? Grrrrr.</p>
<p>OMG why does this documentation start off with <code>// Future Sass, doesn't work yet!</code>?!?! Why would you start off a documentation file with a suggested solution that <strong>doesn't work</strong>?!</p>
<p>Ok. Down to one error. Still not importing the placeholder, why not?</p>
<p>Oh no. This is <a href="https://github.com/sass/dart-sass/issues/1042#issuecomment-656338728" target="_blank">A Problem</a>. Apparently the move to @use has not synced well with the old ways of using mixins, imports and placeholders?</p>
<p>The answer seems to be that you can't have a master file import a variables and expect them to be picked up by downstream files <code>@use</code>ed by that master file, instead you have to import them directly into the file you inted to use? I could have sworn that worked differently before? That isn't how it seems to work in my Jekyll site, perhaps there is a better way to do this?</p>
<p>[ ] Why is the logic around <code>@use</code> not working how I expect it to? Is there a better way?</p>
<p>Ok, I'm... not sure the styles are applying. Let's replicate a markdown block from my other site and see if it looks good.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-3/#code-skip-hello-day-3-2" id="skip-to-code-skip-hello-day-3-2" class="skip-link">Skip code block ▼</a></p>
<pre class="language-markdown"><code class="language-markdown"><span class="token frontmatter"><span class="token punctuation">---</span><br /><span class="token key atrule">layout</span><span class="token punctuation">:</span> page<br /><span class="token punctuation">---</span></span></code></pre>
<p id="code-skip-hello-day-3-2">It doesn't look good, but looking at the HTML markup... it looks like the problem is 11ty's processing and output of the actual markup.</p>
<p>:/</p>
<p>What does Jekyll use?</p>
<blockquote>
<p>Confusingly, GitHub Pages renders Markdown differently than GitHub does. GitHub uses its own Markdown processor; GitHub Pages uses jekyll-commonmark.</p>
</blockquote>
<p>lol <a href="https://www.markdownguide.org/tools/github-pages/" target="_blank">thanks</a>.</p>
<p data-wordfix="true">Looks like <a href="https://www.npmjs.com/package/markdown-it" target="_blank">Markdown-It</a> is <a href="https://www.11ty.dev/docs/languages/markdown/" target="_blank">a popular choice</a> on Eleventy to switch to commonmark.</p>
<p>Oh no, <a href="https://www.npmjs.com/package/markdown-it#syntax-highlighting" target="_blank">it doesn't ship with syntax highlighting</a>.</p>
<p data-wordfix="true">Ok, <code>highlight.js</code> is still not applying good tags. Is it an Eleventy issue, or is it that I need to use Pygments, which is apparently the code syntax highlighting engine that Github Pages uses? Ok, how does that work in Node? There <a href="https://www.npmjs.com/package/pygments" target="_blank">is a package, let's read up</a>!</p>
<p>I am concerned that it hasn't been update in 5 years. You know what? let's try <a href="https://highlightjs.org/" target="_blank">https://highlightjs.org/</a> and see if I can force it to build better styles.</p>
<p>Oh no... white text on bright red background. This is a bad sign.</p>
<p>Ok, this looks like it actually should work ok though, what is going on? I'm going to add some <code>console.log</code> statements.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-3/#code-skip-hello-day-3-1" id="skip-to-code-skip-hello-day-3-1" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript">	<span class="token keyword">let</span> options <span class="token operator">=</span> <span class="token punctuation">{</span><br />		<span class="token literal-property property">html</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span><br />		<span class="token literal-property property">breaks</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span><br />		<span class="token literal-property property">linkify</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span><br />		<span class="token literal-property property">langPrefix</span><span class="token operator">:</span> <span class="token string">"language-"</span><span class="token punctuation">,</span><br />		<span class="token function-variable function">highlight</span><span class="token operator">:</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">str<span class="token punctuation">,</span> lang</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />			<span class="token keyword">if</span> <span class="token punctuation">(</span>lang <span class="token operator">&amp;&amp;</span> hljs<span class="token punctuation">.</span><span class="token function">getLanguage</span><span class="token punctuation">(</span>lang<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br />				<span class="token keyword">try</span> <span class="token punctuation">{</span><br />					console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">"Syntax highlight good"</span><span class="token punctuation">,</span> lang<span class="token punctuation">)</span><span class="token punctuation">;</span><br />					<span class="token keyword">return</span> hljs<span class="token punctuation">.</span><span class="token function">highlight</span><span class="token punctuation">(</span>lang<span class="token punctuation">,</span> str<span class="token punctuation">)</span><span class="token punctuation">.</span>value<span class="token punctuation">;</span><br />				<span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span>__<span class="token punctuation">)</span> <span class="token punctuation">{</span><br />					console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">"Syntax highlight fail"</span><span class="token punctuation">,</span> lang<span class="token punctuation">)</span><span class="token punctuation">;</span><br />				<span class="token punctuation">}</span><br />			<span class="token punctuation">}</span><br /><br />			<span class="token keyword">return</span> <span class="token string">""</span><span class="token punctuation">;</span> <span class="token comment">// use external default escaping</span><br />		<span class="token punctuation">}</span><span class="token punctuation">,</span><br />	<span class="token punctuation">}</span><span class="token punctuation">;</span><br />	eleventyConfig<span class="token punctuation">.</span><span class="token function">setLibrary</span><span class="token punctuation">(</span><span class="token string">"md"</span><span class="token punctuation">,</span> <span class="token function">markdownIt</span><span class="token punctuation">(</span>options<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />	eleventyConfig<span class="token punctuation">.</span><span class="token function">setLibrary</span><span class="token punctuation">(</span><span class="token string">"markdown"</span><span class="token punctuation">,</span> <span class="token function">markdownIt</span><span class="token punctuation">(</span>options<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p id="code-skip-hello-day-3-1">Ok, they aren't triggering. No logging, this isn't working.</p>
<p>The eleventy website has good syntax highlighting. <a href="https://github.com/11ty/11ty-website/blob/master/.eleventy.js" target="_blank">How are they doing it</a>?</p>
<p>Ok, there's a lot going on there and I need a break. Break time.</p>
<p><a target="_blank" href="https://github.com/AramZS/devblog/commit/619a3292f27005d85a771d304bad09aafd858d88" class="git-commit-link"><code>git commit -am &quot;Trying to get better syntax highlighting&quot; </code></a></p>
]]></content:encoded>
	</item>
	
	<item>
		<title>Hello World Devblog - Day 2</title>
		<link>https://fightwithtools.dev/posts/projects/devblog/hello-day-2/?source=rss</link>
		<pubDate>Mon, 14 Jun 2021 03:59:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/projects/devblog/hello-day-2/</guid>
		<description>Part 2 of setting up 11ty dev blog.</description>
		<content:encoded><![CDATA[<h2 id="day-2" tabindex="-1">Day 2</h2>
<p>Ok, day 2. Let's restate the requirements and todos!</p>
<h3 id="project-scope-and-todos" tabindex="-1">Project Scope and ToDos</h3>
<ol>
<li>Static Site Generator that can build the blog and let me host it on Github Pages</li>
<li>I want to write posts in Markdown because I'm lazy, it's easy, and it is how I take notes now.</li>
<li>I don't want to spend a ton of time doing design work. I'm doing complicated designs for other projects, so I want to pull a theme I like that I can rely on someone else to keep up.</li>
<li>Once it gets going, I want template changes to be easy.</li>
<li>It should be as easy as Jekyll, so I need to be able to build it using GitHub Actions, where I can just commit a template change or Markdown file and away it goes. If I can't figure this out than fk it, just use Jekyll.</li>
<li>I require it to be used by a significant percent of my professional peers so I can get easy answers when something goes wrong.</li>
<li>I want source maps. This is a dev log site which means whatever I do with it should be easy for other developers to read.</li>
</ol>
<p>[ ] Also <a href="https://www.npmjs.com/package/@quasibit/eleventy-plugin-sitemap" target="_blank">the sitemap plugin</a> looks cool. Should grab that later.</p>
<p>[ ] So does the <a href="https://www.npmjs.com/package/eleventy-plugin-reading-time" target="_blank">reading time one</a>.</p>
<p>[ ] Also <a href="https://github.com/jdsteinbach/eleventy-plugin-toc/blob/master/src/BuildTOC.js" target="_blank">this TOC plugin</a> mby?</p>
<p data-wordfix="true">[ ] Use <a href="https://www.11ty.dev/docs/data-deep-merge/" target="_blank">Data Deep Merge</a> in this blog.</p>
<p>[ ] Decide if I want to render the CSS fancier than just a base file.</p>
<p>[ ] Can I use the template inside of dinky that already exists instead of copy/pasting it?</p>
<h2 id="setting-up-layouts-folder" tabindex="-1">Setting up Layouts folder</h2>
<p data-wordfix="true">Ok, so why isn't it picking up the layout from either <code>_layouts/post.njk</code> or <code>_layouts/default.njk</code>? Maybe I need to define a default <a href="https://www.11ty.dev/docs/data-template-dir/" target="_blank">at the data level</a>? Or do I need to move it to <code>src</code> even if I define the location in the returned configuration?</p>
<p data-wordfix="true">Moving it into <code>src</code> doesn't seem to do anything. But it looks like all the files I configure into Eleventy in the returned object do need to be in there, so apparently I can't set a default layout in the <code>data</code> folder?</p>
<p>Adding a template to <code>src/posts/posts.json</code></p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-2/#code-skip-hello-day-2-4" id="skip-to-code-skip-hello-day-2-4" class="skip-link">Skip code block ▼</a></p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span> <span class="token property">"layout"</span><span class="token operator">:</span> <span class="token string">"layouts/post.njk"</span> <span class="token punctuation">}</span></code></pre>
<p id="code-skip-hello-day-2-4">Ok, yay, an error!</p>
<p><code>Error You’re trying to use a layout that does not exist layouts/post.njk (undefined)</code></p>
<p>Because I defined a path to layouts in the config, I don't need to include it?</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-2/#code-skip-hello-day-2-3" id="skip-to-code-skip-hello-day-2-3" class="skip-link">Skip code block ▼</a></p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span> <span class="token property">"layout"</span><span class="token operator">:</span> <span class="token string">"post.njk"</span> <span class="token punctuation">}</span></code></pre>
<p id="code-skip-hello-day-2-3">Yup, now I have an error in the template!</p>
<p>Ok, looks like I can't use this structure:</p>
<p><code>{{ site.lang | default: &quot;en-US&quot; }}&quot;</code></p>
<p data-wordfix="true">So, default values, how should I do them? It <a href="https://www.11ty.dev/docs/data-cascade/" target="_blank">looks like</a> the answer is to define it as <a href="https://www.11ty.dev/docs/data-global/" target="_blank">a data global</a>. Ok let's try it, place the default in <code>src/_data/site.json</code>.</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-2/#code-skip-hello-day-2-2" id="skip-to-code-skip-hello-day-2-2" class="skip-link">Skip code block ▼</a></p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span><br />	<span class="token property">"lang"</span><span class="token operator">:</span> <span class="token string">"en-US"</span><br /><span class="token punctuation">}</span></code></pre>
<p id="code-skip-hello-day-2-2">Huh... render error on <em>this</em> file:</p>
<p><code>TemplateContentRenderError ... expected variable end</code></p>
<p>Going to remove <code>{% seo %}</code> from the template. I assume it is a template fragment without looking it up but I'm not prepared to figure it out. Still no solve. Good time to commit!</p>
<p><a target="_blank" href="https://github.com/AramZS/devblog/commit/909100be8205f3ea7d7fd6094a823d9a1252d646" class="git-commit-link"><code>git commit -am &quot;Template still not working but getting closer&quot;</code></a></p>
<p data-wordfix="true">Ok, let's start stripping out stuff from the template. The error indicates the problem is in my markdown, but that doesn't make sense, so simpler template. Ok, first, I want the dinky assets folder so it works properly in the template. There are <a href="https://www.11ty.dev/docs/copy/#change-the-output-directory" target="_blank">more ways to configure the passthrough rules</a> to make this work for me.</p>
<p><code>eleventyConfig.addPassthroughCopy({ &quot;dinky/assets&quot;: &quot;assets&quot; });</code></p>
<p>Ok, passthrough works! But the template still won't render. The error is still in my markdown! At <code>[Line 49, Column 67]</code>. What is going on?! That line is empty, it doesn't have columns.</p>
<p>Wait... the line number is likely being calculated after the metadata is removed from the head of the <code>md</code> file. Ok... my metadata takes up 10 lines so it is really line <em>59</em>. Oh! It's a code sample <em>from</em> the template. It's trying to render an njk variable from the markdown file?! That's very dumb.</p>
<p>To Google! &quot;njk picking up code sample of njk code&quot; &gt; <a href="https://github.com/11ty/eleventy/issues/791" target="_blank">result</a>.</p>
<p>Raw tag huh? How does that work exactly? Oh... like <a href="https://github.com/11ty/11ty-website/blob/master/src/docs/languages/nunjucks.md" target="_blank">this</a>.</p>
<p>Ok, works both for blocks and inline, good!</p>
<p>Ok, defaults for posts <em>have</em> to be in the <code>posts</code> folder's <code>posts.json</code>. I cannot seem to set any defaults for posts in the <code>_data</code> folder. Or at least I haven't figured out how. But ok, things are rendering now in the right template. Also the assets are being passed out of the <code>dinky</code> submodule! This is good. The process works, so now I can start to build in my weirdness.</p>
<p>I still really want to figure out the defaults thing first. How do I make this work?</p>
<p>Ok, <a href="https://github.com/11ty/eleventy/issues/380#issuecomment-568033456" target="_blank">here we go</a>.</p>
<p>So to get a default <code>description</code> value in my template I can set it up with a file at <code>src/_data/description.js</code> and have the content of that file be <code>module.exports = &quot;Talking about code&quot;;</code>. Ok, that works!</p>
<p data-wordfix="true">Yay, Eleventy defaults work now! Good place to commit.</p>
<p><a target="_blank" href="https://github.com/AramZS/devblog/commit/2b51f07a382a3c0311810197e50b603eff45b5be" class="git-commit-link"><code>git commit -am &quot;Ok, renders and defaults are working now&quot;</code></a></p>
<h3 id="sass-figuring-out-_rendersync" tabindex="-1">Sass - figuring out _renderSync</h3>
<p>Hmmm... ok I guess that I picked a bad example plugin, because the one I used <a href="https://www.npmjs.com/package/eleventy-plugin-meta-generator#usage" target="_blank">doesn't have a typical footprint</a>. Well, I'm not going to have a typical footprint I guess. Let's start without that. It runs sync, so I can just call the function during setup mby? Just add <code>sassBuild();</code> to the inside of my .eleventy.js function inside of <code>module.exports = function (eleventyConfig) {</code>?</p>
<p>Ok... renderSync from <code>dart-sass</code> threw an error:</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-2/#code-skip-hello-day-2-1" id="skip-to-code-skip-hello-day-2-1" class="skip-link">Skip code block ▼</a></p>
<pre class="language-bash"><code class="language-bash">Receiver: Closure <span class="token string">'_renderSync'</span><br />Arguments: <span class="token punctuation">[</span>Instance of <span class="token string">'PlainJavaScriptObject'</span>, Instance of <span class="token string">'JavaScriptFunction'</span><span class="token punctuation">]</span><br /><br />`` was thrown:<br />    NoSuchMethodError: method not found: <span class="token string">'call'</span></code></pre>
<p id="code-skip-hello-day-2-1">Lol <a href="https://github.com/sass/dart-sass/issues/23#issuecomment-259011350" target="_blank">documentation error in dart-sass</a> apparently. Don't pass two functions, because that's an async pattern, instead return the result.</p>
<p>Cool. New error!</p>
<p><code>Invalid argument(s): Either options.data or options.file must be set.</code></p>
<p>Can I not use multiple files? I guess I need a single file that calls the others <a href="https://sass-lang.com/documentation/at-rules/use" target="_blank">using @use</a>. Last time I used Sass it was @import, but according to docs, that method is out now. Good to know!</p>
<p data-wordfix="true">Oh, gotta remember paths are relative to execution, so I have to set up paths in both the Sass plugin AND the <code>@use</code> relative to the base of the project, where I'm executing the Eleventy build process.</p>
<p>Still no css file.</p>
<p>Oh, <a href="https://sass-lang.com/documentation/js-api#outfile" target="_blank">lol</a></p>
<blockquote>
<p>Despite the name, Sass does not write the CSS output to this file. The caller must do that themselves.</p>
</blockquote>
<p>Ok, gotta do that.</p>
<h3 id="writing-out-the-sass-file" tabindex="-1">Writing out the Sass file</h3>
<p>Ok, I want to use <code>fs</code> to write the resulting file into <code>docs/styles/styles.css</code>. Only, the <code>styles</code> directory does not predictably exist so <code>fs</code> fails because I have to make that folder. Of course, forgot. Easy enough.</p>
<p>Ok, it works! This is a good place to stop because it is almost midnight.</p>
<p><a target="_blank" href="https://github.com/AramZS/devblog/commit/f4a1307dcf0fbe5dcc03b2ae4d2be737177c3276" class="git-commit-link"><code>git commit -am &quot;Compile that sass&quot;</code></a></p>
<p>And this is pretty far along, huh? Time to push it to Github.</p>
]]></content:encoded>
	</item>
	
	<item>
		<title>Hello World - A Dev Blog</title>
		<link>https://fightwithtools.dev/posts/projects/devblog/hello-day-1/?source=rss</link>
		<pubDate>Sun, 13 Jun 2021 03:59:43 GMT</pubDate>
		<dc:creator>Aram Zucker-Scharff</dc:creator>
		<guid isPermaLink="true">https://fightwithtools.dev/posts/projects/devblog/hello-day-1/</guid>
		<description>Building this very blog for my development notes, using Eleventy.</description>
		<content:encoded><![CDATA[<h2 id="day-1" tabindex="-1">Day 1</h2>
<p>I have decided I want a blog to write down some of my decisions as I build various public projects. So, inital requirements:</p>
<ol>
<li>Static Site Generator that can build the blog and let me host it on Github Pages</li>
<li>I want to write posts in Markdown because I'm lazy, it's easy, and it is how I take notes now.</li>
<li>I don't want to spend a ton of time doing design work. I'm doing complicated designs for other projects, so I want to pull a theme I like that I can rely on someone else to keep up.</li>
<li>Once it gets going, I want template changes to be easy.</li>
<li>It should be as easy as Jekyll, so I need to be able to build it using GitHub Actions, where I can just commit a template change or Markdown file and away it goes. If I can't figure this out than fk it, just use Jekyll.</li>
</ol>
<p data-wordfix="true">So, after being completly put off by the Hugo quickstart page, I decided to go to Eleventy. I'd been using Eleventy for a very basic build process on another project, so I wanted to see what it would be like for a more complex blog. Everyone I know seems to love Eleventy so if I complain about it on Twitter someone will likely give me an answer. This is a requirement I only just realized:</p>
<ol start="6">
<li>I require it to be used by a significant percent of my professional peers so I can get easy answers when something goes wrong.</li>
</ol>
<p data-wordfix="true">Ok. Eleventy it is.</p>
<p>Ok, first things first. New folder. <code>git init</code>.</p>
<p>Oh, it starts new projects with the <code>master</code> branch? I don't like that, I like using <code>main</code>. I can checkout main and delete master right?</p>
<p>Huh... if you don't have anything committed to any branch and you checkout a new branch the <code>master</code> branch ceases to exist. Cool. I guess I don't need to do <a href="https://www.git-tower.com/learn/git/faq/git-rename-master-to-main/" target="_blank">this</a>.</p>
<p data-wordfix="true">Wait... does Eleventy work with GitHub Actions to build? I have no idea. <a href="https://www.linkedin.com/pulse/eleventy-github-pages-lea-tortay/" target="_blank">Looks like yes</a>... let's move forward.</p>
<p><code>npm init -y</code></p>
<p><code>npm install --save-dev @11ty/eleventy</code></p>
<p data-wordfix="true">Here we go with Eleventy! Only...</p>
<p data-wordfix="true">All the pre-built... ughhh &quot;Themes&quot; or &quot;Starters&quot; (I can't say template here, because searching for &quot;Eleventy templates&quot;, while a logical thing to do, just gives me a ton of pages about using Nunjucks) suck. They all suck hardcore. I mean, they're all single page sites with no clear navigation or nav bar and look barely worked out beyond the Bootstrap Starter Template phase. I can't stand any of them. Is there a secret location for good Eleventy themes or is it just that the type of folks most likely to use Eleventy lack design skills?</p>
<p>But... I really like the Jekyll dinky theme. All I really need is the CSS and I can pull a copy of its template into whatever. Easy enough in theory (never in practice).</p>
<p>I'm going to pull it in as a submodule. I forgot how to do submodules. <a href="https://github.blog/2016-02-01-working-with-submodules/" target="_blank">Here we go</a>.</p>
<p><code>git submodule add git@github.com:pages-themes/dinky.git</code></p>
<p><code>git submodule update --init --recursive</code></p>
<p>Alright, what have we got here.</p>
<p>Sass. We've got Sass. That's going to need to be figured out.</p>
<p data-wordfix="true">Let's go to the Eleventy plugins and see what, if anything, can help me here.</p>
<p>Oh and let's grab some cool looking ones.</p>
<p><code>npm install @11ty/eleventy-img</code></p>
<p>Huh, some funkyness on the install... because I forgot that, for various complicated reasons, my Node install defaults to 8.*.</p>
<p>Ok. Create the <code>.nvmrc</code> file and what's the latest version of node these days? Put <code>16</code> in it.</p>
<p>Reboot my console so I take advantage of <a href="https://gist.github.com/AramZS/fda9c04a38908789dccdf78bb94e2b45" target="_blank">the nifty nvm auto-load ZSH script</a>.</p>
<p>Dump package-lock, dump node_modules, <code>npm install</code> again.</p>
<p>Plugin install works now.</p>
<p><code>npm install @11ty/eleventy-plugin-syntaxhighlight --save-dev</code><br />
<code>npm install @11ty/eleventy-navigation --save-dev</code><br />
<code>npm install @11ty/eleventy-plugin-rss --save-dev</code></p>
<p><code>npm install eleventy-plugin-sass --save </code></p>
<p data-wordfix="true">Ok, that didn't work. And the whole point of looking at plugins was a SASS processor integrated into the Eleventy build process. Not great. What's wrong?</p>
<p>Looks like something with <code>node-gyp</code>. Frequently a problem.</p>
<p>Let's check <code>node-gyp</code>.</p>
<p>Ok, a whole thing for problems from an upgrade.</p>
<p>Let's do all of <a href="https://github.com/nodejs/node-gyp/blob/master/macOS_Catalina.md" target="_blank">that</a>. XCode needed an update and for some reason updating to Catalina also wiped out my XCode CLI tools... didn't realize that. Reinstall those:</p>
<p><code>xcode-select --install</code></p>
<p>Ok, cool. Moving on...</p>
<p data-wordfix="true">Oh, I am looking at the configuration options for <code>gulp-sass</code> which get passed into the Eleventy plugin and looks like <code>gulp-sass</code> is depreciated. So this plugin is not one I want to use. And it looks like there isn't an up to date Sass plugin.</p>
<p>lol.</p>
<p data-wordfix="true">So, let's assume I'm going to have to write my own plugin. I know nothing about Eleventy plugins. Find a real basic one and use that as the template to start a new one.</p>
<p>This <a href="https://www.npmjs.com/package/eleventy-plugin-meta-generator" target="_blank">one</a> looks pretty simple! So I'm going to keep that tab open for reference as I build out a Sass processor.</p>
<p>[ ] Also <a href="https://www.npmjs.com/package/@quasibit/eleventy-plugin-sitemap" target="_blank">the sitemap plugin</a> looks cool. Should grab that later.</p>
<p>[ ] So does the <a href="https://www.npmjs.com/package/eleventy-plugin-reading-time" target="_blank">reading time one</a>.</p>
<p>I also saw <a href="https://www.npmjs.com/package/eleventy-load" target="_blank">a Loader plugin</a>... but it looks way more complicated than I need while also <em>not doing what I need</em>, so mark it, move on. Might have something in its code that's useful for later.</p>
<p>[ ] Also <a href="https://github.com/jdsteinbach/eleventy-plugin-toc/blob/master/src/BuildTOC.js" target="_blank">this TOC plugin</a> mby?</p>
<p>Ok, back to Sass. Now, I don't want to fk around with building a whole NPM module for this right now, so let's start with the plugin internal to the project.</p>
<p>There does not seem to be a standard pattern for these like there is for layouts, data, etc... so I'm going to imitate the <code>_{thing}</code> pattern and make a <code>_custom-plugins</code> folder. Maybe someday someone will read this and tell me this is a dumb pattern. Put it in there. Node module structure, <code>index.js</code> at the base, <code>src</code> folder with the files that actually do stuff.</p>
<p>Ok let's get Sass in here. I want the Javascript library, so read through docs <a href="https://sass-lang.com/dart-sass" target="_blank">at their site</a>.</p>
<p><code>npm install sass --save-dev</code><br />
<code>npm install fiber --save-dev</code></p>
<p>That 2nd one didn't work... cool, what is Fiber... let's <a href="https://github.com/laverdet/node-fibers" target="_blank">read about it</a>.</p>
<blockquote>
<p>Update [April 13th, 2021] -- Fibers is not compatible with nodejs v16.0.0 or later. Unfortunately, v8 commit dacc2fee0f is a breaking change and workarounds are non-trivial.</p>
</blockquote>
<p><em>sigh</em></p>
<p>Ok, using latest version of Node, clearly a bad choice.</p>
<p><code>.nvmrc</code> changed to <code>15</code>. I like 15, I've used 15 for other stuff. Hopefully no problem.</p>
<p data-wordfix="true">You know... reading node-fiber's documentation... I... don't actually need it anyway. I want <code>renderSync</code>, to block the build process of Eleventy until the right assets are done.</p>
<p>Whatever... never use latest Node... it always causes problems. I have encountered this time and time again. Clear out package-lock and node_modules.</p>
<p><code>npm install</code></p>
<p>Ok at this point my process has already become more muddled then I'm comfortable with. Better start documenting it actually. Oh wait, this is a dev blog, I should start documenting it AS A BLOG POST.</p>
<p data-wordfix="true">I forgot the pattern for Eleventy posts' folders in a project. <a href="https://github.com/11ty/eleventy-base-blog/tree/master/posts" target="_blank">Here it is</a>.</p>
<p>Started this file.</p>
<p data-wordfix="true">Forgot the number of dashes for the metadata format for markdown that Eleventy likes because it is not 8:30pm and I have not yet had dinner. I was reading about some feature that mentioned it in the context of merging data from templates with markdown files, I should likely note that.</p>
<p data-wordfix="true">[ ] Use <a href="https://www.11ty.dev/docs/data-deep-merge/" target="_blank">Data Deep Merge</a> in this blog.</p>
<p>Ok now:</p>
<p>[x] Write everything down that I've done to this point before it zeroes out of my head.</p>
<p>God bless CLI and browser history.</p>
<p>Ok, back to the Sass plugin. And also: this would be a good time to do a commit huh?</p>
<p data-wordfix="true"><a target="_blank" href="https://github.com/AramZS/devblog/commit/ad3eb51eb8d2aea5f20a18793054d7831966920f" class="git-commit-link"><code>git commit -am &quot;a real 11ty blog... I don't know wtf I'm doing to make this work yet&quot;</code></a></p>
<p>Ok, <code>dart-sass</code>. I don't know what any of these listed options are...</p>
<p>Annoying, since they are emulating the <code>node-sass</code> API, it's just a link to the <code>node-sass</code> README documentation. Ok, taking a look.</p>
<ol start="7">
<li>I want source maps. This is a dev log site which means whatever I do with it should be easy for other developers to read.</li>
</ol>
<p>I also would like to have smart CSS, where it only loads the CSS files it needs for a template, so we'd have a main CSS file and then per-template CSS files? That would be cool. Or maybe <a href="https://github.com/addyosmani/critical#usage" target="_blank">this thing</a>? You know what... table that... let's just render the damn CSS first.</p>
<p>[ ] Decide if I want to render the CSS fancier than just a base file.</p>
<p data-wordfix="true">Huh... a thought... can I just run any arbitrary function in Eleventy as part of the build?</p>
<p data-wordfix="true"><a href="https://www.11ty.dev/docs/data-js/" target="_blank">Looks like</a> the <code>_data</code> folder can contain functions that output arbitrary files?</p>
<p>Should I do that? I mean... I likely could... but it isn't elegant, it isn't the <em>right</em> way. Skip it.</p>
<p data-wordfix="true">Ok, set it up with the most basic Sass build rules. Let's hold there, I'm going to want to try it out, but first, let's make sure the normal Eleventy build works.</p>
<p>Ok, to do that I need a layout in place. Get it in <a href="https://github.com/11ty/eleventy-base-blog/tree/master/_includes/layouts" target="_blank">the right place</a>.</p>
<p data-wordfix="true">To make sure my CSS works properly, I should probably set up the dinky layout here. <code>dinky/_layouts</code>. Ok... only one file, easy enough. And the template syntax looks basically identical. Copy it and paste it into the <code>_includes/layouts</code> folder and rename it to <code>default.njk</code>.</p>
<p data-wordfix="true">NOTE: I'm pretty sure that Nunjucks can process HTML files. Do I want to just add a Eleventy alias to just pull default.html from dinky in the style of <code>eleventyConfig.addLayoutAlias(&quot;base&quot;, &quot;dinky/_layouts/default.html&quot;);</code>? Would that work? Put a pin in that:</p>
<p>[ ] Can I use the template inside of dinky that already exists instead of copy/pasting it?</p>
<p>Pull the .eleventy.js return from the <a href="https://github.com/11ty/eleventy-base-blog/blob/master/.eleventy.js" target="_blank">base blog</a> and change output to <code>docs</code> for Github Pages...</p>
<p class="skip-link-graf">
<a href="https://fightwithtools.dev/posts/projects/devblog/hello-day-1/#code-skip-hello-day-1-1" id="skip-to-code-skip-hello-day-1-1" class="skip-link">Skip code block ▼</a></p>
<pre class="language-javascript"><code class="language-javascript">		<span class="token literal-property property">dir</span><span class="token operator">:</span> <span class="token punctuation">{</span><br />			<span class="token literal-property property">input</span><span class="token operator">:</span> <span class="token string">"."</span><span class="token punctuation">,</span><br />			<span class="token literal-property property">includes</span><span class="token operator">:</span> <span class="token string">"_includes"</span><span class="token punctuation">,</span><br />			<span class="token literal-property property">data</span><span class="token operator">:</span> <span class="token string">"_data"</span><span class="token punctuation">,</span><br />			<span class="token literal-property property">output</span><span class="token operator">:</span> <span class="token string">"docs"</span><span class="token punctuation">,</span><br />		<span class="token punctuation">}</span><span class="token punctuation">,</span></code></pre>
<p id="code-skip-hello-day-1-1">Wait... it's pulling njk files from the base of the project? Mixing project files with build configuration files? That's HOT NONSENSE. I did that last time, but it was becaause I wanted to build some real basic pages and only a few of them. Not good for a larger project IMO. Create an <code>src</code> folder.</p>
<p><code>input: &quot;src&quot;,</code></p>
<p>Crap... what of these folders do I need to move in? I guess <code>posts</code>? That is likely it. I'll find out later!</p>
<p>Ok, theoretically should be able to make a build. Moment of truth.</p>
<p><code>npx @11ty/eleventy</code></p>
<p>It did not pick up the template</p>
<p>Let's try altering the .eleventy.js returned data to include, and I'll move the folder accordingly:</p>
<p><code>layouts: &quot;_layouts&quot;,</code></p>
<p>Still didn't pick it up.</p>
<p>Ok, gotta play around, but good time to commit</p>
<p><a target="_blank" href="https://github.com/AramZS/devblog/commit/448f44a4e9e1ec604bee4665d56f12abf78cfe6a" class="git-commit-link"><code>git commit -am &quot;First render, didn't work&quot;</code></a></p>
<p>Time to take a break for dinner.</p>
]]></content:encoded>
	</item>
	</channel>
</rss>
