- {{content}} +
+
+ {{#has tag="announcements,conferences-2,open-source-2,sponsorships,governance,newsletter-2,company-spotlight,community"}}

{{/has}} +

{{title}}

-

{{date published_at format="MMMM DD, YYYY"}}

-
+
+
+
+ {{content}} +
+
- {{/post}} - - {{#contentFor 'scripts'}} {{/contentFor}} diff --git a/src/css/app.css b/src/css/app.css index d2f5d74..38bfd73 100644 --- a/src/css/app.css +++ b/src/css/app.css @@ -31,6 +31,9 @@ @import "components/_info-block.css" layer(components); @import "components/_info-block-feature.css" layer(components); @import "components/_link-list.css" layer(components); +@import "components/_news.css" layer(components); +@import "components/_pagination.css" layer(components); +@import "components/_post.css" layer(components); @import "components/_section.css" layer(components); @import "components/_sponsor-group.css" layer(components); @import "components/_sponsor-logo.css" layer(components); @@ -44,4 +47,3 @@ /* Vendors */ @import "vendors/ghost.css" layer(vendors); -@import "../../node_modules/tocbot/dist/tocbot.css" layer(vendors); diff --git a/src/css/base/_layout.css b/src/css/base/_layout.css index fa1b854..2d58c08 100644 --- a/src/css/base/_layout.css +++ b/src/css/base/_layout.css @@ -14,13 +14,16 @@ main { gap: var(--space--xxx-large); grid-template-columns: minmax(0, 1fr); margin-block-end: var(--space--xx-large); - padding-inline: var(--space--page); } body:has(.hero--home) { background-color: var(--color--background-secondary); } + +body.page-template { + --color--theme-background: var(--color--background-secondary); +} body.page-about { --color--theme-background: var(--color--accent-purple-background); } @@ -40,3 +43,12 @@ body.page-events { body.page-sponsors { --color--theme-background: var(--color--accent-yellow-background); } + +body.page-news, +body.tag-template { + --color--theme-background: var(--color--accent-red-background); +} + +body.post-template { + --color--theme-background: var(--color--background-secondary); +} diff --git a/src/css/base/_typography.css b/src/css/base/_typography.css index c335aa6..c839a8f 100644 --- a/src/css/base/_typography.css +++ b/src/css/base/_typography.css @@ -30,11 +30,16 @@ h2 { a { color: var(--color--link); text-decoration-color: var(--color--link-accent); + text-decoration-thickness: 10%; transition: var(--transition-duration--base) text-decoration-color var(--transition-timing--base); &:hover { text-decoration-color: var(--color--link); } + + u { + text-decoration: none; + } } label { diff --git a/src/css/base/_variables.css b/src/css/base/_variables.css index f150d07..798e662 100644 --- a/src/css/base/_variables.css +++ b/src/css/base/_variables.css @@ -7,7 +7,8 @@ --color--black-base: #292e37; --color--blue-base: #4581d6; --color--blue-light: #edf5ff; - --color--gray-base: #eff4f8; + --color--gray-base: #e4eaf5; + --color--gray-light: #eff4f8; --color--green-base: #59c899; --color--green-light: #f2fff9; --color--navy-base: #36435e; @@ -18,6 +19,7 @@ --color--purple-light: #fcf4ff; --color--red-base: #ff3b32; --color--red-dark: #cf2821; + --color--red-light: #ffeeed; --color--white-base: #ffffff; --color--yellow-base: #fec233; --color--yellow-light: #fff8ec; @@ -41,11 +43,13 @@ --color--accent-orange-background: var(--color--orange-light); --color--accent-purple: var(--color--purple-base); --color--accent-purple-background: var(--color--purple-light); + --color--accent-red: var(--color--red-base); + --color--accent-red-background: var(--color--red-light); --color--accent-yellow: var(--color--yellow-base); --color--accent-yellow-background: var(--color--yellow-light); --color--background-base: var(--color--white-base); - --color--background-secondary: var(--color--gray-base); + --color--background-secondary: var(--color--gray-light); --color--background-dark: var(--color--navy-dark); --color--button-primary: var(--color--accent-yellow); @@ -108,6 +112,7 @@ /* Container sizing */ --container--base: 85rem; + --container--narrow: 48rem; /* Spacing */ diff --git a/src/css/components/_hero.css b/src/css/components/_hero.css index 2d69b9d..6cf1398 100644 --- a/src/css/components/_hero.css +++ b/src/css/components/_hero.css @@ -1,6 +1,5 @@ .hero { background-color: var(--color--theme-background); - margin-inline: calc(-1 * var(--space--medium)); min-width: 0; padding-block: var(--space--x-large); } diff --git a/src/css/components/_news.css b/src/css/components/_news.css new file mode 100644 index 0000000..9d9f4e1 --- /dev/null +++ b/src/css/components/_news.css @@ -0,0 +1,106 @@ +.news-list { + display: grid; + gap: var(--space--x-large); +} + +.news-teases { + --gutter: var(--space--large); + + display: grid; + gap: var(--gutter); +} + +.news-teases__item { + border-bottom: var(--border--light); + display: grid; + gap: var(--space--small); + padding-block-end: var(--gutter); + + h3, p { + margin: 0; + } +} + +.news-teases__date { + font-size: var(--font-size--body-small); +} + +.news-teases__title { + font-size: var(--font-size--heading-subsection); +} + + +.news-featured { + display: grid; + gap: var(--space--large); + padding-block-end: var(--space--large); + + @media (min-width: 55em) { + &:has(.news-featured__image) { + grid-template-columns: 1fr 1fr; + } + } +} + +.news-featured__content { + align-content: start; + display: grid; + gap: var(--space--small); + + p { + margin: 0; + } +} + +.news-featured__date { + font-size: var(--font-size--body-small); +} + +.news-featured__title { + font-family: var(--font-family--heading); + font-size: var(--font-size--heading-section); + line-height: var(--line-height--tight); + margin: 0; +} + +.news-latest { + display: grid; + gap: var(--space--large); +} + +.news-latest__heading { + margin: 0; +} + +.news-tag-nav { + display: flex; + flex-wrap: wrap; + gap: var(--space--x-small); +} + +.news-tag-nav__link { + border: var(--border--dark); + border-radius: var(--border-radius--base); + color: var(--color--text-base); + font-size: var(--font-size--body-small); + font-weight: var(--font-weight--bold); + padding: var(--space--xx-small) var(--space--small); + text-decoration: none; + transition-property: background-color, border-color; + + &:hover { + background-color: var(--color--secondary-base); + border-color: transparent; + } +} + +.news-tag-nav__link[aria-current] { + background-color: var(--color--secondary-base); + border-color: transparent; +} + +.news-teases__tags { + display: flex; + font-size: var(--font-size--body-small); + gap: var(--space--small); +} diff --git a/src/css/components/_pagination.css b/src/css/components/_pagination.css new file mode 100644 index 0000000..1777101 --- /dev/null +++ b/src/css/components/_pagination.css @@ -0,0 +1,13 @@ +.pagination { + display: flex; + justify-content: space-between; +} + +.pagination__number { + font-size: var(--font-size--body-small); + margin: 0; +} + +.pagination__number-current { + font-weight: var(--font-weight--bold); +} diff --git a/src/css/components/_post.css b/src/css/components/_post.css new file mode 100644 index 0000000..b261d84 --- /dev/null +++ b/src/css/components/_post.css @@ -0,0 +1,69 @@ +.post-header { + background-color: var(--color--theme-background); + padding-block: var(--space--x-large); +} + +.post-header__inner { + display: flex; + flex-direction: column; + gap: var(--space--small); +} + +.post-header__date { + font-size: var(--font-size--body-small); + font-weight: var(--font-weight--bold); + margin: 0; +} + +.post-header__title { + font-family: var(--font-family--heading); + font-size: var(--font-size--heading-title-small); + font-weight: var(--font-weight--bold); + line-height: var(--line-height--tight); + margin: 0; +} + +.post h2 { + border-bottom: var(--border--light); +} + +.post-toc { + align-self: start; + display: none; + position: sticky; + top: calc(var(--space--large) * 3); + + @media (min-width: 55em) { + display: block; + } +} + +[data-toc]:empty { + display: none; +} + +.post-toc__list { + border-left: var(--border--light); + display: flex; + flex-direction: column; + gap: var(--space--small); + padding-inline-start: var(--space--base); +} + +.post-toc__link { + background-color: transparent; + border: 0; + border-bottom: var(--border-width--thick) solid transparent; + color: var(--color--text-base); + font-size: var(--font-size--body-small); + font-weight: var(--font-weight--bold); + padding-block-end: var(--space--xx-small); + text-decoration: 0; + transition-property: border-bottom-color; + + &:hover, + &[aria-current] { + border-bottom-color: var(--color--primary-base); + } +} + diff --git a/src/css/components/_video-tease.css b/src/css/components/_video-tease.css index cab1cc1..62a8b60 100644 --- a/src/css/components/_video-tease.css +++ b/src/css/components/_video-tease.css @@ -9,10 +9,10 @@ .video-tease__image { --play-button-size: 3rem; + align-items: center; border: var(--border--light); border-radius: var(--border-radius--base); - align-items: center; display: grid; justify-items: center; @@ -55,7 +55,7 @@ &:hover { .image img { - transform: scale(1.15); + transform: scale(1.05); } &::before { diff --git a/src/css/utilities/_container.css b/src/css/utilities/_container.css index be52d4f..30db7a3 100644 --- a/src/css/utilities/_container.css +++ b/src/css/utilities/_container.css @@ -5,3 +5,7 @@ padding-inline: var(--space--medium); width: 100%; } + +.u-container--narrow { + max-width: var(--container--narrow); +} diff --git a/src/js/app/index.js b/src/js/app/index.js index f37acca..bbeff40 100644 --- a/src/js/app/index.js +++ b/src/js/app/index.js @@ -1,6 +1,14 @@ import './global-nav'; import './home-involvement'; +// Mark active tag nav link based on current path +const currentPath = window.location.pathname; +document.querySelectorAll('[data-tag-nav] a').forEach(link => { + if (link.getAttribute('href') === currentPath) { + link.setAttribute('aria-current', 'page'); + } +}); + document.querySelectorAll('.section-header').forEach((header) => { header.addEventListener('click', function () { this.parentNode.classList.toggle('active'); diff --git a/src/js/post/index.js b/src/js/post/index.js index c604cac..932bf35 100644 --- a/src/js/post/index.js +++ b/src/js/post/index.js @@ -1,8 +1,4 @@ -// 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/);
@@ -22,13 +18,43 @@ document.querySelectorAll('pre').forEach((pre) => {
     }
 });
 
-tocbot.init({
-    // Where to render the table of contents.
-    tocSelector: '.gh-toc',
-    // Where to grab the headings to build the table of contents.
-    contentSelector: '.post',
-    // Which headings to grab inside of the contentSelector element.
-    headingSelector: 'h2, h3, h4',
-    // Ensure correct positioning
-    hasInnerContainers: true,
-});
+// Table of contents
+const toc = document.querySelector('[data-toc]');
+const post = document.querySelector('[data-post-content]');
+
+if (toc && post) {
+    const headings = [...post.querySelectorAll('h2')].filter(h => h.id);
+
+    if (headings.length > 0) {
+        const list = document.createElement('ul');
+        list.className = 'post-toc__list';
+
+        headings.forEach(heading => {
+            const item = document.createElement('li');
+            item.className = 'post-toc__item';
+            const link = document.createElement('a');
+            link.href = `#${heading.id}`;
+            link.textContent = heading.textContent;
+            link.className = 'post-toc__link';
+            item.appendChild(link);
+            list.appendChild(item);
+        });
+
+        toc.appendChild(list);
+
+        const observer = new IntersectionObserver(entries => {
+            entries.forEach(entry => {
+                const link = toc.querySelector(`a[href="#${entry.target.id}"]`);
+                if (link) {
+                    if (entry.isIntersecting) {
+                        link.setAttribute('aria-current', 'location');
+                    } else {
+                        link.removeAttribute('aria-current');
+                    }
+                }
+            });
+        }, { rootMargin: '0px 0px -80% 0px' });
+
+        headings.forEach(h => observer.observe(h));
+    }
+}

From 62213c6da73ca9200c0263aa98974e675d6feacd Mon Sep 17 00:00:00 2001
From: Elaina Natario 
Date: Fri, 26 Jun 2026 15:04:24 -0400
Subject: [PATCH 25/36] Random finessing (#23)

* relinking a bunch of things to real links

* link adjustment on programs
---
 about.hbs               |  6 ++++++
 custom-events.hbs       |  6 +++---
 custom-programs.hbs     | 24 ++++++++++++------------
 partials/navigation.hbs |  2 +-
 4 files changed, 22 insertions(+), 16 deletions(-)

diff --git a/about.hbs b/about.hbs
index e81dfb7..0629d80 100644
--- a/about.hbs
+++ b/about.hbs
@@ -22,4 +22,10 @@
   {{/get}}
 {{/components/section}}
 
+{{#> "components/section" id="governance-and-finances" copy="title:'About::GovernanceAndFinances - Heading'" grid="trio" feature=true}}
+  {{> "components/info-block" copy="title:'About::GovernanceAndFinances - Governance'" primary="title:'About::GovernanceAndFinances - Governance - Button'" id=""}}
+  {{> "components/info-block" copy="title:'About::GovernanceAndFinances - Finances'" id=""}}
+  {{> "components/info-block" copy="title:'About::GovernanceAndFinances - Bylaws'" id=""}}
+{{/components/section}}
+
 {{> "components/cta" copy="title:'About::Callout'" primary="title:'About::Callout - Button'" label="Contact"}}
diff --git a/custom-events.hbs b/custom-events.hbs
index d419158..26c6de0 100644
--- a/custom-events.hbs
+++ b/custom-events.hbs
@@ -1,13 +1,13 @@
 {{!< default}}
 {{> "components/hero" copy="title:'Events::Hero - Body'" links="tag:hash-events-hero-link" linksLabel="More in events"}}
 
-{{> "components/info-block" copy="title:'Events::RubyConf2026'" primary="title:'Events::RubyConf2026 - Button'" secondary="title:'Events::RubyConf2026 - Secondary Button'" id="rubyconf-2026" container=true inverse=true}}
+{{> "components/info-block" copy="title:'Events::RubyConf2026'" secondary="title:'Events::RubyConf2026 - Secondary Button'" id="rubyconf-2026" container=true inverse=true}}
 
 {{> "components/cta" copy="title:'Events::Callout'" primary="title:'Events::Callout - Button'" label="Scholars and Guides"}}
 
-{{> "components/info-block" copy="title:'Events::CallForProposals'" primary="title:'Events::CallForProposals - Button'" secondary="title:'Events::CallForProposals - Secondary Button'" id="call-for-proposals" container=true}}
+{{> "components/info-block" copy="title:'Events::CallForProposals'" secondary="title:'Events::CallForProposals - Secondary Button'" id="call-for-proposals" container=true}}
 
-{{> "components/info-block" copy="title:'Events::NearbyEvents'" primary="title:'Events::NearbyEvents - Button'" secondary="title:'Events::NearbyEvents - Secondary Button'" id="nearby-events" container=true inverse=true}}
+{{> "components/info-block" copy="title:'Events::NearbyEvents'" primary="title:'Events::NearbyEvents - Button'" id="nearby-events" container=true inverse=true}}
 
 {{#> "components/section" id="past-events" copy="title:'Events::PastEvents - Heading'" grid="trio" footerPrimary="title:'Events::PastEvents - Button'"}}
   {{#get "pages" filter="tag:hash-rubyconf-videos" limit="all" order="published_at asc"}}
diff --git a/custom-programs.hbs b/custom-programs.hbs
index d70642c..d9d7119 100644
--- a/custom-programs.hbs
+++ b/custom-programs.hbs
@@ -1,22 +1,22 @@
 {{!< default}}
 {{> "components/hero" copy="title:'Programs::Hero - Body'" links="tag:hash-programs-hero-link" linksLabel="More in programs"}}
 
-{{> "components/info-block" copy="title:'Programs::RubyGems'" primary="title:'Programs::RubyGems - Button'" secondary="title:'Programs::RubyGems - Secondary Button'" id="rubygems" container=true inverse=true}}
-
-{{#> "components/section" id="open-source-projects" copy="title:'Programs::OpenSourceProjects - Heading'" grid="trio"}}
-  {{> "components/info-block" copy="title:'Programs::OpenSourceProjects - Bundler'" primary="title:'Programs::OpenSourceProjects - Bundler - Button'" id="" border=true}}
-  {{> "components/info-block" copy="title:'Programs::OpenSourceProjects - Gemstash'" primary="title:'Programs::OpenSourceProjects - Gemstash - Button'" id="" border=true}}
-  {{> "components/info-block" copy="title:'Programs::OpenSourceProjects - RubyAPI'" primary="title:'Programs::OpenSourceProjects - RubyAPI - Button'" id="" border=true}}
-  {{> "components/info-block" copy="title:'Programs::OpenSourceProjects - RubyGems'" primary="title:'Programs::OpenSourceProjects - RubyGems - Button'" id="" border=true}}
-  {{> "components/info-block" copy="title:'Programs::OpenSourceProjects - TheRubyToolbox'" primary="title:'Programs::OpenSourceProjects - TheRubyToolbox - Button'" id="" border=true}}
-{{/components/section}}
+{{> "components/info-block" copy="title:'Programs::RubyGems'" primary="title:'Programs::RubyGems - Button'" id="rubygems" container=true inverse=true}}
+
+{{> "components/info-block" copy="title:'Programs::RubyGems - Mission'" id="our-mission" container=true}}
+
+{{> "components/info-block" copy="title:'Programs::RubyGems - Vision'" id="our-vision" container=true inverse=true}}
 
 {{> "components/cta" copy="title:'Programs::Callout - Ideas'" primary="title:'Programs::Callout - Ideas - Button'" label="Suggest a program"}}
 
-{{> "components/info-block" copy="title:'Programs::ProjectDream'" primary="title:'Programs::ProjectDream - Button'" secondary="title:'Programs::ProjectDream - Secondary Button'" id="project-dream" container=true}}
+{{#> "components/section" id="open-source" copy="title:'Programs::OpenSource - Heading'" grid="trio"}}
+  {{> "components/info-block" copy="title:'Programs::OpenSource - Block1'" primary="title:'Programs::OpenSource - Block1 - Button'" id=""}}
+  {{> "components/info-block" copy="title:'Programs::OpenSource - Block2'" id=""}}
+  {{> "components/info-block" copy="title:'Programs::OpenSource - Block3'" id=""}}
+{{/components/section}}
+
+{{> "components/info-block" copy="title:'Programs::ProjectDream'" primary="title:'Programs::ProjectDream - Button'" id="project-dream" container=true}}
 
 {{> "components/info-block" copy="title:'Programs::Apprenticeships'" primary="title:'Programs::Apprenticeships - Button'" id="apprenticeships" container=true inverse=true}}
 
 {{> "components/cta" copy="title:'Programs::Callout - Get Involved'" primary="title:'Programs::Callout - Get Involved - Button'" label="Get involved"}}
-
-{{> "components/info-block" copy="title:'Programs::InfrastructureAndSecurity'" primary="title:'Programs::InfrastructureAndSecurity - Button'" secondary="title:'Programs::InfrastructureAndSecurity - Secondary Button'" id="infrastructure-and-security" container=true}}
diff --git a/partials/navigation.hbs b/partials/navigation.hbs
index 7db0740..2417724 100644
--- a/partials/navigation.hbs
+++ b/partials/navigation.hbs
@@ -16,7 +16,7 @@