Skip to content

Commit 128c370

Browse files
Merge pull request #260 from rubygems/claude/frosty-meitner-new-design
Redesign blog.rubygems.org to match rubygems.org
2 parents ab1d766 + fae0e57 commit 128c370

62 files changed

Lines changed: 811 additions & 4450 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/build.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ jobs:
2929
uses: actions/checkout@v4
3030
with:
3131
persist-credentials: false
32+
- name: Install libvips
33+
run: sudo apt-get update -qq && sudo apt-get install -y --no-install-recommends libvips
3234
- name: Setup Ruby
3335
uses: ruby/setup-ruby@v1
3436
with:

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,5 @@
44
.jekyll-metadata
55
.sass-cache/
66
/_site/*
7+
.playwright-mcp/
8+
/assets/images/og/

404.html

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
---
2+
layout: default
3+
title: Page not found
4+
permalink: /404.html
5+
sitemap: false
6+
---
7+
8+
<div class="max-w-prose">
9+
<p class="text-sm font-semibold text-orange-700 mb-2">404</p>
10+
<h1 class="text-3xl md:text-4xl font-bold text-neutral-800 mb-4">Page not found</h1>
11+
<p class="text-lg text-neutral-700 mb-8">
12+
The page you were looking for doesn't exist. It may have been moved or renamed
13+
since this blog has been around since 2004.
14+
</p>
15+
<ul class="space-y-2 text-base">
16+
<li><a href="/" class="text-orange-700 hover:underline font-semibold">Browse all posts &rarr;</a></li>
17+
<li><a href="https://rubygems.org/" class="text-orange-700 hover:underline font-semibold">Visit RubyGems.org &rarr;</a></li>
18+
<li><a href="https://guides.rubygems.org/" class="text-orange-700 hover:underline font-semibold">Read the guides &rarr;</a></li>
19+
<li><a href="https://status.rubygems.org/" class="text-orange-700 hover:underline font-semibold">Check service status &rarr;</a></li>
20+
</ul>
21+
</div>

AGENTS.md

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
## Project
2+
3+
Jekyll blog at `https://blog.rubygems.org`. Auto-deploys to GitHub Pages on push to `master` (`.github/workflows/build.yml`). Ruby 3.4.7.
4+
5+
## Commands
6+
7+
```bash
8+
bin/setup # bundle install
9+
bundle exec jekyll serve # Dev server at http://127.0.0.1:4000 (auto-rebuilds)
10+
bundle exec jekyll build # One-shot build into _site/
11+
```
12+
13+
Tailwind v4 is compiled by the `jekyll-tailwindcss` plugin during the Jekyll build — no Node toolchain. Edit `_tailwind.css`; the plugin emits `_site/assets/css/styles.css`, which the layout links via `/assets/css/styles.css`. The empty `assets/css/styles.tailwindcss` source file is the marker that tells the plugin where to land the output — leave it as is.
14+
15+
## Layout
16+
17+
- `_posts/YYYY-MM-DD-slug.md`~470 posts back to 2004
18+
- `_layouts/{default,post}.html` — page shell + article wrapper
19+
- `_includes/{article,archive,nav_links}.html` — post card, year sidebar, nav
20+
- `_tailwind.css` — Tailwind entry; holds `@theme` tokens and `.prose` overrides
21+
- `index.html` — blog index; reuses `_includes/article.html` with `index = false`
22+
- `_config.yml` — site URL is `https://blog.rubygems.org` (see `CNAME`)
23+
24+
## Writing posts
25+
26+
Filename `_posts/YYYY-MM-DD-slug.md`. Required frontmatter:
27+
28+
```yaml
29+
---
30+
title: "Post title"
31+
layout: post
32+
author: Author Name
33+
author_email: author@example.com
34+
---
35+
```
36+
37+
## Gotchas
38+
39+
- **Never edit `_site/assets/css/styles.css`** — that's compiled output, regenerated on every build. Edit `_tailwind.css`.
40+
- **Use Tailwind tokens, not raw hex.** All colors and the font stack are defined as `@theme` tokens in `_tailwind.css` — reference `text-orange-700`, `bg-neutral-050`, etc. The token table is the source of truth; do not re-declare values in CLAUDE.md.
41+
- **Don't override `prose` styles in markup.** Tweak them in the `.prose` layer of `_tailwind.css` so all posts stay consistent.
42+
- **Light mode only** — no dark variants.
43+
- The blog mirrors rubygems.org (the "hammy" template). Header, footer, nav, type, and color should match the main site so the blog reads as an extension of it.
44+
45+
## Design intent
46+
47+
Reliable, open, technical. Content-first: the orange brand color (`orange-500` `#F74C27`) and Titillium Web wordmark are the only signature elements; everything else stays out of the way of the writing. References: GitHub Blog, Rust Blog, Go Blog. Anti-references: marketing-heavy or startup-y aesthetics, animation, dark patterns.
48+
49+
Page shell: `max-w-screen-xl`. Article body: `prose prose-lg` inside `max-w-3xl mx-auto` (centered, ~768px). Display heading: `text-3xl md:text-4xl font-bold text-neutral-800`.

CLAUDE.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
@AGENTS.md

Gemfile

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
source "https://rubygems.org"
22
ruby file: ".ruby-version"
33

4-
gem "base64", "~> 0.2.0"
5-
gem "bigdecimal", "~> 3.1"
6-
gem "csv", "~> 3.3"
74
gem "jekyll", "~> 4.0"
8-
gem "puma", "~> 6.4"
9-
gem "rack-jekyll", "~> 0.5.0", github: "adaoraul/rack-jekyll"
105
gem "rake", "~> 13.0"
11-
gem "sass", "~> 3.7"
6+
7+
group :jekyll_plugins do
8+
gem "jekyll-tailwindcss"
9+
gem "jekyll-sitemap"
10+
gem "jekyll-og-image"
11+
end

Gemfile.lock

Lines changed: 31 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,3 @@
1-
GIT
2-
remote: https://github.com/adaoraul/rack-jekyll.git
3-
revision: a997bd0c384fa377cda3b9ebeb462f91cd8dfd03
4-
specs:
5-
rack-jekyll (0.5.0)
6-
jekyll (>= 1.3)
7-
listen (>= 1.3)
8-
rack (>= 1.5)
9-
101
GEM
112
remote: https://rubygems.org/
123
specs:
@@ -48,8 +39,19 @@ GEM
4839
safe_yaml (~> 1.0)
4940
terminal-table (>= 1.8, < 4.0)
5041
webrick (~> 1.7)
42+
jekyll-og-image (2.1.1)
43+
jekyll (>= 3.4, < 5.0)
44+
jekyll-seo-tag (~> 2.8)
45+
ruby-vips (~> 2.2.0)
46+
zeitwerk (~> 2.6)
5147
jekyll-sass-converter (3.1.0)
5248
sass-embedded (~> 1.75)
49+
jekyll-seo-tag (2.8.0)
50+
jekyll (>= 3.8, < 5.0)
51+
jekyll-sitemap (1.4.0)
52+
jekyll (>= 3.7, < 5.0)
53+
jekyll-tailwindcss (0.7.0)
54+
tailwindcss-ruby
5355
jekyll-watch (2.2.1)
5456
listen (~> 3.0)
5557
json (2.17.1.2)
@@ -61,46 +63,42 @@ GEM
6163
listen (3.9.0)
6264
rb-fsevent (~> 0.10, >= 0.10.3)
6365
rb-inotify (~> 0.9, >= 0.9.10)
66+
logger (1.7.0)
6467
mercenary (0.4.0)
65-
nio4r (2.7.5)
6668
pathutil (0.16.2)
6769
forwardable-extended (~> 2.6)
6870
public_suffix (7.0.5)
69-
puma (6.6.1)
70-
nio4r (~> 2.0)
71-
rack (3.2.6)
7271
rake (13.3.1)
7372
rb-fsevent (0.11.2)
7473
rb-inotify (0.11.1)
7574
ffi (~> 1.0)
7675
rexml (3.4.4)
7776
rouge (4.6.1)
77+
ruby-vips (2.2.5)
78+
ffi (~> 1.12)
79+
logger
7880
safe_yaml (1.0.5)
79-
sass (3.7.4)
80-
sass-listen (~> 4.0.0)
8181
sass-embedded (1.94.2)
8282
google-protobuf (~> 4.31)
8383
rake (>= 13)
84-
sass-listen (4.0.0)
85-
rb-fsevent (~> 0.9, >= 0.9.4)
86-
rb-inotify (~> 0.9, >= 0.9.7)
84+
tailwindcss-ruby (4.2.2)
85+
tailwindcss-ruby (4.2.2-arm64-darwin)
8786
terminal-table (3.0.2)
8887
unicode-display_width (>= 1.1.1, < 3)
8988
unicode-display_width (2.6.0)
9089
webrick (1.9.2)
90+
zeitwerk (2.7.5)
9191

9292
PLATFORMS
93+
arm64-darwin-25
9394
ruby
9495

9596
DEPENDENCIES
96-
base64 (~> 0.2.0)
97-
bigdecimal (~> 3.1)
98-
csv (~> 3.3)
9997
jekyll (~> 4.0)
100-
puma (~> 6.4)
101-
rack-jekyll (~> 0.5.0)!
98+
jekyll-og-image
99+
jekyll-sitemap
100+
jekyll-tailwindcss
102101
rake (~> 13.0)
103-
sass (~> 3.7)
104102

105103
CHECKSUMS
106104
addressable (2.9.0) sha256=7fdf6ac3660f7f4e867a0838be3f6cf722ace541dd97767fa42bc6cfa980c7af
@@ -117,32 +115,35 @@ CHECKSUMS
117115
http_parser.rb (0.8.0) sha256=5a0932f1fa82ce08a8516a2685d5a86031c000560f89946913c555a0697544be
118116
i18n (1.14.7) sha256=ceba573f8138ff2c0915427f1fc5bdf4aa3ab8ae88c8ce255eb3ecf0a11a5d0f
119117
jekyll (4.4.1) sha256=4c1144d857a5b2b80d45b8cf5138289579a9f8136aadfa6dd684b31fe2bc18c1
118+
jekyll-og-image (2.1.1) sha256=0d535155abd0c5753f3ee0003ba1ff4051d17eb6b876c44c9d4a58fe0b796732
120119
jekyll-sass-converter (3.1.0) sha256=83925d84f1d134410c11d0c6643b0093e82e3a3cf127e90757a85294a3862443
120+
jekyll-seo-tag (2.8.0) sha256=3f2ed1916d56f14ebfa38e24acde9b7c946df70cb183af2cb5f0598f21ae6818
121+
jekyll-sitemap (1.4.0) sha256=0de08c5debc185ea5a8f980e1025c7cd3f8e0c35c8b6ef592f15c46235cf4218
122+
jekyll-tailwindcss (0.7.0) sha256=987eac000d0ef5a23b901927a34c9949066be3f7acd9729643e2f6afb4e30adf
121123
jekyll-watch (2.2.1) sha256=bc44ed43f5e0a552836245a54dbff3ea7421ecc2856707e8a1ee203a8387a7e1
122124
json (2.17.1.2) sha256=130dc7927f9484007107a4bcb2ebaa9523b973985f374686d5b2395d4143e2fa
123125
kramdown (2.5.1) sha256=87bbb6abd9d3cebe4fc1f33e367c392b4500e6f8fa19dd61c0972cf4afe7368c
124126
kramdown-parser-gfm (1.1.0) sha256=fb39745516427d2988543bf01fc4cf0ab1149476382393e0e9c48592f6581729
125127
liquid (4.0.4) sha256=4fcfebb1a045e47918388dbb7a0925e7c3893e58d2bd6c3b3c73ec17a2d8fdb3
126128
listen (3.9.0) sha256=db9e4424e0e5834480385197c139cb6b0ae0ef28cc13310cfd1ca78377d59c67
129+
logger (1.7.0) sha256=196edec7cc44b66cfb40f9755ce11b392f21f7967696af15d274dde7edff0203
127130
mercenary (0.4.0) sha256=b25a1e4a59adca88665e08e24acf0af30da5b5d859f7d8f38fba52c28f405138
128-
nio4r (2.7.5) sha256=6c90168e48fb5f8e768419c93abb94ba2b892a1d0602cb06eef16d8b7df1dca1
129131
pathutil (0.16.2) sha256=e43b74365631cab4f6d5e4228f812927efc9cb2c71e62976edcb252ee948d589
130132
public_suffix (7.0.5) sha256=1a8bb08f1bbea19228d3bed6e5ed908d1cb4f7c2726d18bd9cadf60bc676f623
131-
puma (6.6.1) sha256=b9b56e4a4ea75d1bfa6d9e1972ee2c9f43d0883f011826d914e8e37b3694ea1e
132-
rack (3.2.6) sha256=5ed78e1f73b2e25679bec7d45ee2d4483cc4146eb1be0264fc4d94cb5ef212c2
133-
rack-jekyll (0.5.0)
134133
rake (13.3.1) sha256=8c9e89d09f66a26a01264e7e3480ec0607f0c497a861ef16063604b1b08eb19c
135134
rb-fsevent (0.11.2) sha256=43900b972e7301d6570f64b850a5aa67833ee7d87b458ee92805d56b7318aefe
136135
rb-inotify (0.11.1) sha256=a0a700441239b0ff18eb65e3866236cd78613d6b9f78fea1f9ac47a85e47be6e
137136
rexml (3.4.4) sha256=19e0a2c3425dfbf2d4fc1189747bdb2f849b6c5e74180401b15734bc97b5d142
138137
rouge (4.6.1) sha256=5075346d5797d6864be93f7adc75a16047a7dbfa572c63c502419ffa582c77de
138+
ruby-vips (2.2.5) sha256=f3c547a172c36ba26b8614c809f5823bc6199623ec6204ec7c3bce29037f7758
139139
safe_yaml (1.0.5) sha256=a6ac2d64b7eb027bdeeca1851fe7e7af0d668e133e8a88066a0c6f7087d9f848
140-
sass (3.7.4) sha256=808b0d39053aa69068df939e24671fe84fd5a9d3314486e1a1457d0934a4255d
141140
sass-embedded (1.94.2) sha256=c5061699ec35fe34b182eab3df4fbe97729e90a8e0d9c247457ccb64ee0d99e6
142-
sass-listen (4.0.0) sha256=ae9dcb76dd3e234329e5ba6e213f48e532c5a3e7b0b4d8a87f13aaca0cc18377
141+
tailwindcss-ruby (4.2.2) sha256=ce66da7b01fb6ef1ad6485b4b8c3476fac959f3324894fd26ec7c67ab3996d30
142+
tailwindcss-ruby (4.2.2-arm64-darwin) sha256=2d66feba0c1ffca5b79246bd881bfb9a6b2298d57c4bc83ee3a8c3233df79d41
143143
terminal-table (3.0.2) sha256=f951b6af5f3e00203fb290a669e0a85c5dd5b051b3b023392ccfd67ba5abae91
144144
unicode-display_width (2.6.0) sha256=12279874bba6d5e4d2728cef814b19197dbb10d7a7837a869bab65da943b7f5a
145145
webrick (1.9.2) sha256=beb4a15fc474defed24a3bda4ffd88a490d517c9e4e6118c3edce59e45864131
146+
zeitwerk (2.7.5) sha256=d8da92128c09ea6ec62c949011b00ed4a20242b255293dd66bf41545398f73dd
146147

147148
RUBY VERSION
148149
ruby 3.4.7

_config.yml

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,42 @@
11
---
22
exclude:
33
- vendor
4-
safe: true
4+
- CLAUDE.md
5+
- AGENTS.md
56
markdown: kramdown
7+
timezone: UTC
68
url: https://blog.rubygems.org
9+
title: RubyGems Blog
10+
description: News and updates from the RubyGems team — releases, security advisories, and project announcements.
11+
12+
plugins:
13+
- jekyll-tailwindcss
14+
- jekyll-sitemap
15+
- jekyll-og-image
16+
17+
og_image:
18+
collections: ["posts", "pages"]
19+
output_dir: assets/images/og
20+
canvas:
21+
background_color: "#FFFFFF"
22+
header:
23+
color: "#262626"
24+
content:
25+
color: "#525252"
26+
border_bottom:
27+
width: 20
28+
fill:
29+
- "#F74C27"
30+
image:
31+
path: /images/blog-mark.png
32+
width: 360
33+
height: 56
34+
radius: 0
35+
gravity: se
36+
position:
37+
x: 60
38+
y: 87
39+
metadata:
40+
fields: ["author", "date"]
41+
separator: ""
42+
date_format: "%B %-d, %Y"

_data/authors.yml

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# Author profiles, keyed by primary email.
2+
#
3+
# Posts reference authors via `author:` and `author_email:` frontmatter.
4+
# When `author_email` matches a key here (or one of its `aliases`), the byline
5+
# renders the canonical name + URL + bio from this file, and the BlogPosting
6+
# JSON-LD surfaces `author.url` and `author.sameAs` for E-E-A-T / AI citation
7+
# signals. Posts whose email matches no entry fall back to the raw `author`
8+
# frontmatter string.
9+
#
10+
# Schema:
11+
# <primary-email>:
12+
# name: "Canonical Name" (required — overrides per-post `author` string)
13+
# url: "https://..." (optional — primary profile, e.g. GitHub)
14+
# bio: "Short bio." (optional — one-sentence bio shown under byline)
15+
# aliases: (optional — alternate emails this author uses)
16+
# - other@example.com
17+
# same_as: (optional — additional profile URLs for JSON-LD)
18+
# - "https://..."
19+
20+
hsbt@ruby-lang.org:
21+
name: "Hiroshi SHIBATA"
22+
url: "https://github.com/hsbt"
23+
bio: "Ruby core committer and RubyGems maintainer."
24+
25+
colby@rubygems.org:
26+
name: "Colby Swandale"
27+
url: "https://github.com/colby-swandale"
28+
bio: "Technical lead at RubyCentral."
29+
aliases:
30+
- me@colby.fyi

_includes/archive.html

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
<div class="post__link--posts-by-year l-col--l">
2-
<div class="nav--v">
1+
<nav aria-label="Archive" class="shrink-0 lg:w-48">
2+
<h3 class="text-sm font-bold text-neutral-700 uppercase tracking-wider mb-3">Archive</h3>
3+
<ul class="flex flex-row flex-wrap lg:flex-col gap-1 -mx-2">
34
{% for post in site.posts %}
45
{% assign index = true %}
56
{% assign truncated = true %}
@@ -8,8 +9,8 @@
89
{% capture next_year %}{{post.next.date | date: "%Y"}}{% endcapture %}
910

1011
{% if current_year != next_year %}
11-
<a class="nav--v__link" href="/#{{current_year}}">{{current_year}}</a>
12+
<li><a class="inline-block px-2 py-1.5 text-base text-neutral-700 rounded hover:bg-neutral-100 hover:text-orange-700 focus-visible:text-orange-700 focus-visible:outline-none focus-visible:underline transition-colors" href="/#{{current_year}}">{{current_year}}</a></li>
1213
{% endif %}
1314
{% endfor %}
14-
</div>
15-
</div>
15+
</ul>
16+
</nav>

0 commit comments

Comments
 (0)