New mobile layout, new regular screen, added the ability to edit directory names from settings
This commit is contained in:
+110
-6
@@ -209,6 +209,7 @@
|
||||
}
|
||||
.curate-row {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 10px;
|
||||
@@ -255,6 +256,28 @@
|
||||
font-size: 0.9em;
|
||||
padding: 6px 0;
|
||||
}
|
||||
.curate-actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.curate-rename-input {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
background: var(--bg-primary);
|
||||
color: var(--text-primary);
|
||||
border: 1px solid var(--accent);
|
||||
border-radius: var(--radius);
|
||||
padding: 4px 8px;
|
||||
font-size: 0.95em;
|
||||
font-family: var(--font-family);
|
||||
}
|
||||
.curate-row-status {
|
||||
flex-basis: 100%;
|
||||
font-size: 0.8em;
|
||||
color: #ff6b6b;
|
||||
}
|
||||
#save-status {
|
||||
font-size: 0.9em;
|
||||
color: #28a745;
|
||||
@@ -384,10 +407,11 @@
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h2>Curate Library</h2>
|
||||
<h2>Manage Library</h2>
|
||||
<p class="setting-desc" style="margin-bottom: 12px;">
|
||||
Hide courses or whole folders from the Library browser without touching anything on disk.
|
||||
Hiding a folder hides everything inside it.
|
||||
Hide courses or whole folders from the Library browser without touching anything on disk
|
||||
(hiding a folder hides everything inside it), or rename a course/folder directly - no need
|
||||
to go to the NAS.
|
||||
</p>
|
||||
|
||||
<div id="hidden-list-wrap" style="margin-bottom: 15px; display: none;">
|
||||
@@ -395,7 +419,7 @@
|
||||
<div id="hidden-list"></div>
|
||||
</div>
|
||||
|
||||
<div style="font-weight: 600; margin-bottom: 8px; font-size: 0.9em; color: var(--text-muted);">Browse to hide</div>
|
||||
<div style="font-weight: 600; margin-bottom: 8px; font-size: 0.9em; color: var(--text-muted);">Browse</div>
|
||||
<div id="curate-path-bar" style="color: var(--text-muted); font-size: 13px; margin-bottom: 8px;"></div>
|
||||
<div id="curate-tree"></div>
|
||||
</div>
|
||||
@@ -549,9 +573,12 @@
|
||||
}
|
||||
container.innerHTML = data.items.map(item => {
|
||||
const safePath = item.path.replace(/'/g, "\\'");
|
||||
const safeName = item.name.replace(/'/g, "\\'");
|
||||
const icon = item.type === 'course' ? '🎓' : '📁';
|
||||
const hiddenClass = item.hidden ? 'is-hidden' : '';
|
||||
const renameBtn = `<button class="btn btn-secondary btn-sm" onclick="event.stopPropagation(); startRename(this, '${safePath}', '${safeName}')" title="Rename">✏️</button>`;
|
||||
const toggleBtn = `<button class="btn btn-secondary btn-sm" onclick="event.stopPropagation(); toggleHidden('${safePath}', ${!item.hidden}, this)">${item.hidden ? 'Show' : 'Hide'}</button>`;
|
||||
const actions = `<div class="curate-actions">${renameBtn}${toggleBtn}</div>`;
|
||||
|
||||
if (item.type === 'course') {
|
||||
return `
|
||||
@@ -560,7 +587,7 @@
|
||||
<span>${icon}</span>
|
||||
<span class="name">${item.name}</span>
|
||||
</div>
|
||||
${toggleBtn}
|
||||
${actions}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
@@ -571,7 +598,7 @@
|
||||
<span>${icon}</span>
|
||||
<span class="name">${item.name}</span>
|
||||
</div>
|
||||
${toggleBtn}
|
||||
${actions}
|
||||
</div>
|
||||
<div class="curate-children" data-loaded="false"></div>
|
||||
`;
|
||||
@@ -620,6 +647,83 @@
|
||||
.catch(() => {});
|
||||
}
|
||||
|
||||
// ---- Library curation: rename a course/folder in place on disk ----
|
||||
function startRename(btnEl, path, currentName) {
|
||||
const row = btnEl.closest('.curate-row');
|
||||
const nameSpan = row ? row.querySelector('.curate-row-name .name') : null;
|
||||
if (!row || !nameSpan) return;
|
||||
|
||||
let settled = false;
|
||||
const input = document.createElement('input');
|
||||
input.type = 'text';
|
||||
input.className = 'curate-rename-input';
|
||||
input.value = currentName;
|
||||
input.onclick = (e) => e.stopPropagation();
|
||||
nameSpan.replaceWith(input);
|
||||
input.focus();
|
||||
input.select();
|
||||
|
||||
function cancel() {
|
||||
if (settled) return;
|
||||
settled = true;
|
||||
input.replaceWith(nameSpan);
|
||||
}
|
||||
function commit() {
|
||||
if (settled) return;
|
||||
const newName = input.value.trim();
|
||||
if (!newName || newName === currentName) {
|
||||
cancel();
|
||||
return;
|
||||
}
|
||||
settled = true;
|
||||
submitRename(btnEl, path, newName, row, nameSpan, input);
|
||||
}
|
||||
input.addEventListener('keydown', (e) => {
|
||||
e.stopPropagation();
|
||||
if (e.key === 'Enter') { e.preventDefault(); commit(); }
|
||||
else if (e.key === 'Escape') { e.preventDefault(); cancel(); }
|
||||
});
|
||||
input.addEventListener('blur', commit);
|
||||
}
|
||||
|
||||
function submitRename(btnEl, path, newName, row, nameSpan, input) {
|
||||
fetch('/api/rename-path', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ path: path, new_name: newName })
|
||||
})
|
||||
.then(r => r.json().then(data => ({ ok: r.ok, data })))
|
||||
.then(({ ok, data }) => {
|
||||
if (!ok || !data.success) {
|
||||
input.replaceWith(nameSpan); // nameSpan still shows the original, unchanged name
|
||||
showRowError(row, data.error || 'Rename failed');
|
||||
return;
|
||||
}
|
||||
if (data.active_course_reset) {
|
||||
alert('That was your active course - reload the main page to pick it up under its new name.');
|
||||
}
|
||||
loadHiddenList();
|
||||
const container = btnEl.closest('.curate-children') || document.getElementById('curate-tree');
|
||||
const isRootContainer = container.id === 'curate-tree';
|
||||
const refreshPath = isRootContainer ? null : container.dataset.path;
|
||||
loadCurateLevel(refreshPath, container, isRootContainer);
|
||||
})
|
||||
.catch(() => {
|
||||
input.replaceWith(nameSpan);
|
||||
showRowError(row, 'Could not reach the server');
|
||||
});
|
||||
}
|
||||
|
||||
function showRowError(row, message) {
|
||||
let status = row.querySelector('.curate-row-status');
|
||||
if (!status) {
|
||||
status = document.createElement('div');
|
||||
status.className = 'curate-row-status';
|
||||
row.appendChild(status);
|
||||
}
|
||||
status.textContent = message;
|
||||
}
|
||||
|
||||
loadHiddenList();
|
||||
loadCurateLevel(null, document.getElementById('curate-tree'), true);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user