diff --git a/.gitea/actions/generate-docs/action.yml b/.gitea/actions/generate-docs/action.yml
index d548d63..de73a66 100644
--- a/.gitea/actions/generate-docs/action.yml
+++ b/.gitea/actions/generate-docs/action.yml
@@ -1,271 +1,275 @@
-name: "Generate Documentation"
-description: "Generate README index and per-skin markdown pages"
-
-inputs:
- new_tag:
- description: "The new tag for this build"
- required: true
- readme_path:
- description: "Path to write README.md"
- required: true
- doc_dir:
- description: "Directory to write per-skin markdown pages"
- required: true
-
-runs:
- using: "composite"
- steps:
- - name: Generate README
- shell: bash
- run: |
- echo "Generating README index…"
-
- sanitize_filename() {
- echo "$1" | \
- tr -d '\000-\037' | \
- sed -e 's#[\\/:\*\?"<>|]#-#g' | \
- sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//'
- }
-
- url_encode_path() {
- local IFS='/'
- local parts=($1)
- local encoded=""
- for part in "${parts[@]}"; do
- [ -n "$encoded" ] && encoded+="/"
- encoded+=$(printf '%s' "$part" | jq -sRr @uri)
- done
- echo "$encoded"
- }
-
- SKINS_JSON_FILE="${{ github.workspace }}/.gitea/workflows/skins.json"
- DESC_FILE=$(mktemp)
-
- echo "---" > "${{ inputs.readme_path }}"
- echo "gitea: none" >> "${{ inputs.readme_path }}"
- echo "include_toc: true" >> "${{ inputs.readme_path }}"
- echo "---" >> "${{ inputs.readme_path }}"
- echo "" >> "${{ inputs.readme_path }}"
- echo "# Skins" >> "${{ inputs.readme_path }}"
- echo "" >> "${{ inputs.readme_path }}"
- echo "" >> "${{ inputs.readme_path }}"
- echo "" >> "${{ inputs.readme_path }}"
- echo "**Go back to [osc/skins]($REGISTRY_URL/osc/skins)**" >> "${{ inputs.readme_path }}"
- echo "" >> "${{ inputs.readme_path }}"
- echo "**Click on the Skin name to download it, or click on the thumbnail to see more about the skin, including a video preview, screenshots, and mod icons.**" >> "${{ inputs.readme_path }}"
- echo "" >> "${{ inputs.readme_path }}"
-
- jq -r '.descriptions | to_entries[] | "\(.key)=\(.value)"' "$SKINS_JSON_FILE" > "$DESC_FILE"
- jq -r '.order[]?' "$SKINS_JSON_FILE" > order.txt
-
- get_desc() {
- grep -F -m1 -- "$1=" "$DESC_FILE" 2>/dev/null | cut -d '=' -f2- || true
- }
-
- declare -A ordered
- while IFS= read -r skin; do
- [ "$skin" = "default-skin" ] && continue
- ordered["$skin"]=1
- dir="$DANSER_SKINS_DIR/$skin"
- [ ! -d "$dir" ] && continue
-
- ini_file=$(find "$dir" -maxdepth 1 -iname "skin.ini" | head -n1 || true)
- skin_header="$skin"
-
- if [ -f "$ini_file" ]; then
- name_line=$(grep -a -i -m1 'Name[[:space:]]*:' "$ini_file" || true)
- if [ -n "$name_line" ]; then
- val="${name_line#*:}"
- val="$(echo "$val" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')"
- [ -n "$val" ] && skin_header=$(sanitize_filename "$val")
- fi
- else
- continue
- fi
-
- raw_path="$(printf "%s/%s" "$skin" "$skin_header" | sed 's/^ *//;s/ *$//')"
- base_path=$(url_encode_path "$raw_path")
-
- echo "## [$skin_header]($REGISTRY_URL/$USER_REPOSITORY/media/tag/${{ inputs.new_tag }}/export/${base_path}.osk)" >> "${{ inputs.readme_path }}"
- echo "" >> "${{ inputs.readme_path }}"
-
- desc=$(get_desc "$skin")
- [ -n "$desc" ] && { echo "$desc" >> "${{ inputs.readme_path }}"; echo "" >> "${{ inputs.readme_path }}"; }
-
- if [ -f "$ini_file" ]; then
- author_line=$(grep -i '^[[:space:]]*Author:' "$ini_file" | head -n1 || true)
- if [ -n "$author_line" ]; then
- author=$(echo "$author_line" | cut -d ':' -f2- | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
- [ -n "$author" ] && { echo "**Author:** $author" >> "${{ inputs.readme_path }}"; echo "" >> "${{ inputs.readme_path }}"; }
- fi
- fi
-
- echo "[](/docs/${base_path}.md)" >> "${{ inputs.readme_path }}"
- echo "" >> "${{ inputs.readme_path }}"
- done < order.txt
-
- for dir in "$DANSER_SKINS_DIR"/*; do
- [ -d "$dir" ] || continue
- skin="$(basename "$dir")"
- [ "$skin" = "default-skin" ] && continue
- [[ -n "${ordered[$skin]}" ]] && continue
-
- ini_file=$(find "$dir" -maxdepth 1 -iname "skin.ini" | head -n1 || true)
- skin_header="$skin"
-
- if [ -f "$ini_file" ]; then
- name_line=$(grep -a -i -m1 'Name[[:space:]]*:' "$ini_file" || true)
- if [ -n "$name_line" ]; then
- val="${name_line#*:}"
- val="$(echo "$val" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')"
- [ -n "$val" ] && skin_header=$(sanitize_filename "$val")
- fi
- else
- continue
- fi
-
- raw_path="$(printf "%s/%s" "$skin" "$skin_header" | sed 's/^ *//;s/ *$//')"
- base_path=$(url_encode_path "$raw_path")
-
- echo "## [$skin_header]($REGISTRY_URL/$USER_REPOSITORY/media/tag/${{ inputs.new_tag }}/export/${base_path}.osk)" >> "${{ inputs.readme_path }}"
- echo "" >> "${{ inputs.readme_path }}"
-
- if [ -f "$ini_file" ]; then
- author_line=$(grep -i '^[[:space:]]*Author:' "$ini_file" | head -n1 || true)
- if [ -n "$author_line" ]; then
- author=$(echo "$author_line" | cut -d ':' -f2- | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
- [ -n "$author" ] && { echo "**Author:** $author" >> "${{ inputs.readme_path }}"; echo "" >> "${{ inputs.readme_path }}"; }
- fi
- fi
-
- echo "[](/docs/${base_path}.md)" >> "${{ inputs.readme_path }}"
- echo "" >> "${{ inputs.readme_path }}"
- done
-
- echo "# Build History" >> "${{ inputs.readme_path }}"
- echo "" >> "${{ inputs.readme_path }}"
- echo "| Version | Date |" >> "${{ inputs.readme_path }}"
- echo "| ------- | ---- |" >> "${{ inputs.readme_path }}"
-
- current_commit_date=$(TZ="Europe/Zurich" date -d "$(git log -1 --format=%cI)" "+%d.%m.%Y %H:%M:%S")
- echo "| [\`${{ inputs.new_tag }} (Current)\`]($REGISTRY_URL/$USER_REPOSITORY/src/tag/${{ inputs.new_tag }}/README.md) | $current_commit_date |" >> "${{ inputs.readme_path }}"
-
- old_tags=$(git tag --sort=-v:refname | grep -v "^${{ inputs.new_tag }}$" | grep -E '^v[0-9]+\.[0-9]+\.[0-9]+$' || true)
- if [ -n "$old_tags" ]; then
- echo "$old_tags" | while read -r tag; do
- tag_date=$(git log -1 --format=%ci "$tag")
- formatted_date=$(TZ="Europe/Zurich" date -d "$tag_date" "+%d.%m.%Y %H:%M:%S")
- echo "| [\`$tag\`]($REGISTRY_URL/$USER_REPOSITORY/src/tag/$tag/README.md) | $formatted_date |" >> "${{ inputs.readme_path }}"
- done
- fi
-
- echo "README index generated successfully."
-
- - name: Generate Per-Skin Pages
- shell: bash
- run: |
- echo "Generating detailed per-skin markdown pages…"
-
- sanitize_filename() {
- echo "$1" | \
- tr -d '\000-\037' | \
- sed -e 's#[\\/:\*\?"<>|]#-#g' | \
- sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//'
- }
-
- url_encode_path() {
- local IFS='/'
- local parts=($1)
- local encoded=""
- for part in "${parts[@]}"; do
- [ -n "$encoded" ] && encoded+="/"
- encoded+=$(printf '%s' "$part" | jq -sRr @uri)
- done
- echo "$encoded"
- }
-
- mkdir -p "${{ inputs.doc_dir }}"
-
- for dir in "$DANSER_SKINS_DIR"/*; do
- [ -d "$dir" ] || continue
-
- skin=$(basename "$dir")
- [ "$skin" = "default-skin" ] && continue
- ini_file=$(find "$dir" -maxdepth 1 -iname "skin.ini" | head -n1 || true)
- skin_header="$skin"
-
- if [ -f "$ini_file" ]; then
- line=$(grep -i '^[[:space:]]*Name:' "$ini_file" | head -n1 || true)
- if [ -n "$line" ]; then
- val="${line#*:}"
- val="$(echo "$val" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')"
- if [ -n "$val" ]; then
- skin_header=$(sanitize_filename "$val")
- fi
- fi
- fi
-
- raw_path="${skin}/${skin_header}"
- base_path=$(url_encode_path "$raw_path")
- osk_url="$REGISTRY_URL/$USER_REPOSITORY/media/tag/${{ inputs.new_tag }}/export/${base_path}.osk"
- md_file_path="${{ inputs.doc_dir }}/${raw_path}.md"
-
- mkdir -p "$(dirname "$md_file_path")"
-
- video_url="$REGISTRY_URL/$USER_REPOSITORY/media/tag/${{ inputs.new_tag }}/media/gameplay/${base_path}.mp4"
-
- author=""
- if [ -f "$ini_file" ]; then
- author_line=$(grep -i '^[[:space:]]*Author:' "$ini_file" | head -n1 || true)
- if [ -n "$author_line" ]; then
- author=$(echo "$author_line" | cut -d ':' -f2- | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
- fi
- fi
-
- {
- echo "# [$skin_header]($osk_url)"
- echo ""
- [ -n "$author" ] && echo "**Author:** $author"
- [ -n "$author" ] && echo ""
-
- echo "## Hitsounds"
- echo ""
- echo ""
-
- echo "## Ranking Panel"
- echo ""
- echo ""
-
- echo "## Mod Icons"
- echo ""
-
- echo ""
- echo "## Build History"
- echo ""
- echo "| Version | Date |"
- echo "| ------- | ---- |"
-
- current_commit_date=$(TZ="Europe/Zurich" date -d "$(git log -1 --format=%cI)" "+%d.%m.%Y %H:%M:%S")
- echo "| [\`${{ inputs.new_tag }} (Current)\`]($REGISTRY_URL/$USER_REPOSITORY/src/tag/${{ inputs.new_tag }}/docs/${base_path}.md) | $current_commit_date |"
-
- old_tags=$(git tag --sort=-v:refname | grep -v "^${{ inputs.new_tag }}$" | grep -E '^v[0-9]+\.[0-9]+\.[0-9]+$' || true)
- if [ -n "$old_tags" ]; then
- echo "$old_tags" | while read -r tag; do
- raw_osk_path="export/${skin}/${skin_header}.osk"
- if git ls-tree -r --name-only "$tag" | grep -Fx -- "$raw_osk_path" >/dev/null; then
- tag_date=$(git log -1 --format=%ci "$tag")
- formatted_date=$(TZ="Europe/Zurich" date -d "$tag_date" "+%d.%m.%Y %H:%M:%S")
- echo "| [\`$tag\`]($REGISTRY_URL/$USER_REPOSITORY/src/tag/$tag/docs/${base_path}.md) | $formatted_date |"
- fi
- done
- fi
-
- } > "$md_file_path"
-
- echo " → Wrote $md_file_path"
- done
-
- echo "Per-skin markdown pages complete."
+name: "Generate Documentation"
+description: "Generate README index and per-skin markdown pages"
+
+inputs:
+ new_tag:
+ description: "The new tag for this build"
+ required: true
+ readme_path:
+ description: "Path to write README.md"
+ required: true
+ doc_dir:
+ description: "Directory to write per-skin markdown pages"
+ required: true
+ user_repository:
+ description: "Path of the repository (relative inside container)"
+ required: true
+
+
+runs:
+ using: "composite"
+ steps:
+ - name: Generate README
+ shell: bash
+ run: |
+ echo "Generating README index…"
+
+ sanitize_filename() {
+ echo "$1" | \
+ tr -d '\000-\037' | \
+ sed -e 's#[\\/:\*\?"<>|]#-#g' | \
+ sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//'
+ }
+
+ url_encode_path() {
+ local IFS='/'
+ local parts=($1)
+ local encoded=""
+ for part in "${parts[@]}"; do
+ [ -n "$encoded" ] && encoded+="/"
+ encoded+=$(printf '%s' "$part" | jq -sRr @uri)
+ done
+ echo "$encoded"
+ }
+
+ SKINS_JSON_FILE="${{ github.workspace }}/.gitea/workflows/skins.json"
+ DESC_FILE=$(mktemp)
+
+ echo "---" > "${{ inputs.readme_path }}"
+ echo "gitea: none" >> "${{ inputs.readme_path }}"
+ echo "include_toc: true" >> "${{ inputs.readme_path }}"
+ echo "---" >> "${{ inputs.readme_path }}"
+ echo "" >> "${{ inputs.readme_path }}"
+ echo "# Skins" >> "${{ inputs.readme_path }}"
+ echo "" >> "${{ inputs.readme_path }}"
+ echo "" >> "${{ inputs.readme_path }}"
+ echo "" >> "${{ inputs.readme_path }}"
+ echo "**Go back to [osc/skins]($REGISTRY_URL/osc/skins)**" >> "${{ inputs.readme_path }}"
+ echo "" >> "${{ inputs.readme_path }}"
+ echo "**Click on the Skin name to download it, or click on the thumbnail to see more about the skin, including a video preview, screenshots, and mod icons.**" >> "${{ inputs.readme_path }}"
+ echo "" >> "${{ inputs.readme_path }}"
+
+ jq -r '.descriptions | to_entries[] | "\(.key)=\(.value)"' "$SKINS_JSON_FILE" > "$DESC_FILE"
+ jq -r '.order[]?' "$SKINS_JSON_FILE" > order.txt
+
+ get_desc() {
+ grep -F -m1 -- "$1=" "$DESC_FILE" 2>/dev/null | cut -d '=' -f2- || true
+ }
+
+ declare -A ordered
+ while IFS= read -r skin; do
+ [ "$skin" = "default-skin" ] && continue
+ ordered["$skin"]=1
+ dir="$DANSER_SKINS_DIR/$skin"
+ [ ! -d "$dir" ] && continue
+
+ ini_file=$(find "$dir" -maxdepth 1 -iname "skin.ini" | head -n1 || true)
+ skin_header="$skin"
+
+ if [ -f "$ini_file" ]; then
+ name_line=$(grep -a -i -m1 'Name[[:space:]]*:' "$ini_file" || true)
+ if [ -n "$name_line" ]; then
+ val="${name_line#*:}"
+ val="$(echo "$val" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')"
+ [ -n "$val" ] && skin_header=$(sanitize_filename "$val")
+ fi
+ else
+ continue
+ fi
+
+ raw_path="$(printf "%s/%s" "$skin" "$skin_header" | sed 's/^ *//;s/ *$//')"
+ base_path=$(url_encode_path "$raw_path")
+
+ echo "## [$skin_header]($REGISTRY_URL/${{ inputs.user_repository }}/media/tag/${{ inputs.new_tag }}/export/${base_path}.osk)" >> "${{ inputs.readme_path }}"
+ echo "" >> "${{ inputs.readme_path }}"
+
+ desc=$(get_desc "$skin")
+ [ -n "$desc" ] && { echo "$desc" >> "${{ inputs.readme_path }}"; echo "" >> "${{ inputs.readme_path }}"; }
+
+ if [ -f "$ini_file" ]; then
+ author_line=$(grep -i '^[[:space:]]*Author:' "$ini_file" | head -n1 || true)
+ if [ -n "$author_line" ]; then
+ author=$(echo "$author_line" | cut -d ':' -f2- | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
+ [ -n "$author" ] && { echo "**Author:** $author" >> "${{ inputs.readme_path }}"; echo "" >> "${{ inputs.readme_path }}"; }
+ fi
+ fi
+
+ echo "[](/docs/${base_path}.md)" >> "${{ inputs.readme_path }}"
+ echo "" >> "${{ inputs.readme_path }}"
+ done < order.txt
+
+ for dir in "$DANSER_SKINS_DIR"/*; do
+ [ -d "$dir" ] || continue
+ skin="$(basename "$dir")"
+ [ "$skin" = "default-skin" ] && continue
+ [[ -n "${ordered[$skin]}" ]] && continue
+
+ ini_file=$(find "$dir" -maxdepth 1 -iname "skin.ini" | head -n1 || true)
+ skin_header="$skin"
+
+ if [ -f "$ini_file" ]; then
+ name_line=$(grep -a -i -m1 'Name[[:space:]]*:' "$ini_file" || true)
+ if [ -n "$name_line" ]; then
+ val="${name_line#*:}"
+ val="$(echo "$val" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')"
+ [ -n "$val" ] && skin_header=$(sanitize_filename "$val")
+ fi
+ else
+ continue
+ fi
+
+ raw_path="$(printf "%s/%s" "$skin" "$skin_header" | sed 's/^ *//;s/ *$//')"
+ base_path=$(url_encode_path "$raw_path")
+
+ echo "## [$skin_header]($REGISTRY_URL/${{ inputs.user_repository }}/media/tag/${{ inputs.new_tag }}/export/${base_path}.osk)" >> "${{ inputs.readme_path }}"
+ echo "" >> "${{ inputs.readme_path }}"
+
+ if [ -f "$ini_file" ]; then
+ author_line=$(grep -i '^[[:space:]]*Author:' "$ini_file" | head -n1 || true)
+ if [ -n "$author_line" ]; then
+ author=$(echo "$author_line" | cut -d ':' -f2- | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
+ [ -n "$author" ] && { echo "**Author:** $author" >> "${{ inputs.readme_path }}"; echo "" >> "${{ inputs.readme_path }}"; }
+ fi
+ fi
+
+ echo "[](/docs/${base_path}.md)" >> "${{ inputs.readme_path }}"
+ echo "" >> "${{ inputs.readme_path }}"
+ done
+
+ echo "# Build History" >> "${{ inputs.readme_path }}"
+ echo "" >> "${{ inputs.readme_path }}"
+ echo "| Version | Date |" >> "${{ inputs.readme_path }}"
+ echo "| ------- | ---- |" >> "${{ inputs.readme_path }}"
+
+ current_commit_date=$(TZ="Europe/Zurich" date -d "$(git log -1 --format=%cI)" "+%d.%m.%Y %H:%M:%S")
+ echo "| [\`${{ inputs.new_tag }} (Current)\`]($REGISTRY_URL/${{ inputs.user_repository }}/src/tag/${{ inputs.new_tag }}/README.md) | $current_commit_date |" >> "${{ inputs.readme_path }}"
+
+ old_tags=$(git tag --sort=-v:refname | grep -v "^${{ inputs.new_tag }}$" | grep -E '^v[0-9]+\.[0-9]+\.[0-9]+$' || true)
+ if [ -n "$old_tags" ]; then
+ echo "$old_tags" | while read -r tag; do
+ tag_date=$(git log -1 --format=%ci "$tag")
+ formatted_date=$(TZ="Europe/Zurich" date -d "$tag_date" "+%d.%m.%Y %H:%M:%S")
+ echo "| [\`$tag\`]($REGISTRY_URL/${{ inputs.user_repository }}/src/tag/$tag/README.md) | $formatted_date |" >> "${{ inputs.readme_path }}"
+ done
+ fi
+
+ echo "README index generated successfully."
+
+ - name: Generate Per-Skin Pages
+ shell: bash
+ run: |
+ echo "Generating detailed per-skin markdown pages…"
+
+ sanitize_filename() {
+ echo "$1" | \
+ tr -d '\000-\037' | \
+ sed -e 's#[\\/:\*\?"<>|]#-#g' | \
+ sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//'
+ }
+
+ url_encode_path() {
+ local IFS='/'
+ local parts=($1)
+ local encoded=""
+ for part in "${parts[@]}"; do
+ [ -n "$encoded" ] && encoded+="/"
+ encoded+=$(printf '%s' "$part" | jq -sRr @uri)
+ done
+ echo "$encoded"
+ }
+
+ mkdir -p "${{ inputs.doc_dir }}"
+
+ for dir in "$DANSER_SKINS_DIR"/*; do
+ [ -d "$dir" ] || continue
+
+ skin=$(basename "$dir")
+ [ "$skin" = "default-skin" ] && continue
+ ini_file=$(find "$dir" -maxdepth 1 -iname "skin.ini" | head -n1 || true)
+ skin_header="$skin"
+
+ if [ -f "$ini_file" ]; then
+ line=$(grep -i '^[[:space:]]*Name:' "$ini_file" | head -n1 || true)
+ if [ -n "$line" ]; then
+ val="${line#*:}"
+ val="$(echo "$val" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')"
+ if [ -n "$val" ]; then
+ skin_header=$(sanitize_filename "$val")
+ fi
+ fi
+ fi
+
+ raw_path="${skin}/${skin_header}"
+ base_path=$(url_encode_path "$raw_path")
+ osk_url="$REGISTRY_URL/${{ inputs.user_repository }}/media/tag/${{ inputs.new_tag }}/export/${base_path}.osk"
+ md_file_path="${{ inputs.doc_dir }}/${raw_path}.md"
+
+ mkdir -p "$(dirname "$md_file_path")"
+
+ video_url="$REGISTRY_URL/${{ inputs.user_repository }}/media/tag/${{ inputs.new_tag }}/media/gameplay/${base_path}.mp4"
+
+ author=""
+ if [ -f "$ini_file" ]; then
+ author_line=$(grep -i '^[[:space:]]*Author:' "$ini_file" | head -n1 || true)
+ if [ -n "$author_line" ]; then
+ author=$(echo "$author_line" | cut -d ':' -f2- | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
+ fi
+ fi
+
+ {
+ echo "# [$skin_header]($osk_url)"
+ echo ""
+ [ -n "$author" ] && echo "**Author:** $author"
+ [ -n "$author" ] && echo ""
+
+ echo "## Hitsounds"
+ echo ""
+ echo ""
+
+ echo "## Ranking Panel"
+ echo ""
+ echo ""
+
+ echo "## Mod Icons"
+ echo ""
+
+ echo ""
+ echo "## Build History"
+ echo ""
+ echo "| Version | Date |"
+ echo "| ------- | ---- |"
+
+ current_commit_date=$(TZ="Europe/Zurich" date -d "$(git log -1 --format=%cI)" "+%d.%m.%Y %H:%M:%S")
+ echo "| [\`${{ inputs.new_tag }} (Current)\`]($REGISTRY_URL/${{ inputs.user_repository }}/src/tag/${{ inputs.new_tag }}/docs/${base_path}.md) | $current_commit_date |"
+
+ old_tags=$(git tag --sort=-v:refname | grep -v "^${{ inputs.new_tag }}$" | grep -E '^v[0-9]+\.[0-9]+\.[0-9]+$' || true)
+ if [ -n "$old_tags" ]; then
+ echo "$old_tags" | while read -r tag; do
+ raw_osk_path="export/${skin}/${skin_header}.osk"
+ if git ls-tree -r --name-only "$tag" | grep -Fx -- "$raw_osk_path" >/dev/null; then
+ tag_date=$(git log -1 --format=%ci "$tag")
+ formatted_date=$(TZ="Europe/Zurich" date -d "$tag_date" "+%d.%m.%Y %H:%M:%S")
+ echo "| [\`$tag\`]($REGISTRY_URL/${{ inputs.user_repository }}/src/tag/$tag/docs/${base_path}.md) | $formatted_date |"
+ fi
+ done
+ fi
+
+ } > "$md_file_path"
+
+ echo " → Wrote $md_file_path"
+ done
+
+ echo "Per-skin markdown pages complete."