mirror of
https://github.com/Horizontal42/summarum.git
synced 2026-11-11 02:12:00 +03:00
sheets: reorder by dragging instead of up/down buttons
Move-up/move-down felt disconnected from the result — clicking a button and having two rows silently swap position doesn't read as motion. Dropped both buttons for native HTML5 drag-and-drop: drag a sheet, an accent line shows where it'll land, drop to reorder. Still respects the pinned/unpinned grouping — dragging across that boundary is a no-op, same as the old up/down buttons.
This commit is contained in:
parent
5205c9fb63
commit
7b94f6a5b0
3 changed files with 42 additions and 17 deletions
|
|
@ -61,8 +61,6 @@ const dict: Record<string, Record<string, string>> = {
|
|||
cancel: "Cancel",
|
||||
pin: "Pin",
|
||||
unpin: "Unpin",
|
||||
moveUp: "Move up",
|
||||
moveDown: "Move down",
|
||||
marketUpdated: "Market data updated",
|
||||
exportImage: "Copy as image",
|
||||
imageCopied: "Image copied",
|
||||
|
|
@ -139,8 +137,6 @@ const dict: Record<string, Record<string, string>> = {
|
|||
cancel: "Отмена",
|
||||
pin: "Закрепить",
|
||||
unpin: "Открепить",
|
||||
moveUp: "Выше",
|
||||
moveDown: "Ниже",
|
||||
marketUpdated: "Рыночные данные обновлены",
|
||||
exportImage: "Скопировать картинкой",
|
||||
imageCopied: "Картинка скопирована",
|
||||
|
|
|
|||
47
src/main.ts
47
src/main.ts
|
|
@ -81,24 +81,28 @@ function pinDoc(id: string): void {
|
|||
renderDocList();
|
||||
}
|
||||
|
||||
function moveDoc(id: string, dir: -1 | 1): void {
|
||||
const idx = data.docs.findIndex((d) => d.id === id);
|
||||
if (idx < 0) return;
|
||||
const doc = data.docs[idx];
|
||||
const target = data.docs[idx + dir];
|
||||
if (!target || !!target.pinned !== !!doc.pinned) return; // can't cross pin boundary
|
||||
data.docs.splice(idx, 1);
|
||||
data.docs.splice(idx + dir, 0, doc);
|
||||
/** drag id -> drop-target id; no-op across the pinned/unpinned boundary */
|
||||
function reorderDoc(srcId: string, targetId: string): void {
|
||||
if (srcId === targetId) return;
|
||||
const src = data.docs.find((d) => d.id === srcId);
|
||||
const target = data.docs.find((d) => d.id === targetId);
|
||||
if (!src || !target || !!src.pinned !== !!target.pinned) return;
|
||||
data.docs = data.docs.filter((d) => d.id !== srcId);
|
||||
const targetIdx = data.docs.findIndex((d) => d.id === targetId);
|
||||
data.docs.splice(targetIdx, 0, src);
|
||||
saveAppData(data);
|
||||
renderDocList();
|
||||
}
|
||||
|
||||
let dragSrcId: string | null = null;
|
||||
|
||||
function renderDocList(): void {
|
||||
const list = $("#doc-list");
|
||||
list.replaceChildren();
|
||||
for (const doc of data.docs) {
|
||||
const el = document.createElement("div");
|
||||
el.className = "doc-item" + (doc.id === data.activeId ? " active" : "") + (doc.pinned ? " pinned" : "");
|
||||
el.draggable = true;
|
||||
const name = document.createElement("span");
|
||||
name.className = "doc-name";
|
||||
name.textContent = doc.title || t("untitled");
|
||||
|
|
@ -114,8 +118,31 @@ function renderDocList(): void {
|
|||
};
|
||||
|
||||
el.appendChild(mkBtn("pin-btn" + (doc.pinned ? " active" : ""), "📌", doc.pinned ? t("unpin") : t("pin"), () => pinDoc(doc.id)));
|
||||
el.appendChild(mkBtn("move-btn", "↑", t("moveUp"), () => moveDoc(doc.id, -1)));
|
||||
el.appendChild(mkBtn("move-btn", "↓", t("moveDown"), () => moveDoc(doc.id, 1)));
|
||||
|
||||
el.addEventListener("dragstart", (e) => {
|
||||
dragSrcId = doc.id;
|
||||
el.classList.add("dragging");
|
||||
e.dataTransfer!.effectAllowed = "move";
|
||||
e.dataTransfer?.setData("text/plain", doc.id);
|
||||
});
|
||||
el.addEventListener("dragend", () => {
|
||||
el.classList.remove("dragging");
|
||||
dragSrcId = null;
|
||||
for (const other of list.querySelectorAll(".doc-item")) other.classList.remove("drag-over");
|
||||
});
|
||||
el.addEventListener("dragover", (e) => {
|
||||
if (!dragSrcId || dragSrcId === doc.id) return;
|
||||
const src = data.docs.find((d) => d.id === dragSrcId);
|
||||
if (!src || !!src.pinned !== !!doc.pinned) return; // can't cross the pin boundary
|
||||
e.preventDefault(); // allow drop
|
||||
for (const other of list.querySelectorAll(".doc-item")) other.classList.remove("drag-over");
|
||||
el.classList.add("drag-over");
|
||||
});
|
||||
el.addEventListener("drop", (e) => {
|
||||
e.preventDefault();
|
||||
el.classList.remove("drag-over");
|
||||
if (dragSrcId) reorderDoc(dragSrcId, doc.id);
|
||||
});
|
||||
|
||||
const del = document.createElement("button");
|
||||
del.className = "del";
|
||||
|
|
|
|||
|
|
@ -102,7 +102,7 @@ body {
|
|||
.doc-item {
|
||||
padding: 7px 10px;
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
cursor: grab;
|
||||
font-size: 13px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
|
|
@ -110,12 +110,15 @@ body {
|
|||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
border-top: 2px solid transparent;
|
||||
transition: background-color 0.15s ease, color 0.15s ease, opacity 0.15s ease, border-top-color 0.15s ease;
|
||||
}
|
||||
.doc-item:hover { background: var(--hover); }
|
||||
.doc-item.active { background: var(--sel); }
|
||||
.doc-item.dragging { opacity: 0.4; }
|
||||
.doc-item.drag-over { border-top-color: var(--accent); }
|
||||
.doc-name { flex: 1; overflow: hidden; text-overflow: ellipsis; }
|
||||
.doc-item .pin-btn,
|
||||
.doc-item .move-btn,
|
||||
.doc-item .del {
|
||||
flex-shrink: 0;
|
||||
opacity: 0;
|
||||
|
|
@ -130,7 +133,6 @@ body {
|
|||
transition: opacity 0.15s ease, background-color 0.15s ease;
|
||||
}
|
||||
.doc-item:hover .pin-btn,
|
||||
.doc-item:hover .move-btn,
|
||||
.doc-item:hover .del { opacity: 0.7; }
|
||||
.doc-item .pin-btn.active { opacity: 1; }
|
||||
.doc-item:hover .pin-btn.active { opacity: 1; }
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue