mirror of
https://github.com/notion-enhancer/notion-enhancer.git
synced 2025-04-05 13:19:03 +00:00
re-orderable mods: menu elements can be dragged
This commit is contained in:
parent
a3e8758280
commit
74a03a176c
@ -115,6 +115,7 @@ module.exports = (store, __exports) => {
|
|||||||
'--theme--interactive_hover-border',
|
'--theme--interactive_hover-border',
|
||||||
'--theme--button_close',
|
'--theme--button_close',
|
||||||
'--theme--button_close-fill',
|
'--theme--button_close-fill',
|
||||||
|
'--theme--selected',
|
||||||
'--theme--primary',
|
'--theme--primary',
|
||||||
'--theme--primary_click',
|
'--theme--primary_click',
|
||||||
'--theme--option-color',
|
'--theme--option-color',
|
||||||
|
@ -254,6 +254,9 @@ s {
|
|||||||
|
|
||||||
/* module meta */
|
/* module meta */
|
||||||
|
|
||||||
|
#modules {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
#modules section {
|
#modules section {
|
||||||
background: var(--theme--sidebar);
|
background: var(--theme--sidebar);
|
||||||
border: 1px solid var(--theme--table-border);
|
border: 1px solid var(--theme--table-border);
|
||||||
@ -589,3 +592,64 @@ s {
|
|||||||
height: 132.5px;
|
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);
|
||||||
|
}
|
||||||
|
@ -20,6 +20,10 @@
|
|||||||
</svg>
|
</svg>
|
||||||
<input type="text" placeholder="search ('/' to focus)" />
|
<input type="text" placeholder="search ('/' to focus)" />
|
||||||
<div id="tags"></div>
|
<div id="tags"></div>
|
||||||
|
<button id="draggable-toggle">
|
||||||
|
<b data-bolded="configure">configure</b> |
|
||||||
|
<span data-bolded="reorder">reorder</span>
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div id="modules"></div>
|
<div id="modules"></div>
|
||||||
</main>
|
</main>
|
||||||
|
@ -184,12 +184,12 @@ window['__start'] = async () => {
|
|||||||
};
|
};
|
||||||
function innerText(elem) {
|
function innerText(elem) {
|
||||||
let text = '';
|
let text = '';
|
||||||
for (let node of elem.childNodes) {
|
for (let $node of elem.childNodes) {
|
||||||
if (node.nodeType === 3) text += node.textContent;
|
if ($node.nodeType === 3) text += $node.textContent;
|
||||||
if (node.nodeType === 1)
|
if ($node.nodeType === 1)
|
||||||
text += ['text', 'number'].includes(node.type)
|
text += ['text', 'number'].includes($node.type)
|
||||||
? node.value
|
? $node.value
|
||||||
: innerText(node);
|
: innerText($node);
|
||||||
}
|
}
|
||||||
return text;
|
return text;
|
||||||
}
|
}
|
||||||
@ -284,20 +284,20 @@ window['__start'] = async () => {
|
|||||||
return parsed;
|
return parsed;
|
||||||
}
|
}
|
||||||
|
|
||||||
let modified_notice;
|
let $modified_notice;
|
||||||
function modified() {
|
function modified() {
|
||||||
if (modified_notice) return;
|
if ($modified_notice) return;
|
||||||
modified_notice = createAlert(
|
$modified_notice = createAlert(
|
||||||
'info',
|
'info',
|
||||||
`changes may not fully apply until <span data-relaunch>app relaunch</span>.`
|
`changes may not fully apply until <span data-relaunch>app relaunch</span>.`
|
||||||
);
|
);
|
||||||
modified_notice.el
|
$modified_notice.el
|
||||||
.querySelector('[data-relaunch]')
|
.querySelector('[data-relaunch]')
|
||||||
.addEventListener('click', (event) => {
|
.addEventListener('click', (event) => {
|
||||||
electron.remote.app.relaunch();
|
electron.remote.app.relaunch();
|
||||||
electron.remote.app.quit();
|
electron.remote.app.quit();
|
||||||
});
|
});
|
||||||
modified_notice.append();
|
$modified_notice.append();
|
||||||
}
|
}
|
||||||
|
|
||||||
const file_icon = await fs.readFile(
|
const file_icon = await fs.readFile(
|
||||||
@ -389,15 +389,8 @@ window['__start'] = async () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const $modules = document.querySelector('#modules');
|
const $modules = document.querySelector('#modules');
|
||||||
for (let mod of modules.loaded.sort((a, b) =>
|
|
||||||
a.tags.includes('core') ||
|
for (let mod of modules.loaded) {
|
||||||
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 fonts of mod.fonts || []) {
|
for (let fonts of mod.fonts || []) {
|
||||||
document
|
document
|
||||||
.querySelector('head')
|
.querySelector('head')
|
||||||
@ -417,37 +410,39 @@ window['__start'] = async () => {
|
|||||||
avatar: `https://github.com/${mod.author}.png`,
|
avatar: `https://github.com/${mod.author}.png`,
|
||||||
};
|
};
|
||||||
mod.elem = helpers.createElement(`
|
mod.elem = helpers.createElement(`
|
||||||
<section class="${
|
<section class="${
|
||||||
mod.tags.includes('core') || enabled ? 'enabled' : 'disabled'
|
mod.tags.includes('core') || enabled ? 'enabled' : 'disabled'
|
||||||
}" id="${mod.id}">
|
}" id="${mod.id}">
|
||||||
<div class="meta">
|
<div class="meta">
|
||||||
<h3 ${
|
<h3 ${
|
||||||
mod.tags.includes('core')
|
mod.tags.includes('core')
|
||||||
? `>${mod.name}`
|
? `>${mod.name}`
|
||||||
: `class="toggle">
|
: `class="toggle">
|
||||||
<input type="checkbox" id="enable_${mod.id}"
|
<input type="checkbox" id="enable_${mod.id}"
|
||||||
${enabled ? 'checked' : ''} />
|
${enabled ? 'checked' : ''} />
|
||||||
<label for="enable_${mod.id}">
|
<label for="enable_${mod.id}">
|
||||||
<span class="name">${mod.name}</span>
|
<span class="name">${mod.name}</span>
|
||||||
<span class="switch"><span class="dot"></span></span>
|
<span class="switch"><span class="dot"></span></span>
|
||||||
</label>`
|
</label>`
|
||||||
}</h3>
|
}</h3>
|
||||||
<p class="tags">${mod.tags
|
<p class="tags">${mod.tags
|
||||||
.map((tag) => (tag.startsWith('#') ? tag : `#${tag}`))
|
.map((tag) => (tag.startsWith('#') ? tag : `#${tag}`))
|
||||||
.join(' ')}</p>
|
.join(' ')}</p>
|
||||||
<div class="desc">${markdown(mod.desc)}</div>
|
<div class="desc">${markdown(mod.desc)}</div>
|
||||||
<p>
|
<p>
|
||||||
<a href="${author.link}" class="author">
|
<a href="${author.link}" class="author">
|
||||||
<img src="${author.avatar}" onerror="this.src='./icons/user.png'">
|
<img src="${author.avatar}" onerror="this.src='./icons/user.png'">
|
||||||
${author.name}
|
${author.name}
|
||||||
</a>
|
</a>
|
||||||
<span class="version">v${mod.version}</span>
|
<span class="version">v${mod.version}</span>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
${
|
${
|
||||||
mod.options && mod.options.length ? '<div class="options"></div>' : ''
|
mod.options && mod.options.length
|
||||||
}
|
? '<div class="options"></div>'
|
||||||
</section>
|
: ''
|
||||||
|
}
|
||||||
|
</section>
|
||||||
`);
|
`);
|
||||||
const $enable = mod.elem.querySelector(`#enable_${mod.id}`);
|
const $enable = mod.elem.querySelector(`#enable_${mod.id}`);
|
||||||
if ($enable)
|
if ($enable)
|
||||||
@ -500,12 +495,96 @@ window['__start'] = async () => {
|
|||||||
}
|
}
|
||||||
$options.appendChild($opt);
|
$options.appendChild($opt);
|
||||||
}
|
}
|
||||||
$modules.append(mod.elem);
|
if (mod.tags.includes('core')) $modules.append(mod.elem);
|
||||||
}
|
}
|
||||||
|
|
||||||
document
|
document
|
||||||
.querySelectorAll('input[type="checkbox"]')
|
.querySelectorAll('input[type="checkbox"]')
|
||||||
.forEach((checkbox) =>
|
.forEach((checkbox) =>
|
||||||
checkbox.addEventListener('click', (event) => event.target.blur())
|
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));
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
@ -140,6 +140,13 @@ function getEnhancements() {
|
|||||||
modules.invalid.push(dir);
|
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;
|
return modules;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user