Skip to content

lbngoc/releases-catalog

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

13 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

πŸ“¦ Releases Catalog

Live Demo Version License Build

Eleventy Vite TailwindCSS Alpine.js

A lightweight static release catalog for browsing versioned builds, changelogs, and downloadable artifacts.

Built with Eleventy, Vite, Alpine.js, and Tailwind CSS.


πŸ–Ό Screenshot

Releases Catalog Screenshot


✨ Overview

Releases Catalog is a static web application designed to:

  • List application releases from a CSV file
  • Dynamically load and render versioned changelogs
  • Provide downloadable build artifacts
  • Support deep-linking to specific releases
  • Work entirely without a backend

Perfect for:

  • Internal QA build portals
  • Client distribution pages
  • Open-source release hubs
  • Mobile APK / IPA distribution pages

πŸš€ Features

  • πŸ“„ Release metadata from catalog.csv
  • πŸ“ On-demand loading of CHANGELOG.md
  • πŸ”— Deep linking via #v=version.id
  • 🎯 Unique version identifiers (versionCode)
  • πŸ’Ύ Session-based changelog caching
  • πŸ”„ Per-release refresh (clear cache & reload)
  • πŸŒ— Dark mode with system preference detection and manual toggle
  • πŸ“± Fully responsive layout
  • ⚑ Client-side pagination
  • 🧩 Configurable via window.catalogConfig
  • πŸ— Relative paths β€” works in any subdirectory without config
  • 🧱 No backend required

πŸ›  Tech Stack


πŸ“‚ Project Structure

src/
β”œβ”€β”€ _includes/        # Layouts & Nunjucks partials
β”œβ”€β”€ assets/
β”‚   β”œβ”€β”€ main.js       # Vite entry
β”‚   β”œβ”€β”€ main.css      # Tailwind styles
β”‚   └── svg/          # Icons
β”œβ”€β”€ catalog/          # Alpine app logic
β”‚   β”œβ”€β”€ app.js
β”‚   β”œβ”€β”€ config.js
β”‚   β”œβ”€β”€ services.js
β”‚   └── utils.js
β”œβ”€β”€ releases/         # Version folders (CHANGELOG + artifacts)
β”œβ”€β”€ catalog.csv       # Release metadata (id, version, datetime)
β”œβ”€β”€ index.njk         # Entry template
└── favicon.svg

_site/                # Generated output

πŸ“„ Release Data Format

catalog.csv

#id,version,datetime
240823526,0.0.1,2024-08-23T10:00:00
260225100,0.0.2,2025-02-26T10:00:00

Each row generates a unique versionCode:

versionCode = `${version}.${id}`
// e.g. 0.0.2.260225100

This ensures unique deep-linking, stable cache keys, and no collision if versions repeat.


πŸ“ Release Folder Structure

Each release folder must match the version field:

releases/
└── 0.0.2/
    β”œβ”€β”€ CHANGELOG.md
    └── my-app-0.0.2.apk

πŸ”— Deep Linking

Link directly to a specific release:

https://example.com/#v=0.0.2.260225100

Behavior:

  • Automatically navigates to the correct page
  • Scrolls to and highlights the release
  • Expands the changelog section

When no hash is present, the latest release is automatically expanded without modifying the URL.


πŸŒ— Dark Mode

Dark mode is supported with:

  • System preference detection β€” follows prefers-color-scheme on first visit
  • Manual toggle β€” sun/moon button in the header
  • Persistent preference β€” stored in localStorage
  • No flash β€” inline script applies the class before CSS loads

πŸ— Subdirectory Deployment

All asset and data paths in the app use relative URLs (no leading /), so the site works out of the box when deployed under any subdirectory (e.g. https://example.com/myapp/) β€” no configuration or post-build edits needed.

Keep paths in config.js relative (catalog.csv, releases/..., assets/svg/...) to preserve this behavior. Absolute paths (starting with /) will bypass the subdirectory and break.


βš™ Configuration Override

Customize behavior by defining window.catalogConfig before the app loads. All methods have access to this (the merged config object), so this.releasesRelativePath and other properties are available inside any overridden function.

Configuration Options

Option Type Default Description
pageSize number 5 Releases per page
catalogCsv string "catalog.csv" Path or URL to catalog CSV file
releasesRelativePath string "releases" Base path/URL used by URL builder functions
getAssetIconUrl(asset) function β€” Icon URL for a given asset filename
getAssetDownloadUrl(version, asset) function β€” Download URL for an artifact
getAssetDownloadName(version, asset) function β€” Filename hint for download
getChangelogUrl(versionCode) function β€” URL for CHANGELOG.md
transformChangelogHtml(html) function β€” Post-process rendered changelog HTML

Same-host (relative paths)

Files are served alongside the static site. Relative paths are resolved by the browser from the current page URL, so subdirectory deployments work automatically without any config change.

Do not use a leading / β€” absolute paths ignore the deployment subdirectory and will break.

<script>
window.catalogConfig = {
  pageSize: 10,
  catalogCsv: "catalog.csv",        // relative to page URL
  releasesRelativePath: "releases",  // relative to page URL

  getAssetDownloadName(version, asset) {
    return `myapp-${version}.apk`;
  },

  transformChangelogHtml(html) {
    return html.replace(
      /\b([A-Z]+-\d+)\b/g,
      (match) => `<a href="https://your-jira/browse/${match}" target="_blank">${match}</a>`
    );
  }
};
</script>

CDN / External Storage

Full URLs (https://...) are used as-is by the browser. Setting catalogCsv and releasesRelativePath to full URLs is enough; the URL builder functions (getAssetDownloadUrl, getChangelogUrl) use this.releasesRelativePath automatically and require no override.

<script>
window.catalogConfig = {
  catalogCsv: "https://cdn.example.com/my-app/catalog.csv",
  releasesRelativePath: "https://cdn.example.com/my-app/releases",
};
</script>

CORS: The CDN must allow cross-origin requests (Access-Control-Allow-Origin) since catalog.csv and CHANGELOG.md are loaded via fetch().

Download: The HTML download attribute only works for same-origin URLs. For cross-origin assets, configure the CDN to send Content-Disposition: attachment to force a file download.


πŸ§ͺ Development

npm install
npm run dev

πŸ— Build

npm run build
# Output: _site/

πŸ“¦ Deployment

Static output in _site/ β€” deploy to any static host:

  • GitHub Pages
  • Netlify / Vercel / Cloudflare Pages
  • Any static hosting provider

No server required.


🧠 How It Works

  1. catalog.csv provides release metadata.
  2. Releases are paginated client-side.
  3. CHANGELOG files are fetched on demand and cached in sessionStorage.
  4. Markdown is parsed and rendered dynamically.
  5. UI state (active release, page) is driven by the URL hash (#v=).
  6. Dark mode state is managed via localStorage and a class on <html>.

🀝 Contributing

Pull requests are welcome. For major changes, please open an issue first.

About

A lightweight static release catalog for browsing versioned builds, changelogs, and downloadable artifacts.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors