# Design: packages.danix.xyz Shortcodes

**Date:** 2026-05-14
**Status:** Approved

## Overview

Two Alpine.js shortcodes for the repository page that fetch live data from `packages.danix.xyz` and render it in the browser. Data updates on every page load without a site rebuild.

## Prerequisites

### CORS (manual step — not in theme)

Add to Apache config on `packages.danix.xyz`:

```apache
Header set Access-Control-Allow-Origin "https://danix.xyz"
```

Without this header, browser fetch from `danix.xyz` will be blocked by CORS policy.

---

## Shortcode 1: `pkg-list`

### Usage

```
{{< pkg-list >}}
```

No parameters. Fetches from hardcoded `https://packages.danix.xyz/PACKAGES.TXT`.

### File

`themes/danix-xyz-hacker/layouts/shortcodes/pkg-list.html`

### Behavior

- On mount, Alpine fetches `PACKAGES.TXT` via `fetch()`
- Parses repeating blocks: extracts `PACKAGE NAME` and `PACKAGE LOCATION` lines
- Parses filename to extract short name and version:
  - Input: `waybar-0.14.0-x86_64-2_danix.txz`
  - Output: name=`waybar`, version=`0.14.0`
- Derives category and folder link from `PACKAGE LOCATION` (e.g. `./desktop/waybar` → `https://packages.danix.xyz/desktop/waybar/`)
- Renders a filterable table

### Table columns

| Name | Version | Link |
|------|---------|------|
| waybar | 0.14.0 | → packages.danix.xyz/desktop/waybar/ |

- **Name**: parsed short name (before first version segment)
- **Version**: first version segment from filename
- **Link**: anchor pointing to folder on packages.danix.xyz, label is `category/name`

### Filter

Text input above table. Filters by name, client-side, no server round-trips.

### States

1. **Loading**: spinner + i18n loading string
2. **Loaded**: filter input + table
3. **Error**: styled error block + fallback link to `https://packages.danix.xyz`

### i18n keys (new)

```yaml
pkg_list_loading: "Loading packages..."       # it: "Caricamento pacchetti..."
pkg_list_error: "Could not load packages."    # it: "Impossibile caricare i pacchetti."
pkg_list_filter: "Filter packages..."         # it: "Filtra pacchetti..."
pkg_list_link_label: "View"                   # it: "Visualizza"
```

---

## Shortcode 2: `pkg-changelog`

### Usage

```
{{< pkg-changelog count="10" >}}
```

`count`: number of entries to display. Default: `10`.

### File

`themes/danix-xyz-hacker/layouts/shortcodes/pkg-changelog.html`

### Behavior

- On mount, Alpine fetches `https://packages.danix.xyz/ChangeLog.txt` via `fetch()`
- Splits on `+--------------------------+` delimiter to get individual entries
- Discards empty chunks; takes first N (from `count` param rendered into `x-data`)
- Each chunk: first non-empty line = timestamp, remaining lines = change description

### Timeline rendering

Vertical timeline with purple accent dots (theme `primaryAccent` color `#a855f7`):

```
│
◉  Thu May 14 17:17:42 UTC 2026
│  personal/python3-platformdirs/...: Updated for git 7836e58
│
◉  Thu May 14 17:02:54 UTC 2026
│  personal/nvchecker/...: Added version 2.20.
```

- Dot: `◉` or CSS circle marker, purple accent color
- Timestamp: bold, readable date
- Change text: monospace, preserves whitespace/line breaks from source

### States

1. **Loading**: spinner + i18n loading string
2. **Loaded**: timeline
3. **Error**: styled error block + fallback link to `https://packages.danix.xyz/ChangeLog.txt`

### i18n keys (new)

```yaml
pkg_changelog_loading: "Loading changelog..."     # it: "Caricamento changelog..."
pkg_changelog_error: "Could not load changelog."  # it: "Impossibile caricare il changelog."
```

---

## File Checklist

| File | Action |
|------|--------|
| `themes/danix-xyz-hacker/layouts/shortcodes/pkg-list.html` | Create |
| `themes/danix-xyz-hacker/layouts/shortcodes/pkg-changelog.html` | Create |
| `themes/danix-xyz-hacker/i18n/en.yaml` | Add i18n keys |
| `themes/danix-xyz-hacker/i18n/it.yaml` | Add i18n keys |
| `packages.danix.xyz` Apache config | Add CORS header (manual) |
| `content/en/repository/index.md` | Add shortcode calls |
| `content/it/repository/index.md` | Add shortcode calls |

## Out of Scope

- CSS rebuild (`npm run build`) required if shortcodes introduce Tailwind classes not already in `main.min.css`; use existing utility classes where possible to avoid this
- No new JS files — logic lives inline in shortcode templates
- No sorting (filter only for pkg-list)
- No pagination (count param caps changelog entries)
