feat: add syntax highlighting and fix code alignment

This commit is contained in:
2025-12-10 11:46:41 -08:00
parent 07aa12a042
commit bbac528845
6 changed files with 117 additions and 32 deletions

View File

@@ -16,6 +16,7 @@
"react-dom": "^19.0.0",
"react-markdown": "9.0.3",
"reading-time": "1.5.0",
"rehype-highlight": "7.0.2",
"rehype-raw": "7.0.0",
"remark-gfm": "4.0.0"
},

54
pnpm-lock.yaml generated
View File

@@ -26,6 +26,9 @@ importers:
reading-time:
specifier: 1.5.0
version: 1.5.0
rehype-highlight:
specifier: 7.0.2
version: 7.0.2
rehype-raw:
specifier: 7.0.0
version: 7.0.0
@@ -1602,6 +1605,9 @@ packages:
hast-util-from-parse5@8.0.3:
resolution: {integrity: sha512-3kxEVkEKt0zvcZ3hCRYI8rqrgwtlIOFMWkbclACvjlDw8Li9S2hk/d51OI0nr/gIpdMHNepwgOKqZ/sy0Clpyg==}
hast-util-is-element@3.0.0:
resolution: {integrity: sha512-Val9mnv2IWpLbNPqc/pUem+a7Ipj2aHacCwgNfTiK0vJKl0LF+4Ba4+v1oPHFpf3bLYmreq0/l3Gud9S5OH42g==}
hast-util-parse-selector@4.0.0:
resolution: {integrity: sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A==}
@@ -1614,12 +1620,19 @@ packages:
hast-util-to-parse5@8.0.0:
resolution: {integrity: sha512-3KKrV5ZVI8if87DVSi1vDeByYrkGzg4mEfeu4alwgmmIeARiBLKCZS2uw5Gb6nU9x9Yufyj3iudm6i7nl52PFw==}
hast-util-to-text@4.0.2:
resolution: {integrity: sha512-KK6y/BN8lbaq654j7JgBydev7wuNMcID54lkRav1P0CaE1e47P72AWWPiGKXTJU271ooYzcvTAn/Zt0REnvc7A==}
hast-util-whitespace@3.0.0:
resolution: {integrity: sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==}
hastscript@9.0.1:
resolution: {integrity: sha512-g7df9rMFX/SPi34tyGCyUBREQoKkapwdY/T04Qn9TDWfHhAYt4/I0gMVirzK5wEzeUqIjEB+LXC/ypb7Aqno5w==}
highlight.js@11.11.1:
resolution: {integrity: sha512-Xwwo44whKBVCYoliBQwaPvtd/2tYFkRQtXDWj1nackaV2JPXx3L0+Jvd8/qCJ2p+ML0/XVkJ2q+Mr+UVdpJK5w==}
engines: {node: '>=12.0.0'}
hosted-git-info@2.8.9:
resolution: {integrity: sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==}
@@ -1896,6 +1909,9 @@ packages:
loupe@3.1.2:
resolution: {integrity: sha512-23I4pFZHmAemUnz8WZXbYRSKYj801VDaNv9ETuMh7IrMc7VuVVSo+Z9iLE3ni30+U48iDWfi30d3twAXBYmnCg==}
lowlight@3.3.0:
resolution: {integrity: sha512-0JNhgFoPvP6U6lE/UdVsSq99tn6DhjjpAj5MxG49ewd2mOBVtwWYIT8ClyABhq198aXXODMU6Ox8DrGy/CpTZQ==}
lru-cache@10.4.3:
resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==}
@@ -2374,6 +2390,9 @@ packages:
resolution: {integrity: sha512-qx+xQGZVsy55CH0a1hiVwHmqjLryfh7wQyF5HO07XJ9f7dQMY/gPQHhlyDkIzJKC+x2fUCpCcUODUUUFrm7SHA==}
hasBin: true
rehype-highlight@7.0.2:
resolution: {integrity: sha512-k158pK7wdC2qL3M5NcZROZ2tR/l7zOzjxXd5VGdcfIyoijjQqpHd3JKtYSBDpDZ38UI2WJWuFAtkMDxmx5kstA==}
rehype-raw@7.0.0:
resolution: {integrity: sha512-/aE8hCfKlQeA8LmyeyQvQF3eBiLRGNlfBJEvWH7ivp9sBqs7TNqBL5X3v157rM4IFETqDnIOO+z5M/biZbo9Ww==}
@@ -2751,6 +2770,9 @@ packages:
unified@11.0.5:
resolution: {integrity: sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==}
unist-util-find-after@5.0.0:
resolution: {integrity: sha512-amQa0Ep2m6hE2g72AugUItjbuM8X8cGQnFoHk0pGfrFeT9GZhzN5SW8nRsiGKK7Aif4CrACPENkA6P/Lw6fHGQ==}
unist-util-is@6.0.0:
resolution: {integrity: sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==}
@@ -4651,6 +4673,10 @@ snapshots:
vfile-location: 5.0.3
web-namespaces: 2.0.1
hast-util-is-element@3.0.0:
dependencies:
'@types/hast': 3.0.4
hast-util-parse-selector@4.0.0:
dependencies:
'@types/hast': 3.0.4
@@ -4701,6 +4727,13 @@ snapshots:
web-namespaces: 2.0.1
zwitch: 2.0.4
hast-util-to-text@4.0.2:
dependencies:
'@types/hast': 3.0.4
'@types/unist': 3.0.3
hast-util-is-element: 3.0.0
unist-util-find-after: 5.0.0
hast-util-whitespace@3.0.0:
dependencies:
'@types/hast': 3.0.4
@@ -4713,6 +4746,8 @@ snapshots:
property-information: 7.1.0
space-separated-tokens: 2.0.2
highlight.js@11.11.1: {}
hosted-git-info@2.8.9: {}
html-url-attributes@3.0.1: {}
@@ -4972,6 +5007,12 @@ snapshots:
loupe@3.1.2: {}
lowlight@3.3.0:
dependencies:
'@types/hast': 3.0.4
devlop: 1.1.0
highlight.js: 11.11.1
lru-cache@10.4.3: {}
magic-string@0.30.17:
@@ -5676,6 +5717,14 @@ snapshots:
dependencies:
jsesc: 0.5.0
rehype-highlight@7.0.2:
dependencies:
'@types/hast': 3.0.4
hast-util-to-text: 4.0.2
lowlight: 3.3.0
unist-util-visit: 5.0.0
vfile: 6.0.3
rehype-raw@7.0.0:
dependencies:
'@types/hast': 3.0.4
@@ -6179,6 +6228,11 @@ snapshots:
trough: 2.2.0
vfile: 6.0.3
unist-util-find-after@5.0.0:
dependencies:
'@types/unist': 3.0.3
unist-util-is: 6.0.0
unist-util-is@6.0.0:
dependencies:
'@types/unist': 3.0.3

