HerdosUI Party

re-order (and re-color) party frames

이 스크립트를 설치하려면 Tampermonkey, Greasemonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey와 같은 확장 프로그램을 설치해야 합니다.

이 스크립트를 설치하려면 Tampermonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey 또는 Userscripts와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 유저 스크립트 관리자 확장 프로그램이 필요합니다.

(이미 유저 스크립트 관리자가 설치되어 있습니다. 설치를 진행합니다!)

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

(이미 유저 스타일 관리자가 설치되어 있습니다. 설치를 진행합니다!)

// ==UserScript==
// @name         HerdosUI Party
// @namespace    https://hordes.io/
// @version      2026-03-01
// @description  re-order (and re-color) party frames
// @author       Anwohner
// @match        *://hordes.io/play*
// @icon         https://hordes.io/data/ui/favicon32.png
// @grant        GM_addStyle
// @run-at       document-end
// ==/UserScript==

'use strict'

GM_addStyle(`
.partyframes {
    .iconcontainer { display: none; }
    position: absolute;
    left: 60px;
    top: 60px;
}
`)

const state = {}

const observer = new MutationObserver((records) => {
    for (const record of records) {
        for (const node of record.addedNodes) {
            if (node.nodeType !== Node.ELEMENT_NODE) continue
            if (node.classList.contains('layout')) return reload()
            if (!node.dataset.sort && node.classList.contains('grid') &&
                node.parentNode.classList.contains('partyframes')) {
                onFrame(node)
                sortFrames(node.parentNode)
            }
        }
    }
})

const init = () => {
    console.log('HerdosUI Party')
    observer.observe(document.body, {
        childList: true
    })
}

window.addEventListener('load', init)

const reload = () => {
    const partyframes = document.querySelector('.partyframes')
    partyframes.querySelectorAll('.grid').forEach(node => onFrame(node))
    sortFrames(partyframes)
    observer.observe(partyframes, {
        childList: true
    })
}

const onFrame = (node) => {
    if (!state.player) state.player = document.querySelector('#ufplayer .bar:not(.dark) .progressBar span.left')?.textContent
    const icon = node.querySelector('.iconcontainer img.icon[src]')
    const pcls = parseInt(icon.src.split('/').pop())
    const pbar = node.querySelector('.bars > .barsInner > div:nth-child(1) > .progressBar')
    const name = pbar.querySelector('span.left')?.textContent
    const offl = pbar.querySelector('span.right')?.textContent === 'offline'
    if (name == state.player) {
        node.dataset.sort = 9
        pbar.style.background = `var(--primary)`
    } else if (offl) {
        node.dataset.sort = 0
    } else {
        node.dataset.sort = pcls + 1
        pbar.style.background = `var(--c${pcls})`
    }
}

const sortFrames = (node) => {
    [...node.children].sort((a, b) => a.dataset.sort > b.dataset.sort ? 1 : -1)
        .reverse().forEach(x => node.appendChild(x))
}