From b0689805f122607ff8a4075468f66b57c1dd2679 Mon Sep 17 00:00:00 2001 From: Jim Remsik Date: Sun, 29 Mar 2026 10:26:27 -0500 Subject: [PATCH 1/6] Add code block styles inspired by GitHub, themed to match site design --- src/css/app.css | 1 + src/css/components/code.css | 114 ++++++++++++++++++++++++++++++++++++ 2 files changed, 115 insertions(+) create mode 100644 src/css/components/code.css diff --git a/src/css/app.css b/src/css/app.css index 42dcd3c..18d7dfe 100644 --- a/src/css/app.css +++ b/src/css/app.css @@ -4,6 +4,7 @@ /* Components */ @import './components/button.css'; +@import './components/code.css'; @import './components/get-involved.css'; @import './components/sponsors.css'; @import './components/profile-image.css'; diff --git a/src/css/components/code.css b/src/css/components/code.css new file mode 100644 index 0000000..891d0a8 --- /dev/null +++ b/src/css/components/code.css @@ -0,0 +1,114 @@ +/* Inline code */ +:not(pre) > code { + background-color: var(--color-lightblue); + border: 1px solid color-mix(in srgb, var(--color-blue) 25%, transparent); + border-radius: 4px; + color: var(--color-mutednavy); + font-family: 'Menlo', 'Consolas', 'Monaco', monospace; + font-size: 0.875em; + padding: 0.15em 0.4em; +} + +/* Code block wrapper — Ghost wraps
 in a .kg-code-card */
+.kg-code-card {
+    margin: 1.75rem 0;
+}
+
+pre {
+    background-color: var(--color-navy);
+    border-radius: 6px;
+    color: #cdd9e5;
+    font-family: 'Menlo', 'Consolas', 'Monaco', monospace;
+    font-size: 0.875rem;
+    line-height: 1.6;
+    margin: 1.75rem 0;
+    overflow-x: auto;
+    padding: 1.25rem 1.5rem;
+    position: relative;
+}
+
+pre code {
+    background: none;
+    border: none;
+    color: inherit;
+    font-size: inherit;
+    padding: 0;
+}
+
+/* Language label — Ghost adds data-language on the 
 element */
+pre[data-language]::before {
+    background-color: var(--color-yellow);
+    border-radius: 0 0 4px 4px;
+    color: var(--color-navy);
+    content: attr(data-language);
+    font-family: 'Inter', sans-serif;
+    font-size: 0.7rem;
+    font-weight: 600;
+    letter-spacing: 0.05em;
+    padding: 2px 8px;
+    position: absolute;
+    right: 1rem;
+    text-transform: uppercase;
+    top: 0;
+}
+
+/* Syntax token colors — tuned for the navy background */
+.kg-code-card .token.comment,
+.kg-code-card .token.prolog,
+.kg-code-card .token.doctype,
+.kg-code-card .token.cdata {
+    color: #768390;
+    font-style: italic;
+}
+
+.kg-code-card .token.punctuation {
+    color: #8dbbe8;
+}
+
+.kg-code-card .token.namespace {
+    opacity: 0.7;
+}
+
+.kg-code-card .token.property,
+.kg-code-card .token.tag,
+.kg-code-card .token.boolean,
+.kg-code-card .token.number,
+.kg-code-card .token.constant,
+.kg-code-card .token.symbol,
+.kg-code-card .token.deleted {
+    color: var(--color-red);
+}
+
+.kg-code-card .token.selector,
+.kg-code-card .token.attr-name,
+.kg-code-card .token.string,
+.kg-code-card .token.char,
+.kg-code-card .token.builtin,
+.kg-code-card .token.inserted {
+    color: var(--color-green);
+}
+
+.kg-code-card .token.operator,
+.kg-code-card .token.entity,
+.kg-code-card .token.url,
+.language-css .token.string,
+.style .token.string {
+    color: #8dbbe8;
+}
+
+.kg-code-card .token.atrule,
+.kg-code-card .token.attr-value,
+.kg-code-card .token.keyword {
+    color: var(--color-blue);
+}
+
+.kg-code-card .token.function,
+.kg-code-card .token.class-name {
+    color: var(--color-yellow);
+}
+
+.kg-code-card .token.regex,
+.kg-code-card .token.important,
+.kg-code-card .token.variable {
+    color: #f69d50;
+}

From 15ef97daa43b2f5b5b19726281634165e815db60 Mon Sep 17 00:00:00 2001
From: Jim Remsik 
Date: Sun, 29 Mar 2026 11:54:12 -0500
Subject: [PATCH 2/6] Add syntax highlighting token colors and code block wrap
 toggle

---
 src/css/components/code.css | 71 ++++++++++++++++++++-----------------
 src/js/post/index.js        | 12 +++++++
 2 files changed, 50 insertions(+), 33 deletions(-)

diff --git a/src/css/components/code.css b/src/css/components/code.css
index 891d0a8..816e43d 100644
--- a/src/css/components/code.css
+++ b/src/css/components/code.css
@@ -35,12 +35,17 @@ pre code {
     padding: 0;
 }
 
-/* Language label — Ghost adds data-language on the 
 element */
-pre[data-language]::before {
+pre.wrap {
+    white-space: pre-wrap;
+    overflow-x: visible;
+}
+
+/* Language label — Prism adds language-* class to 
 */
+pre[class*="language-"]::before {
     background-color: var(--color-yellow);
     border-radius: 0 0 4px 4px;
     color: var(--color-navy);
-    content: attr(data-language);
+    content: attr(class);
     font-family: 'Inter', sans-serif;
     font-size: 0.7rem;
     font-weight: 600;
@@ -53,62 +58,62 @@ pre[data-language]::before {
 }
 
 /* Syntax token colors — tuned for the navy background */
-.kg-code-card .token.comment,
-.kg-code-card .token.prolog,
-.kg-code-card .token.doctype,
-.kg-code-card .token.cdata {
+.token.comment,
+.token.prolog,
+.token.doctype,
+.token.cdata {
     color: #768390;
     font-style: italic;
 }
 
-.kg-code-card .token.punctuation {
+.token.punctuation {
     color: #8dbbe8;
 }
 
-.kg-code-card .token.namespace {
+.token.namespace {
     opacity: 0.7;
 }
 
-.kg-code-card .token.property,
-.kg-code-card .token.tag,
-.kg-code-card .token.boolean,
-.kg-code-card .token.number,
-.kg-code-card .token.constant,
-.kg-code-card .token.symbol,
-.kg-code-card .token.deleted {
+.token.property,
+.token.tag,
+.token.boolean,
+.token.number,
+.token.constant,
+.token.symbol,
+.token.deleted {
     color: var(--color-red);
 }
 
-.kg-code-card .token.selector,
-.kg-code-card .token.attr-name,
-.kg-code-card .token.string,
-.kg-code-card .token.char,
-.kg-code-card .token.builtin,
-.kg-code-card .token.inserted {
+.token.selector,
+.token.attr-name,
+.token.string,
+.token.char,
+.token.builtin,
+.token.inserted {
     color: var(--color-green);
 }
 
-.kg-code-card .token.operator,
-.kg-code-card .token.entity,
-.kg-code-card .token.url,
+.token.operator,
+.token.entity,
+.token.url,
 .language-css .token.string,
 .style .token.string {
     color: #8dbbe8;
 }
 
-.kg-code-card .token.atrule,
-.kg-code-card .token.attr-value,
-.kg-code-card .token.keyword {
+.token.atrule,
+.token.attr-value,
+.token.keyword {
     color: var(--color-blue);
 }
 
-.kg-code-card .token.function,
-.kg-code-card .token.class-name {
+.token.function,
+.token.class-name {
     color: var(--color-yellow);
 }
 
-.kg-code-card .token.regex,
-.kg-code-card .token.important,
-.kg-code-card .token.variable {
+.token.regex,
+.token.important,
+.token.variable {
     color: #f69d50;
 }
diff --git a/src/js/post/index.js b/src/js/post/index.js
index 163b633..04ed4ba 100644
--- a/src/js/post/index.js
+++ b/src/js/post/index.js
@@ -1,6 +1,18 @@
 // Ship JS only active on post pages for better performance
 import tocbot from 'tocbot';
 
+// Apply .wrap class to any 
 immediately following a  HTML card
+document.querySelectorAll('pre').forEach((pre) => {
+    let node = pre.closest('.kg-code-card') ?? pre;
+    let prev = node.previousSibling;
+    while (prev && prev.nodeType === Node.TEXT_NODE) {
+        prev = prev.previousSibling;
+    }
+    if (prev && prev.nodeType === Node.COMMENT_NODE && prev.nodeValue.trim() === 'wrap') {
+        pre.classList.add('wrap');
+    }
+});
+
 tocbot.init({
     // Where to render the table of contents.
     tocSelector: '.gh-toc',

From a366afd180d244d74953b712cc119b60be99bdf6 Mon Sep 17 00:00:00 2001
From: Jim Remsik 
Date: Sun, 29 Mar 2026 12:16:28 -0500
Subject: [PATCH 3/6] Fix code block language label to show language name
 without prefix

---
 default.hbs                 | 4 ++++
 src/css/components/code.css | 6 +++---
 src/js/post/index.js        | 9 +++++++++
 3 files changed, 16 insertions(+), 3 deletions(-)

diff --git a/default.hbs b/default.hbs
index ce4a0c5..c02f271 100644
--- a/default.hbs
+++ b/default.hbs
@@ -10,6 +10,10 @@
     
     
 
+    {{!-- Prism syntax highlighting --}}
+    
+    
+
     {{!-- contentFor/block scripts - use with defer --}}
     {{{block "scripts"}}}
 
diff --git a/src/css/components/code.css b/src/css/components/code.css
index 816e43d..863b8ca 100644
--- a/src/css/components/code.css
+++ b/src/css/components/code.css
@@ -40,12 +40,12 @@ pre.wrap {
     overflow-x: visible;
 }
 
-/* Language label — Prism adds language-* class to 
 */
-pre[class*="language-"]::before {
+/* Language label — set via JS from Prism's language-* class */
+pre[data-language]::before {
     background-color: var(--color-yellow);
     border-radius: 0 0 4px 4px;
     color: var(--color-navy);
-    content: attr(class);
+    content: attr(data-language);
     font-family: 'Inter', sans-serif;
     font-size: 0.7rem;
     font-weight: 600;
diff --git a/src/js/post/index.js b/src/js/post/index.js
index 04ed4ba..c604cac 100644
--- a/src/js/post/index.js
+++ b/src/js/post/index.js
@@ -1,6 +1,15 @@
 // Ship JS only active on post pages for better performance
 import tocbot from 'tocbot';
 
+// Set data-language on 
 elements so CSS can display a clean label.
+// Runs on load to ensure Prism's autoloader has finished highlighting.
+window.addEventListener('load', () => {
+    document.querySelectorAll('pre > code[class*="language-"]').forEach((code) => {
+        const match = code.className.match(/\blanguage-(\w+)\b/);
+        if (match) code.closest('pre').dataset.language = match[1];
+    });
+});
+
 // Apply .wrap class to any 
 immediately following a  HTML card
 document.querySelectorAll('pre').forEach((pre) => {
     let node = pre.closest('.kg-code-card') ?? pre;

From fe1f4812d56f05778fcf1600015fd8c673d85eed Mon Sep 17 00:00:00 2001
From: Jim Remsik 
Date: Sun, 29 Mar 2026 12:26:54 -0500
Subject: [PATCH 4/6] Add ADR for code block syntax highlighting and ADR
 template

---
 .../0001-code-block-syntax-highlighting.md    | 32 +++++++++++++++++++
 docs/adr/template.md                          | 24 ++++++++++++++
 2 files changed, 56 insertions(+)
 create mode 100644 docs/adr/0001-code-block-syntax-highlighting.md
 create mode 100644 docs/adr/template.md

diff --git a/docs/adr/0001-code-block-syntax-highlighting.md b/docs/adr/0001-code-block-syntax-highlighting.md
new file mode 100644
index 0000000..d578423
--- /dev/null
+++ b/docs/adr/0001-code-block-syntax-highlighting.md
@@ -0,0 +1,32 @@
+# ADR 0001: Code Block Syntax Highlighting
+
+**Date:** 2026-03-29
+**Status:** Done
+
+## Context
+
+The theme needed support for displaying code blocks in posts and pages. Ghost's Koenig editor outputs `
` markup but the theme had no styles or syntax highlighting for it.
+
+## Decisions
+
+### Prism.js via CDN
+
+Prism.js is loaded from jsDelivr with the autoloader plugin rather than bundled into `app.js`. This keeps the theme build lean and means any language is supported on demand without maintaining a list of grammar files.
+
+### Token colors from the design system
+
+Syntax token colors are mapped to existing CSS variables (`--color-blue`, `--color-green`, `--color-red`, `--color-yellow`) rather than introducing a third-party theme. This keeps the code blocks feeling native to the site.
+
+### Language label via JS + CSS
+
+Ghost's Markdown card puts `language-*` on the `` element, not the `
`. A script in `post.js` reads the class, extracts the language name, and sets it as `data-language` on the `
`. A CSS `::before` pseudo-element renders the label. This avoids a dependency on Ghost-specific markup that could change.
+
+### Line wrap toggle via `` HTML card
+
+Ghost provides no mechanism to add classes to code block elements from the editor. Authors who want line wrapping instead of horizontal scroll can insert an HTML card containing `` immediately before a code block. A script in `post.js` detects the comment node and adds a `.wrap` class to the `
`.
+
+## Alternatives Considered
+
+- **Bundling Prism grammars** — would avoid the CDN dependency but add build complexity and require updating the bundle when new languages are needed.
+- **A Prism theme (e.g. Tomorrow Night)** — rejected in favor of token colors derived from the design system.
+- **Default line wrapping** — rejected because wrapping breaks visual indentation and makes code harder to scan. Opt-in per block is more appropriate.
diff --git a/docs/adr/template.md b/docs/adr/template.md
new file mode 100644
index 0000000..eb89f3f
--- /dev/null
+++ b/docs/adr/template.md
@@ -0,0 +1,24 @@
+# ADR XXXX: Title
+
+**Date:** YYYY-MM-DD
+**Status:** Proposed
+
+
+
+## Context
+
+What problem were you solving? What constraints or forces shaped the decision?
+
+## Decisions
+
+What was decided, and why?
+
+## Alternatives Considered
+
+What else was on the table and why was it ruled out?

From 9fd8d889906dd3316620d8370c44f8a916a79dca Mon Sep 17 00:00:00 2001
From: Jim Remsik 
Date: Sun, 29 Mar 2026 12:29:48 -0500
Subject: [PATCH 5/6] Document ADR process in README

---
 README.md | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/README.md b/README.md
index 3677dbf..e5ca0ea 100644
--- a/README.md
+++ b/README.md
@@ -54,6 +54,10 @@ You might have to refresh by hand after each change.
 If you can't see your changes, and you're sure that `npm run dev` is still going, you'll likely need to disable your browser's caching.
 Go to the Network tab in your dev tools and toggle "Disable cache".
 
+### Architecture decisions
+
+Significant decisions about how the theme is built are documented in [`docs/adr/`](docs/adr/). Before making a non-trivial change — adding a dependency, changing how a feature works, picking between approaches — please write an ADR. Use [`docs/adr/template.md`](docs/adr/template.md) as a starting point. The goal isn't process for its own sake; it's making sure future contributors understand *why* things are the way they are, not just what they are.
+
 ### Deployment
 
 The theme will automatically check, zip, and upload to Ghost via GitHub Actions. If you want to try it yourself locally:

From 107e9f48b1c4d0000b97a98d7eeaf8b3262dcc2f Mon Sep 17 00:00:00 2001
From: Jim Remsik 
Date: Sun, 29 Mar 2026 12:47:51 -0500
Subject: [PATCH 6/6] Bump version to 1.1.3

---
 package.json | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/package.json b/package.json
index 1150ea5..f423741 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "rubycentral-theme",
-  "version": "1.1.2",
+  "version": "1.1.3",
   "description": "A Ghost theme for Ruby Central",
   "engines": {
     "ghost": ">=4.0.0"