View File

@@ -4,15 +4,17 @@ date: "2025-12-10"
summary: "A structured approach to programmatic problem solving."
---
If you have ever watched me help someone debug their code in a Discord server, you have probably noticed something: I almost never start by looking at their code. Instead, I ask them to explain their logic. What are they trying to accomplish? How do they think it should work?
If you've ever seen me help someone with their code, you may have noticed my unusual approach. I *never* have them start by looking at their code. Instead, I ask them to explain their logic. What are they trying to accomplish? How do they think it should work?
This is not because I am lazy or trying to make things difficult. It is because I have learned, through years of teaching and debugging, that **most coding problems are not actually coding problems - they are logic problems**.
## The Problem with Starting with Code
When you sit down at your keyboard and immediately start typing, you are trying to solve two problems at once: figuring out what you want to do, and figuring out how to express that in code. This is like trying to learn a new language while simultaneously trying to write a novel in it. You are juggling syntax and logic, and it is incredibly easy to drop one or both.
When you sit down at your keyboard and immediately start typing, you are trying to solve two problems at once. You are figuring out what you want to do, and figuring out how to make the computer do it.
Consider this scenario: you are trying to write a FizzBuzz algorithm. If you jump straight into code, you might write something like:
It's like trying to learn English by writing Shakespearian poetry. Sounds messy, right?
Let's say you are trying to write a FizzBuzz algorithm. If you start with code instead of logic, you might write something like...
```javascript
for (let i = 1; i <= 100; i++) {
@@ -26,13 +28,13 @@ for (let i = 1; i <= 100; i++) {
}
```
You have already hit a problem, and you have not even finished writing the code yet. But if you had worked out the logic first, you would have caught this issue before you ever touched your keyboard.
You have already hit a problem, and you haven't even finished writing the code yet! If you had worked out the logic *first*, instead of jumping right into code, you would have been able to identify this problem without mucking around with the syntax.
## The Algorithmic Thinking Approach
Instead of starting with code, start with plain English. Write out your instructions step-by-step, as if you were explaining to a very literal, very stupid toddler who will do exactly what you say and nothing more.
Instead of starting with code, start with plain language. Write out your instructions. Do so one step at a time, as if you were explaining to Naomi (who will do exactly what you say and nothing more).
Let us use FizzBuzz as an example. Here is how I would break it down:
Let's use FizzBuzz as an example. Here is how I would break it down:
1. First, I look at the number.
2. Is the number divisible by three?
@@ -124,7 +126,7 @@ xxxxxxx
xxxxxxxxx
```
But that is not a pyramid! A pyramid should be centered, like:
But that is not a pyramid! A pyramid should be centred, like:
```
x
@@ -134,7 +136,7 @@ But that is not a pyramid! A pyramid should be centered, like:
xxxxxxxxx
```
The instructions were missing a crucial detail: the spacing. But more importantly, they were not precise enough. "Add two more of the same single string beside it" - beside what? Where? The instructions assumed I would understand the intent, but a computer (or a very literal person following instructions) would not.
The instructions were missing a crucial detail: the spacing. But more importantly, they were imprecise. "Add two more of the same single string beside it" - beside what? Where? The instructions assumed I would understand the intent, but a computer (or a very literal Naomi following instructions) would not.
After several iterations, we refined the instructions to be precise:
@@ -163,9 +165,9 @@ Let us go back to the pyramid example. We have our logic:
Now we can think about the code structure:
- We need a loop to iterate through rows.
- For each row, we need to calculate spaces (which decrease as rows increase).
- For each row, we need to calculate characters (which increase as rows increase).
- We need to print the combination.
- For each row, we gotta know how many spaces to use. We use less spaces in each row.
- For each row, we gotta know how many characters to use. We use more characters in each row.
- Finally, print our result.
The code almost writes itself once the logic is clear:
@@ -179,11 +181,13 @@ function pyramid(characterToBuildPyramidWith, numOfRows) {
}
```
But notice: I did not write this code until I had worked through the logic step-by-step. I knew exactly what I needed to calculate and why, because I had already tested the logic manually.
But wait! Did you see? I did not write this code until I had worked through the logic entirely by hand. I knew exactly what I wanted my program to do! All I had to worry about when I hit the keyboard was the syntax to make it do the thing.
## When Logic Breaks During Coding
Here is a scenario that happens all the time: you have worked out your logic, tested it manually, and it looks perfect. You start translating it to code, and halfway through, you realize something does not make sense. Maybe you cannot figure out how to express a particular step. Maybe you discover an edge case you did not consider. Maybe the logic just... does not work the way you thought it would.
I see it all the time. You have worked out your logic, tested it manually, and it looks perfect. You start translating it to code, and halfway through, you realize it's not perfect at all.
Maybe you cannot figure out how to achieve a specific step. Maybe you discover an edge case you did not consider. Maybe the logic just... does not work the way you thought it would.
**Stop coding immediately.**
@@ -223,13 +227,14 @@ When you think algorithmically first, you gain several advantages:
## The Takeaway
The next time you sit down to solve a coding problem, resist the urge to immediately start typing. Instead:
The next time you have to write some code, don't write the code! Do this:
1. Write out your logic in plain English, step-by-step.
2. Test that logic manually with several examples.
3. Refine your logic until it works perfectly.
4. **Only then** translate it into code.
2. Test that logic by hand, using multiple test cases.
3. Ideally, you've touched every "branch" in your logical breakdown.
3. Edit and adjust the logic when test cases fail.
4. Once all of your manual test cases pass your hand-written logic, you can finally begin translating it into code.
You will find that your code is cleaner, your bugs are fewer, and your problem-solving skills are stronger. And hey - if you can explain your logic to me in plain English and it works, then translating it to code is just a matter of syntax. And syntax is the easy part!
> 💡 Remember: computers are really stupid toddlers who will do only and exactly what you say. Be precise, be thorough, and test your logic before you write your code.
> 💡 Remember: computers are children who will do only and exactly what you say. Be precise, be thorough, and test your logic before you write your code.

View File

@@ -53,4 +53,31 @@ figcaption {
@apply text-sm;
@apply text-center;
@apply italic;
}
pre {
@apply text-left;
@apply bg-gray-100;
@apply p-2;
@apply rounded-md;
@apply border;
@apply border-gray-300;
@apply overflow-x-auto;
@apply whitespace-pre-wrap;
@apply break-words;
@apply text-sm;
@apply font-mono;
}
code:not(pre code) {
@apply text-sm;
@apply font-mono;
@apply bg-gray-100;
@apply p-1;
@apply rounded-md;
@apply border;
@apply border-gray-300;
@apply overflow-x-auto;
@apply whitespace-pre-wrap;
@apply break-words;
}

View File

@@ -11,19 +11,18 @@ import type { JSX, ReactNode } from "react";
import "./globals.css";
// eslint-disable-next-line new-cap -- This is a function call.
const inter = Inter({ subsets: [ "latin" ] });
const inter = Inter({ subsets: ["latin"] });
const metadata: Metadata = {
description:
"The personal musings of a transfem software engineer.",
description: "The personal musings of a transfem software engineer.",
openGraph: {
images: "https://cdn.nhcarrigan.com/og-image.png",
},
title: "Naomi's Blog",
title: "Naomi's Blog",
twitter: {
card: "summary_large_image",
card: "summary_large_image",
images: "https://cdn.nhcarrigan.com/og-image.png",
site: "@naomi_lgbt",
site: "@naomi_lgbt",
},
};
@@ -48,14 +47,12 @@ const RootLayout = ({
strategy={"afterInteractive"}
type="text/javascript"
></Script>
<link href="https://cdn.nhcarrigan.com/logo.png" rel="icon" sizes="any" />
<link
href="https://cdn.nhcarrigan.com/logo.png"
rel="icon"
sizes="any"
/>
<body className={inter.className}>
{children}
</body>
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.11.1/styles/default.min.css"
></link>
<body className={inter.className}>{children}</body>
</html>
);
};

View File

@@ -7,6 +7,7 @@
import Markdown from "react-markdown";
import rehypeRaw from "rehype-raw";
import remarkGfm from "remark-gfm";
import rehypeHighlight from "rehype-highlight";
import type { JSX } from "react";
import { Rule } from "@/components/rule";
import { getPostData } from "@/lib/posts";
@@ -34,7 +35,7 @@ const Page = async({
<h2 className="text-center">{post.data.summary}</h2>
<p className="text-center">{`A ${post.data.readtime}.`}</p>
<Rule />
<Markdown rehypePlugins={[ rehypeRaw ]} remarkPlugins={[ remarkGfm ]}>
<Markdown rehypePlugins={[ rehypeRaw, rehypeHighlight ]} remarkPlugins={[ remarkGfm ]}>
{post.content}
</Markdown>
<Rule />