Add: Slip UI

This commit is contained in:
eight04 2021-12-09 22:25:33 +08:00
parent 43c37ea56a
commit 5adb7f593d
6 changed files with 119 additions and 14 deletions

View File

@ -0,0 +1,57 @@
html, body {
margin: 0;
padding: 0;
}
#main {
display: grid;
grid-template-columns: min-content minmax(0, 1fr);
height: 100vh;
}
#main.ready {
animation: slidein .25s ease-in-out;
}
.closer {
max-height: 100vh;
}
.closer::after {
content: "\bb";
}
ol {
list-style: none;
margin: 0;
padding: 0;
font-size: 16px;
overflow-y: auto;
}
li {
position: relative;
user-select: none;
border: 1px solid;
padding: 0.3em 0;
background: white;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis
}
li:not(:first-child) {
margin-top: -1px;
}
.dragger::before {
content: "\2261"
}
.dragger {
padding: 0.6em;
cursor: grab;
}
.slip-reordering,
.slip-reordering .dragger {
cursor: grabbing;
}
@keyframes slidein {
from {
transform: translateX(100%);
}
to {
transform: translateX(0);
}
}

View File

@ -5,6 +5,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title i18n-text-append="optionsHeading">Stylus </title> <title i18n-text-append="optionsHeading">Stylus </title>
<link rel="stylesheet" href="/global.css"> <link rel="stylesheet" href="/global.css">
<link rel="stylesheet" href="execution-order.css">
<script src="/js/polyfill.js"></script> <script src="/js/polyfill.js"></script>
<script src="/js/toolbox.js"></script> <script src="/js/toolbox.js"></script>
@ -19,6 +20,7 @@
<body> <body>
<div id="main"> <div id="main">
<button class="closer"></button>
<ol id="style-list"></ol> <ol id="style-list"></ol>
</div> </div>
<script src="/vendor/slipjs/slip.js"></script> <script src="/vendor/slipjs/slip.js"></script>

View File

@ -1,25 +1,46 @@
/* global Slip */
/* global prefs */ /* global prefs */
/* global API */ /* global API */
'use strict';
(async () => { (async () => {
const list = (await getOrderedStyles()).map(createLi); const list = (await getOrderedStyles()).map(createLi);
document.querySelector("#main").append(...list.map(l => l.el)); const ol = document.querySelector('#style-list');
ol.append(...list.map(l => l.el));
ol.addEventListener('slip:beforeswipe', e => e.preventDefault());
ol.addEventListener('slip:beforewait', e => {
if (e.target.classList.contains('dragger')) {
e.preventDefault();
}
});
ol.addEventListener('slip:reorder', e => {
const [item] = list.splice(e.detail.originalIndex, 1);
list.splice(e.detail.spliceIndex, 0, item);
ol.insertBefore(e.target, e.detail.insertBefore);
prefs.set('styles.order', list.map(l => l.style._id));
});
new Slip(ol);
document.querySelector('#main').classList.add('ready');
document.querySelector('.closer').addEventListener('click', () => {
parent.dispatchEvent(new Event('closeOptions'));
});
function createLi(style) { function createLi(style) {
const el = document.createElement("li"); const el = document.createElement('li');
const dragger = document.createElement("span"); const dragger = document.createElement('span');
dragger.class = "dragger"; dragger.className = 'dragger';
el.append(dragger, style.name); el.append(dragger, style.name);
return {el}; return {el, style};
} }
async function getOrderedStyles() { async function getOrderedStyles() {
const [styles, ] = await Promise.all([ const [styles] = await Promise.all([
API.styles.getAll(), API.styles.getAll(),
prefs.ready prefs.ready,
]); ]);
const styleSet = new Set(styles); const styleSet = new Set(styles);
const uuidIndex = new Map; const uuidIndex = new Map();
for (const s of styleSet) { for (const s of styleSet) {
uuidIndex.set(s._id, s); uuidIndex.set(s._id, s);
} }
@ -27,7 +48,10 @@
for (const uid of prefs.get('styles.order')) { for (const uid of prefs.get('styles.order')) {
const s = uuidIndex.get(uid); const s = uuidIndex.get(uid);
if (s) { if (s) {
uuidIndex.delete(uid);
orderedStyles.push(s); orderedStyles.push(s);
styleSet.delete(s);
} }
} }
orderedStyles.push(...styleSet); orderedStyles.push(...styleSet);

View File

@ -980,6 +980,18 @@ a:hover {
animation: fadeout .25s ease-in-out; animation: fadeout .25s ease-in-out;
} }
#stylus-execution-order {
position: fixed;
height: 100%;
border: 0;
right: 0;
max-width: 400px;
width: 90%;
}
#stylus-execution-order.fadeout {
animation: slideout .25s ease-in-out;
}
.settings-column { .settings-column {
margin-top: 1rem; margin-top: 1rem;
} }
@ -1001,6 +1013,14 @@ a:hover {
opacity: 0; opacity: 0;
} }
} }
@keyframes slideout {
from {
transform: translateX(0);
}
to {
transform: translateX(100%);
}
}
@keyframes fadein-25pct { @keyframes fadein-25pct {
from { from {
@ -1165,3 +1185,4 @@ a:hover {
margin-left: -2px; margin-left: -2px;
} }
} }

View File

@ -139,20 +139,21 @@ function onRuntimeMessage(msg) {
function Embed(El) { function Embed(El) {
let el; let el;
return async state => { return toggle;
if (!state && !el) return; async function toggle(state) {
if (!el) el = El();
if (state) { if (state) {
if (!el) el = El();
if (!el.offsetParent) { if (!el.offsetParent) {
document.body.append(el); document.body.append(el);
} }
el.focus(); el.focus();
} else { } else {
if (!el || !el.offsetParent) return;
if (el.contentDocument) { if (el.contentDocument) {
el.contentDocument.body.classList.add('scaleout'); el.contentDocument.body.classList.add('scaleout');
} }
await animateElement(el, 'fadeout'); await animateElement(el, 'fadeout');
el.remove(); el.remove();
} }
}; }
} }

View File

@ -61,8 +61,8 @@ const files = {
'dist/webext-launch-web-auth-flow.min.js → webext-launch-web-auth-flow.min.js', 'dist/webext-launch-web-auth-flow.min.js → webext-launch-web-auth-flow.min.js',
], ],
'slipjs': [ 'slipjs': [
'slip.js' 'slip.js',
] ],
}; };
main().catch(console.error); main().catch(console.error);