Reihenfolge mit Pfeilen, Zifferntasten entfernt
Sortiert wird im Programm-Editor mit Pfeilen in der Kopfzeile jeder Zeile — das Array ist die Reihenfolge, also gilt sie ueberall zugleich: Streifen, Schublade, Kacheln, Schreibtischsymbole, Startmenue. Neue Apps haengen sich hinten an, statt eine Taste zu verlangen. Die Zifferntasten sind ganz weg (Marcs Entscheidung): ein Pflichtfeld je App, das beim Sortieren nur die Frage aufgeworfen haette, ob es mitwandert. Damit faellt das Feld 'key' aus dem Datenmodell, aus der Kachel, aus der Hilfe und aus der Statuszeile. Alte Eintraege verlieren es beim naechsten Speichern still. Kein A-Z-Knopf — erstmal zu viel, kommt zurueck wenn er fehlt.
This commit is contained in:
1 parent
cc7a50c621
commit
0e1c986f90
6 files changed
+73
-32
No files matched your search
+41
-10
@@ -277,7 +277,6 @@ function renderTiles() {
|
||||
a.target = state.settings.openIn === "tab" ? "_blank" : "_self";
|
||||
a.rel = "noopener";
|
||||
a.innerHTML = `
|
||||
${app.key ? `<span class="tile-key">[${app.key}]</span>` : ""}
|
||||
<span class="tile-icon">${glyphSvg(app.glyph)}</span>
|
||||
<span class="tile-name">${escapeHtml(app.name)}</span>
|
||||
<span class="tile-sub">${escapeHtml(app.subtitle || "")}</span>
|
||||
@@ -707,11 +706,17 @@ function openApps() {
|
||||
const GLYPHS_LIST = Object.keys(GLYPHS).filter((g) => !WETTER_GLYPHEN.includes(g));
|
||||
|
||||
const rowHtml = (a, i) => `
|
||||
<details class="approw" ${a.__neu ? "open" : ""}>
|
||||
<details class="approw" ${a.__offen ? "open" : ""}>
|
||||
<summary>
|
||||
<span class="ae-glyph">${glyphSvg(a.glyph)}</span>
|
||||
<span>${escapeHtml(a.name || a.id || "neue app")}</span>
|
||||
<span class="ae-url">${escapeHtml(a.url || "")}</span>
|
||||
<span class="ae-move">
|
||||
<button class="ae-arrow" data-up="${i}" ${i === 0 ? "disabled" : ""}
|
||||
title="nach oben" aria-label="${escapeAttr(a.name || a.id)} nach oben">▲</button>
|
||||
<button class="ae-arrow" data-down="${i}" ${i === draft.length - 1 ? "disabled" : ""}
|
||||
title="nach unten" aria-label="${escapeAttr(a.name || a.id)} nach unten">▼</button>
|
||||
</span>
|
||||
</summary>
|
||||
<div class="ae-body">
|
||||
<label class="ae-field"><span>ID</span>
|
||||
@@ -727,8 +732,6 @@ function openApps() {
|
||||
<select data-i="${i}" data-f="glyph">
|
||||
${GLYPHS_LIST.map((g) => `<option value="${g}" ${a.glyph === g ? "selected" : ""}>${g}</option>`).join("")}
|
||||
</select></label>
|
||||
<label class="ae-field"><span>Taste</span>
|
||||
<input data-i="${i}" data-f="key" value="${escapeAttr(a.key || "")}" maxlength="1" placeholder="1" /></label>
|
||||
<div class="ae-actions">
|
||||
<button class="btn btn-danger" data-del="${i}">löschen</button>
|
||||
</div>
|
||||
@@ -752,6 +755,35 @@ function openApps() {
|
||||
render(root);
|
||||
})
|
||||
);
|
||||
|
||||
// Merken, was offen ist — das Umsortieren zeichnet die Liste neu, und ohne
|
||||
// das klappte dabei alles zu, was man gerade bearbeitet.
|
||||
list.querySelectorAll(".approw").forEach((d, i) => {
|
||||
d.addEventListener("toggle", () => {
|
||||
if (draft[i]) draft[i].__offen = d.open;
|
||||
});
|
||||
});
|
||||
|
||||
// Die Pfeile sitzen im <summary>: Ohne preventDefault klappt jeder
|
||||
// Sortierklick die Zeile auf oder zu.
|
||||
const tausche = (i, j) => {
|
||||
if (j < 0 || j >= draft.length) return;
|
||||
[draft[i], draft[j]] = [draft[j], draft[i]];
|
||||
render(root);
|
||||
// Zurück auf denselben Knopf, damit man mehrmals hintereinander drücken
|
||||
// kann, ohne die Maus nachzuführen.
|
||||
const wieder = list.querySelector(`[data-${j < i ? "up" : "down"}="${j}"]`);
|
||||
if (wieder && !wieder.disabled) wieder.focus();
|
||||
};
|
||||
|
||||
list.querySelectorAll("[data-up], [data-down]").forEach((b) =>
|
||||
b.addEventListener("click", (e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
const i = Number(b.dataset.up ?? b.dataset.down);
|
||||
tausche(i, "up" in b.dataset ? i - 1 : i + 1);
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
openPanel(
|
||||
@@ -768,7 +800,8 @@ function openApps() {
|
||||
render(root);
|
||||
|
||||
root.querySelector("#btnAdd").addEventListener("click", () => {
|
||||
draft.push({ id: "", name: "", url: "", glyph: "box", key: String(draft.length + 1), __neu: true });
|
||||
// Immer ans Ende — sortiert wird mit den Pfeilen, nicht beim Anlegen.
|
||||
draft.push({ id: "", name: "", url: "", glyph: "box", __offen: true });
|
||||
render(root);
|
||||
});
|
||||
|
||||
@@ -777,9 +810,10 @@ function openApps() {
|
||||
msg.dataset.kind = "";
|
||||
msg.textContent = "speichere …";
|
||||
try {
|
||||
const clean = draft.map(({ __neu, ...rest }) => rest);
|
||||
const clean = draft.map(({ __offen, ...rest }) => rest);
|
||||
state.cfg.apps = (await api("/api/apps", { method: "PUT", body: JSON.stringify(clean) })).apps;
|
||||
draft = state.cfg.apps.map((a) => ({ ...a }));
|
||||
const offen = new Set(draft.filter((a) => a.__offen).map((a) => a.id));
|
||||
draft = state.cfg.apps.map((a) => ({ ...a, __offen: offen.has(a.id) }));
|
||||
msg.textContent = `${state.cfg.apps.length} gespeichert.`;
|
||||
render(root);
|
||||
renderMenubarApps();
|
||||
@@ -807,7 +841,6 @@ function openAbout() {
|
||||
<code>desktop</code> Symbole und Fenster. Die HoneyBar oben ist in beiden dieselbe —
|
||||
und dieselbe steckt per <code>honeybar/honeybar.js</code> auch in Aether und InkNote.</p>
|
||||
<dl class="keys">
|
||||
${state.cfg.apps.map((a) => `<dt>${a.key || "·"}</dt><dd>${escapeHtml(a.name)} starten</dd>`).join("")}
|
||||
<dt>M</dt><dd>Betriebsart wechseln</dd>
|
||||
<dt>S</dt><dd>Einstellungen</dd>
|
||||
<dt>?</dt><dd>diese Hilfe</dd>
|
||||
@@ -1137,8 +1170,6 @@ async function main() {
|
||||
}
|
||||
if (typing) return;
|
||||
|
||||
const app = state.cfg.apps.find((a) => a.key === e.key);
|
||||
if (app) return launch(app);
|
||||
if (e.key === "m" || e.key === "M") setMode(state.settings.mode === "desktop" ? "terminal" : "desktop");
|
||||
if (e.key === "s" || e.key === "S") openSettings();
|
||||
if (e.key === "?") openAbout();
|
||||
|
||||
Reference in new issue
Block a user