Plan: Custom GitHub Star Badges

Plan: Custom GitHub Star Badges

Replace shields.io badges with custom-styled HTML that fetches star counts via client-side JavaScript with 24-hour localStorage caching.

Files to Modify

  1. utils/project_listings.jl - Replace shields.io badge with HTML placeholder

  2. _css/custom.css - Add star badge styles

  3. _layout/foot.html - Add JavaScript to fetch and display star counts

Implementation

  1. utils/project_listings.jl

Replace the shields.io image badge in project_listing() with a custom HTML structure:

function star_badge(r::Repo)
    return a(
        :href => url_stargazers(r),
        :class => "star-badge",
        Symbol("data-repo") => "$(name(org(r)))/$(name(r))",
        span(:class => "star-icon", "★"),
        span(:class => "star-count"),
    )
end

Update project_listing() to use star_badge(r) instead of the current img(:src => url_star_shield(r)) approach.

Remove url_star_shield() function (no longer needed).

  1. _css/custom.css

Add styles in the project badges section (after line 137):

.star-badge {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    color: var(--c-text-gray);
    font-size: 9pt;
    text-decoration: none !important;
    background: none !important;
}

.star-badge:hover {
    color: var(--c-text);
}

.star-icon {
    color: var(--c-yellow-2);
}

  1. _layout/foot.html

Add JavaScript before the closing </script> tag (around line 63):

// Fetch GitHub star counts
(function() {
    var badges = document.querySelectorAll('.star-badge[data-repo]');
    if (!badges.length) return;

    badges.forEach(function(badge) {
        var repo = badge.dataset.repo;
        var cacheKey = 'stars:' + repo;
        var cached = localStorage.getItem(cacheKey);

        if (cached) {
            var data = JSON.parse(cached);
            if (Date.now() - data.time < 86400000) {  // 24 hours
                badge.querySelector('.star-count').textContent = data.stars;
                return;
            }
        }

        fetch('https://api.github.com/repos/' + repo)
            .then(function(res) { return res.json(); })
            .then(function(data) {
                var stars = data.stargazers_count;
                badge.querySelector('.star-count').textContent = stars;
                localStorage.setItem(cacheKey, JSON.stringify({
                    stars: stars,
                    time: Date.now()
                }));
            })
            .catch(function() {
                badge.querySelector('.star-count').textContent = '—';
            });
    });
})();

Verification

  1. Run serve() locally

  2. Navigate to the projects page

  3. Verify star badges display with correct counts

  4. Check browser DevTools:

    • Network tab: GitHub API requests should fire

    • Application > Local Storage: stars:org/repo entries should appear

  5. Refresh page - stars should load from cache (no new API requests)

  6. Verify styling matches site theme in both light and dark mode

Code under MIT license, text CC BY-SA 4.0, Adrian Hill.
Built with ♥ using Franklin.jl and Julia.
Last modified on March 13, 2026.
Impressum.