|
@@ -121,6 +121,26 @@ const Browser = (() => {
|
|
|
bindEvents(list);
|
|
bindEvents(list);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ function getDirCommonType(dirId) {
|
|
|
|
|
+ const cached = dirContents[dirId];
|
|
|
|
|
+ if (!cached) return null;
|
|
|
|
|
+ const types = new Set();
|
|
|
|
|
+ for (const track of cached.tracks) {
|
|
|
|
|
+ if (!track.trackType) return null;
|
|
|
|
|
+ types.add(track.trackType);
|
|
|
|
|
+ if (types.size > 1) return null;
|
|
|
|
|
+ }
|
|
|
|
|
+ for (const subDir of cached.dirs) {
|
|
|
|
|
+ if (!dirContents[subDir.id]) return null; // uncached sub-dir → unknown
|
|
|
|
|
+ const subType = getDirCommonType(subDir.id);
|
|
|
|
|
+ if (!subType) return null;
|
|
|
|
|
+ types.add(subType);
|
|
|
|
|
+ if (types.size > 1) return null;
|
|
|
|
|
+ }
|
|
|
|
|
+ if (types.size === 0) return null;
|
|
|
|
|
+ return [...types][0];
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
function buildTreeHtml(dirs, tracks, depth) {
|
|
function buildTreeHtml(dirs, tracks, depth) {
|
|
|
let html = '';
|
|
let html = '';
|
|
|
const baseIndent = depth * 16;
|
|
const baseIndent = depth * 16;
|
|
@@ -128,12 +148,17 @@ const Browser = (() => {
|
|
|
for (const dir of dirs) {
|
|
for (const dir of dirs) {
|
|
|
const isExpanded = expandedDirs.has(dir.id);
|
|
const isExpanded = expandedDirs.has(dir.id);
|
|
|
const isSelected = selectedDirId === dir.id;
|
|
const isSelected = selectedDirId === dir.id;
|
|
|
|
|
+ const dirType = getDirCommonType(dir.id);
|
|
|
|
|
+ const dirTypeEmoji = dirType ? TRACK_TYPE_EMOJI[dirType] : null;
|
|
|
|
|
+ const dirTypeSuffix = dirTypeEmoji
|
|
|
|
|
+ ? ` <span class="type-emoji" title="${escAttr(dirType.charAt(0).toUpperCase() + dirType.slice(1))}">${dirTypeEmoji}</span>`
|
|
|
|
|
+ : '';
|
|
|
html += `<div class="tree-item dir-item${isSelected ? ' selected' : ''}"
|
|
html += `<div class="tree-item dir-item${isSelected ? ' selected' : ''}"
|
|
|
data-id="${dir.id}" data-name="${escAttr(dir.name)}"
|
|
data-id="${dir.id}" data-name="${escAttr(dir.name)}"
|
|
|
style="padding-left:${12 + baseIndent}px" data-drop-target="true" draggable="true">
|
|
style="padding-left:${12 + baseIndent}px" data-drop-target="true" draggable="true">
|
|
|
<span class="expand-btn${isExpanded ? ' expanded' : ''}" data-expand="${dir.id}"></span>
|
|
<span class="expand-btn${isExpanded ? ' expanded' : ''}" data-expand="${dir.id}"></span>
|
|
|
<span class="item-icon">📁</span>
|
|
<span class="item-icon">📁</span>
|
|
|
- <span class="item-name">${escHtml(dir.name)}</span>
|
|
|
|
|
|
|
+ <span class="item-name">${escHtml(dir.name)}${dirTypeSuffix}</span>
|
|
|
<span class="item-date">${formatDate(dir.updatedAt)}</span>
|
|
<span class="item-date">${formatDate(dir.updatedAt)}</span>
|
|
|
<span class="item-actions">
|
|
<span class="item-actions">
|
|
|
<button class="item-btn rename-dir-btn" data-id="${dir.id}" data-name="${escAttr(dir.name)}" title="Rename">✏️</button>
|
|
<button class="item-btn rename-dir-btn" data-id="${dir.id}" data-name="${escAttr(dir.name)}" title="Rename">✏️</button>
|
|
@@ -158,13 +183,13 @@ const Browser = (() => {
|
|
|
const typeTitle = track.trackType
|
|
const typeTitle = track.trackType
|
|
|
? track.trackType.charAt(0).toUpperCase() + track.trackType.slice(1)
|
|
? track.trackType.charAt(0).toUpperCase() + track.trackType.slice(1)
|
|
|
: '';
|
|
: '';
|
|
|
- const emojiPrefix = typeEmoji
|
|
|
|
|
- ? `<span class="type-emoji" title="${escAttr(typeTitle)}">${typeEmoji}</span> `
|
|
|
|
|
|
|
+ const emojiSuffix = typeEmoji
|
|
|
|
|
+ ? ` <span class="type-emoji" title="${escAttr(typeTitle)}">${typeEmoji}</span>`
|
|
|
: '';
|
|
: '';
|
|
|
html += `<div class="tree-item track-item${isSel ? ' multi-selected' : ''}" data-id="${track.id}" draggable="true"
|
|
html += `<div class="tree-item track-item${isSel ? ' multi-selected' : ''}" data-id="${track.id}" draggable="true"
|
|
|
data-name="${escAttr(track.name)}" style="padding-left:${28 + baseIndent}px">
|
|
data-name="${escAttr(track.name)}" style="padding-left:${28 + baseIndent}px">
|
|
|
<span class="item-icon">🗺️</span>
|
|
<span class="item-icon">🗺️</span>
|
|
|
- <span class="item-name">${emojiPrefix}${escHtml(track.name)}</span>
|
|
|
|
|
|
|
+ <span class="item-name">${escHtml(track.name)}${emojiSuffix}</span>
|
|
|
<span class="item-meta">${dist}</span>
|
|
<span class="item-meta">${dist}</span>
|
|
|
<span class="item-date">${formatDate(track.trackDate || track.uploadDate)}</span>
|
|
<span class="item-date">${formatDate(track.trackDate || track.uploadDate)}</span>
|
|
|
<span class="item-actions">
|
|
<span class="item-actions">
|