Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 59 additions & 0 deletions .github/workflows/nightly-beta.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
name: Nightly Beta

on:
schedule:
- cron: '0 3 * * *'
workflow_dispatch:

jobs:
nightly-beta:
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main'
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Check for changes since last beta
id: check
run: |
LAST_BETA=$(git tag -l 'v*-beta*' --sort=-v:refname | head -n1)
LAST_RELEASE=$(git describe --tags --abbrev=0 --match 'v[0-9]*' --exclude '*-*' HEAD 2>/dev/null || echo "")
REF="${LAST_BETA:-${LAST_RELEASE}}"

if [ -n "$REF" ]; then
CHANGES=$(git log "${REF}..HEAD" --oneline --no-merges | grep -cv '\[skip ci\]' || true)
else
CHANGES=$(git log HEAD --oneline --no-merges | grep -cv '\[skip ci\]' || true)
fi

echo "changes=$CHANGES" >> $GITHUB_OUTPUT
echo "Changes since ${REF:-inception}: $CHANGES"

- name: Create beta tag and trigger release
if: steps.check.outputs.changes != '0'
run: |
BASE=$(git describe --tags --abbrev=0 --match 'v[0-9]*' --exclude '*-*' HEAD 2>/dev/null || echo "v0.1.0")
SHA=$(git rev-parse HEAD)

# Find next available beta number (API check handles ghost refs from deleted tags)
NUM=1
while gh api "repos/${{ github.repository }}/git/ref/tags/${BASE}-beta.${NUM}" --silent 2>/dev/null; do
NUM=$((NUM + 1))
done

# Create tag, retry with next number on conflict (ghost ref not visible via GET)
for i in $(seq 0 4); do
TAG="${BASE}-beta.$((NUM + i))"
if gh api "repos/${{ github.repository }}/git/refs" \
-f ref="refs/tags/${TAG}" -f sha="${SHA}" 2>/dev/null; then
echo "Created tag: ${TAG}"
gh workflow run release.yml -f "tag=${TAG}"
echo "Triggered release build"
exit 0
fi
done
echo "::error::Could not create beta tag"
exit 1
env:
GH_TOKEN: ${{ secrets.PAT_TOKEN }}
124 changes: 124 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
name: Package and Release

on:
push:
branches: [main]
tags: ['v*']
workflow_dispatch:
inputs:
tag:
description: 'Tag to build (e.g. v1.0.0-beta.1). Leave empty for alpha build.'
required: false

permissions:
contents: write

jobs:
release:
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/')
steps:
- uses: actions/checkout@v4
with:
ref: ${{ inputs.tag || github.ref }}
fetch-depth: 0

