From 74a03a176c5bab2c9234a2ddf3963cab5e7f7ece Mon Sep 17 00:00:00 2001
From: dragonwocky
Date: Thu, 1 Oct 2020 13:32:50 +1000
Subject: [PATCH] re-orderable mods: menu elements can be dragged
---
mods/core/client.js | 1 +
mods/core/css/menu.css | 64 +++++++++++++++
mods/core/menu.html | 4 +
mods/core/menu.js | 171 ++++++++++++++++++++++++++++++-----------
pkg/helpers.js | 7 ++
5 files changed, 201 insertions(+), 46 deletions(-)
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.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[0]}> |
+ <${draggable.tags[1]} data-bolded="reorder">reorder${draggable.tags[1]}>
+ `;
+ $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;
}