diff --git a/mods/core/client.js b/mods/core/client.js index 0aca69c..396c8bd 100644 --- a/mods/core/client.js +++ b/mods/core/client.js @@ -115,6 +115,7 @@ module.exports = (store, __exports) => { '--theme--interactive_hover-border', '--theme--button_close', '--theme--button_close-fill', + '--theme--selected', '--theme--primary', '--theme--primary_click', '--theme--option-color', diff --git a/mods/core/css/menu.css b/mods/core/css/menu.css index 9bb5c5d..43a26fd 100644 --- a/mods/core/css/menu.css +++ b/mods/core/css/menu.css @@ -254,6 +254,9 @@ s { /* module meta */ +#modules { + position: relative; +} #modules section { background: var(--theme--sidebar); border: 1px solid var(--theme--table-border); @@ -589,3 +592,64 @@ s { height: 132.5px; } } + +/* draggable re-ordering of mods */ + +#draggable-toggle { + background: none; + border: none; + margin-top: 0.8em; + padding-left: 0; + cursor: pointer; + color: var(--theme--text_ui); +} + +[data-bolded] { + display: inline-flex; + flex-direction: column; +} +[data-bolded]::after { + content: attr(data-bolded); + height: 0; + visibility: hidden; + overflow: hidden; + user-select: none; + pointer-events: none; + font-weight: bold; +} + +#modules.reorder section { + margin-bottom: 0.4em; +} +#modules.reorder [draggable] { + margin-bottom: 1.15em; +} +#modules.reorder [draggable]::after { + content: ''; + height: 0.3em; + width: 99%; + position: absolute; + margin: 0.5em 0; + opacity: 0.7; + background: var(--theme--table-border); +} +#modules.reorder [draggable].dragged-over::after { + background: var(--theme--selected); +} + +#modules.reorder .switch, +#modules.reorder .tags, +#modules.reorder .desc, +#modules.reorder .options, +#modules.reorder .author, +#modules.reorder .version { + display: none; +} +#modules.reorder label { + cursor: pointer; +} +#modules.reorder label::before { + content: '::'; + margin-right: 0.4em; + color: var(--theme--text_ui); +} diff --git a/mods/core/menu.html b/mods/core/menu.html index 83e6d60..3b3f91a 100644 --- a/mods/core/menu.html +++ b/mods/core/menu.html @@ -20,6 +20,10 @@
+
diff --git a/mods/core/menu.js b/mods/core/menu.js index d839720..22e79c6 100644 --- a/mods/core/menu.js +++ b/mods/core/menu.js @@ -184,12 +184,12 @@ window['__start'] = async () => { }; function innerText(elem) { let text = ''; - for (let node of elem.childNodes) { - if (node.nodeType === 3) text += node.textContent; - if (node.nodeType === 1) - text += ['text', 'number'].includes(node.type) - ? node.value - : innerText(node); + for (let $node of elem.childNodes) { + if ($node.nodeType === 3) text += $node.textContent; + if ($node.nodeType === 1) + text += ['text', 'number'].includes($node.type) + ? $node.value + : innerText($node); } return text; } @@ -284,20 +284,20 @@ window['__start'] = async () => { return parsed; } - let modified_notice; + let $modified_notice; function modified() { - if (modified_notice) return; - modified_notice = createAlert( + if ($modified_notice) return; + $modified_notice = createAlert( 'info', `changes may not fully apply until app relaunch.` ); - modified_notice.el + $modified_notice.el .querySelector('[data-relaunch]') .addEventListener('click', (event) => { electron.remote.app.relaunch(); electron.remote.app.quit(); }); - modified_notice.append(); + $modified_notice.append(); } const file_icon = await fs.readFile( @@ -389,15 +389,8 @@ window['__start'] = async () => { } const $modules = document.querySelector('#modules'); - for (let mod of modules.loaded.sort((a, b) => - a.tags.includes('core') || - store('mods', { [a.id]: { pinned: false } }).pinned - ? -1 - : b.tags.includes('core') || - store('mods', { [b.id]: { pinned: false } }).pinned - ? 1 - : a.name.localeCompare(b.name) - )) { + + for (let mod of modules.loaded) { for (let fonts of mod.fonts || []) { document .querySelector('head') @@ -417,37 +410,39 @@ window['__start'] = async () => { avatar: `https://github.com/${mod.author}.png`, }; mod.elem = helpers.createElement(` -
+
-

${mod.name}` - : `class="toggle"> - ${mod.name}` + : `class="toggle"> + ` - }

-

${mod.tags - .map((tag) => (tag.startsWith('#') ? tag : `#${tag}`)) - .join(' ')}

-
${markdown(mod.desc)}
-

- + ` + } +

${mod.tags + .map((tag) => (tag.startsWith('#') ? tag : `#${tag}`)) + .join(' ')}

+
${markdown(mod.desc)}
+

+ ${author.name} - + v${mod.version} -

-
- ${ - mod.options && mod.options.length ? '
' : '' - } -
+

+ + ${ + mod.options && mod.options.length + ? '
' + : '' + } +
`); const $enable = mod.elem.querySelector(`#enable_${mod.id}`); if ($enable) @@ -500,12 +495,96 @@ window['__start'] = async () => { } $options.appendChild($opt); } - $modules.append(mod.elem); + if (mod.tags.includes('core')) $modules.append(mod.elem); } - document .querySelectorAll('input[type="checkbox"]') .forEach((checkbox) => checkbox.addEventListener('click', (event) => event.target.blur()) ); + + // draggable re-ordering + const draggable = { + state: 0, + tags: ['b', 'span'], + $toggle: document.querySelector('#draggable-toggle'), + list: modules.loaded + .filter((m) => !m.tags.includes('core')) + .map((m) => m.elem), + target: null, + render() { + draggable.target = null; + for (let $node of draggable.list) { + $node.draggable = false; + $modules.append($node); + } + }, + mouseover(event) { + if (!draggable.target && event.target.innerText) { + for (let $node of draggable.list) $node.draggable = false; + const $node = draggable.list.find( + (node) => node.innerText === event.target.innerText + ); + if ($node) $node.draggable = draggable.state; + } + }, + }; + document.addEventListener('dragstart', (event) => { + draggable.target = event.target; + event.target.style.opacity = 0.5; + }); + document.addEventListener('dragend', (event) => { + event.target.style.opacity = ''; + }); + document.addEventListener('dragover', (event) => { + event.preventDefault(); + document + .querySelectorAll('.dragged-over') + .forEach((el) => el.classList.remove('dragged-over')); + const $node = draggable.list.find( + (node) => node.innerText === event.target.innerText + ); + if ($node) $node.classList.add('dragged-over'); + }); + document.addEventListener('drop', (event) => { + event.preventDefault(); + document + .querySelectorAll('.dragged-over') + .forEach((el) => el.classList.remove('dragged-over')); + if ( + draggable.target && + draggable.target.innerText !== event.target.innerText + ) { + const from = draggable.list.findIndex( + (node) => node.innerText === draggable.target.innerText + ), + to = draggable.list.findIndex( + (node) => node.innerText === event.target.innerText + ); + // [draggable.list[from], draggable.list[to]] = [ + // draggable.list[to], + // draggable.list[from], + // ]; -- swap + if (to >= draggable.list.length) { + let k = to - draggable.list.length; + while (k--) draggable.list.push(undefined); + } + draggable.list.splice(to, 0, draggable.list.splice(from, 1)[0]); + } + draggable.render(); + }); + document.addEventListener('mouseover', draggable.mouseover); + draggable.render(); + draggable.$toggle.addEventListener('click', (event) => { + draggable.state = !draggable.state; + draggable.tags = draggable.tags.reverse(); + draggable.$toggle.innerHTML = ` + <${draggable.tags[0]} data-bolded="configure">configure | + <${draggable.tags[1]} data-bolded="reorder">reorder + `; + $modules.classList[draggable.state ? 'add' : 'remove']('reorder'); + $modules + .querySelectorAll('input') + .forEach((input) => (input.disabled = draggable.state)); + }); }; diff --git a/pkg/helpers.js b/pkg/helpers.js index c905331..7ff97e9 100644 --- a/pkg/helpers.js +++ b/pkg/helpers.js @@ -140,6 +140,13 @@ function getEnhancements() { modules.invalid.push(dir); } } + modules.loaded = modules.loaded.sort((a, b) => + a.tags.includes('core') + ? -1 + : b.tags.includes('core') + ? 1 + : a.name.localeCompare(b.name) + ); return modules; }