- name: Check if build is needed
id: guard
run: |
# Tags and workflow_dispatch always build
if [[ "$GITHUB_REF" == refs/tags/* ]] || [[ -n "${{ inputs.tag }}" ]] || [[ "$GITHUB_EVENT_NAME" == "workflow_dispatch" ]]; then
echo "skip=false" >> $GITHUB_OUTPUT
exit 0
fi

# Branch pushes: skip if only docs/CI files changed
DOMINATED=true
for f in $(git diff --name-only HEAD~1..HEAD 2>/dev/null); do
case "$f" in
*.md|*.sh|.github/*|.gitignore|.pkgmeta) ;;
*) DOMINATED=false; break ;;
esac
done
echo "skip=$DOMINATED" >> $GITHUB_OUTPUT

- name: Generate Changelog.lua
if: steps.guard.outputs.skip != 'true'
id: changelog
run: |
chmod +x generate_changelog.sh
if [[ "$GITHUB_REF" == refs/heads/* ]] && [[ -z "${{ inputs.tag }}" ]]; then
export FORCE_ALPHA=true
fi
./generate_changelog.sh

VERSION=$(grep 'DF.ADDON_VERSION' Changelog.lua | sed 's/.*= "\(.*\)"/\1/')
CHANNEL=$(grep 'DF.RELEASE_CHANNEL' Changelog.lua | sed 's/.*= "\(.*\)"/\1/')
echo "version=$VERSION" >> $GITHUB_OUTPUT
echo "channel=$CHANNEL" >> $GITHUB_OUTPUT

NOTES=$(awk '/^## / { count++; if (count > 1) exit } count >= 1 { print }' CHANGELOG.md | head -c 1800 | sed -e :a -e '/^[[:space:]-]*$/{ $d; N; ba; }')
{
echo "notes<<NOTES_EOF"
echo "$NOTES"
echo "NOTES_EOF"
} >> $GITHUB_OUTPUT

- name: Package and Release
if: steps.guard.outputs.skip != 'true'
uses: BigWigsMods/packager@v2
env:
CF_API_KEY: ${{ secrets.CF_API_KEY }}
GITHUB_OAUTH: ${{ secrets.GITHUB_TOKEN }}

- name: Notify Discord
if: steps.guard.outputs.skip != 'true' && success()
env:
DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }}
VERSION: ${{ steps.changelog.outputs.version }}
CHANNEL: ${{ steps.changelog.outputs.channel }}
NOTES: ${{ steps.changelog.outputs.notes }}
run: |
if [ -z "$DISCORD_WEBHOOK_URL" ]; then
echo "No Discord webhook configured, skipping."
exit 0
fi

case "$CHANNEL" in
release)
COLOR=3066993
TITLE="DandersFrames ${VERSION} — New Release"
FOOTER="Available on CurseForge"
;;
beta)
COLOR=16755200
TITLE="DandersFrames ${VERSION} — Beta"
FOOTER="Available on CurseForge (Beta channel)"
;;
*)
COLOR=9474192
TITLE="DandersFrames ${VERSION} — Alpha"
FOOTER="Available on CurseForge (Alpha channel)"
;;
esac

PAYLOAD=$(jq -n \
--arg title "$TITLE" \
--arg desc "$NOTES" \
--arg color "$COLOR" \
--arg footer "$FOOTER" \
--arg url "https://www.curseforge.com/wow/addons/danders-frames" \
'{
embeds: [{
title: $title,
description: $desc,
color: ($color | tonumber),
url: $url,
footer: { text: $footer }
}]
}')

curl -s -o /dev/null -w "%{http_code}" \
-H "Content-Type: application/json" \
-d "$PAYLOAD" \
"$DISCORD_WEBHOOK_URL"
13 changes: 13 additions & 0 deletions .pkgmeta
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package-as: DandersFrames
enable-nolib-creation: no

ignore:
- CHANGELOG.md
- README.md
- generate_changelog.sh
- .github
- .gitignore

manual-changelog:
filename: CHANGELOG.md
markup-type: markdown
29 changes: 29 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# DandersFrames Changelog

## [4.0.5] - 2026-02-14

### Bug Fixes
* Raid frames misaligned / anchoring broken
* Groups per row setting not working in live raids
* Arena/BG frames showing wrong layout after reload
* Arena health bars not updating after reload
* Leader change causes frames to disappear or misalign
* Menu bind ignores out-of-combat setting
* Boss aura font size defaulting to 200% instead of 100%
* Click casting profiles don't switch on spec change
* Clique not working on pet frames
* Absorb overlay doesn't fade when out of range
* Heal absorb and heal prediction bars don't fade when out of range
* Defensive icon flashes at wrong opacity when appearing
* Name text stays full opacity on out-of-range players
* Health text and status text stay full opacity on out-of-range players
* Name alpha resets after exiting test mode
* Glowy hand cursor after failed click cast spells
* Macro editing window gets stuck open when reopened
* Flat raid unlock mover sized incorrectly
* Fonts broken on non-English client languages

### New Features
* Click casting spec default profile option
* Group visibility options now available in flat raid mode
* Slider edit boxes accept precise decimal values for fine-tuned positioning and scaling
5 changes: 5 additions & 0 deletions Changelog.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
local addonName, DF = ...
DF.ADDON_VERSION = "dev"
DF.BUILD_DATE = "0000-00-00T00:00:00Z"
DF.RELEASE_CHANNEL = "alpha"
DF.CHANGELOG_TEXT = "Development version"
4 changes: 3 additions & 1 deletion DandersFrames.toc
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
## Notes: Custom party/raid frames for WoW Midnight 12.0
## X-Credits: Some optimization patterns informed by studying Grid2 and other community addons.
## Author: Danders
## Version: 4.0.5
## Version: @project-version@
## X-Curse-Project-ID: 1389690
## IconTexture: Interface\AddOns\DandersFrames\Media\DF_Icon
## SavedVariables: DandersFramesDB_v2, DandersFramesClickCastingDB
## SavedVariablesPerCharacter: DandersFramesCharDB
Expand All @@ -25,6 +26,7 @@ DandersFrames.xml

# Core
Config.lua
Changelog.lua
Profile.lua
ExportCategories.lua
Core.lua
Expand Down
94 changes: 91 additions & 3 deletions GUI/GUI.lua
Original file line number Diff line number Diff line change
Expand Up @@ -4328,7 +4328,10 @@ function DF:CreateGUI()

local title = titleBar:CreateFontString(nil, "OVERLAY", "GameFontNormal")
title:SetPoint("LEFT", 12, 0)
title:SetText("DandersFrames v" .. (DF.VERSION or "?"))
local versionStr = DF.ADDON_VERSION or DF.VERSION or "?"
local channelTags = { alpha = " |cffff8800alpha|r", beta = " |cffff8800beta|r" }
local channelTag = channelTags[DF.RELEASE_CHANNEL] or ""
title:SetText("DandersFrames " .. versionStr .. channelTag)
local c = GetThemeColor()
title:SetTextColor(c.r, c.g, c.b)
title.UpdateTheme = function()
Expand Down Expand Up @@ -4363,7 +4366,92 @@ function DF:CreateGUI()
closeIcon:SetVertexColor(C_TEXT_DIM.r, C_TEXT_DIM.g, C_TEXT_DIM.b)
end)
closeBtn:SetScript("OnClick", function() frame:Hide() end)


-- Info button (changelog)
local infoBtn = CreateFrame("Button", nil, frame, "BackdropTemplate")
infoBtn:SetSize(20, 20)
infoBtn:SetPoint("TOPRIGHT", -32, -5)
infoBtn:SetFrameStrata("FULLSCREEN_DIALOG")
infoBtn:SetFrameLevel(210)
infoBtn:SetBackdrop({
bgFile = "Interface\\Buttons\\WHITE8x8",
edgeFile = "Interface\\Buttons\\WHITE8x8",
edgeSize = 1,
})
infoBtn:SetBackdropColor(C_ELEMENT.r, C_ELEMENT.g, C_ELEMENT.b, 1)
infoBtn:SetBackdropBorderColor(C_BORDER.r, C_BORDER.g, C_BORDER.b, 0.5)
local infoIcon = infoBtn:CreateTexture(nil, "OVERLAY")
infoIcon:SetPoint("CENTER")
infoIcon:SetSize(12, 12)
infoIcon:SetTexture("Interface\\AddOns\\DandersFrames\\Media\\Icons\\info")
infoIcon:SetVertexColor(C_TEXT_DIM.r, C_TEXT_DIM.g, C_TEXT_DIM.b)
infoBtn:SetScript("OnEnter", function(self)
local tc = GetThemeColor()
self:SetBackdropBorderColor(tc.r, tc.g, tc.b, 1)
infoIcon:SetVertexColor(tc.r, tc.g, tc.b)
end)
infoBtn:SetScript("OnLeave", function(self)
self:SetBackdropBorderColor(C_BORDER.r, C_BORDER.g, C_BORDER.b, 0.5)
infoIcon:SetVertexColor(C_TEXT_DIM.r, C_TEXT_DIM.g, C_TEXT_DIM.b)
end)

-- Changelog overlay
local changelogOverlay = CreateFrame("Frame", nil, frame, "BackdropTemplate")
changelogOverlay:SetPoint("TOPLEFT", frame, "TOPLEFT", 12, -34)
changelogOverlay:SetPoint("BOTTOMRIGHT", frame, "BOTTOMRIGHT", -12, 36)
changelogOverlay:SetFrameStrata("FULLSCREEN_DIALOG")
changelogOverlay:SetFrameLevel(300)
CreatePanelBackdrop(changelogOverlay)
changelogOverlay:Hide()

local changelogTitle = changelogOverlay:CreateFontString(nil, "OVERLAY", "GameFontNormal")
changelogTitle:SetPoint("TOPLEFT", 12, -10)
changelogTitle:SetText("Changelog")
changelogTitle:SetTextColor(C_TEXT.r, C_TEXT.g, C_TEXT.b)

local backBtn = CreateFrame("Button", nil, changelogOverlay, "BackdropTemplate")
backBtn:SetSize(60, 22)
backBtn:SetPoint("TOPRIGHT", -8, -6)
CreateElementBackdrop(backBtn)
local backText = backBtn:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
backText:SetPoint("CENTER")
backText:SetText("Back")
backText:SetTextColor(C_TEXT.r, C_TEXT.g, C_TEXT.b)
backBtn:SetScript("OnEnter", function(self)
local tc = GetThemeColor()
self:SetBackdropBorderColor(tc.r, tc.g, tc.b, 1)
end)
backBtn:SetScript("OnLeave", function(self)
self:SetBackdropBorderColor(C_BORDER.r, C_BORDER.g, C_BORDER.b, 0.5)
end)
backBtn:SetScript("OnClick", function() changelogOverlay:Hide() end)

local changelogScroll = CreateFrame("ScrollFrame", nil, changelogOverlay, "UIPanelScrollFrameTemplate")
changelogScroll:SetPoint("TOPLEFT", 8, -34)
changelogScroll:SetPoint("BOTTOMRIGHT", -26, 8)

local changelogEdit = CreateFrame("EditBox", nil, changelogScroll)
changelogEdit:SetMultiLine(true)
changelogEdit:SetAutoFocus(false)
changelogEdit:SetFontObject(GameFontHighlightSmall)
changelogEdit:SetTextColor(C_TEXT_DIM.r, C_TEXT_DIM.g, C_TEXT_DIM.b)
changelogEdit:SetWidth(changelogScroll:GetWidth() or 500)
changelogEdit:SetText(DF.CHANGELOG_TEXT or "No changelog available.")
changelogEdit:SetCursorPosition(0)
changelogEdit:EnableMouse(true)
changelogEdit:SetScript("OnEscapePressed", function(self) self:ClearFocus() end)
changelogEdit:SetScript("OnEditFocusGained", function(self) self:HighlightText(0, 0) end)
changelogScroll:SetScrollChild(changelogEdit)

infoBtn:SetScript("OnClick", function()
if changelogOverlay:IsShown() then
changelogOverlay:Hide()
else
changelogEdit:SetWidth(changelogScroll:GetWidth())
changelogOverlay:Show()
end
end)

-- =========================================================================
-- RESIZE HANDLE (bottom-right corner)
-- =========================================================================
Expand Down Expand Up @@ -5051,7 +5139,7 @@ function DF:CreateGUI()
-- Version on the right
local versionText = footer:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
versionText:SetPoint("RIGHT", footer, "RIGHT", -2, 0)
versionText:SetText("v" .. (DF.VERSION or "?"))
versionText:SetText(versionStr .. channelTag)
versionText:SetTextColor(C_TEXT_DIM.r, C_TEXT_DIM.g, C_TEXT_DIM.b, 0.5)

-- Create the click casting UI content
Expand Down
Loading