155 lines
5.6 KiB
JavaScript
155 lines
5.6 KiB
JavaScript
// js/ui.js
|
|
import { playSample } from "./pattern/pattern_audio.js";
|
|
import { renderPatternEditor } from "./pattern/pattern_ui.js";
|
|
import { renderAudioEditor } from "./audio/audio_ui.js";
|
|
import { loadProjectFromServer } from "./file.js";
|
|
|
|
let samplePathMap = {};
|
|
|
|
export function renderAll() {
|
|
renderPatternEditor();
|
|
renderAudioEditor();
|
|
const loopArea = document.getElementById("loop-region");
|
|
|
|
if (loopArea) {
|
|
// Sincroniza a visibilidade da área de loop com o estado atual
|
|
loopArea.classList.toggle("visible", appState.global.isLoopActive);
|
|
}
|
|
}
|
|
|
|
export function getSamplePathMap() {
|
|
return samplePathMap;
|
|
}
|
|
|
|
function buildSamplePathMap(tree, currentPath) {
|
|
for (const key in tree) {
|
|
if (key === "_isFile") continue;
|
|
const node = tree[key];
|
|
const newPath = `${currentPath}/${key}`;
|
|
if (node._isFile) {
|
|
samplePathMap[key] = newPath;
|
|
} else {
|
|
buildSamplePathMap(node, newPath);
|
|
}
|
|
}
|
|
}
|
|
|
|
export async function loadAndRenderSampleBrowser() {
|
|
const browserContent = document.getElementById("browser-content");
|
|
try {
|
|
const response = await fetch(`metadata/samples-manifest.json?v=${Date.now()}`);
|
|
if (!response.ok) throw new Error("Arquivo samples-manifest.json não encontrado.");
|
|
const fileTree = await response.json();
|
|
|
|
samplePathMap = {};
|
|
buildSamplePathMap(fileTree, "src/samples");
|
|
|
|
renderFileTree(fileTree, browserContent, "src/samples");
|
|
} catch (error) {
|
|
console.error("Erro ao carregar samples:", error);
|
|
browserContent.innerHTML = `<p style="color:var(--accent-red); padding: 10px;">${error.message}</p>`;
|
|
}
|
|
}
|
|
|
|
// Em ui.js, substitua a função antiga por esta:
|
|
|
|
function renderFileTree(tree, parentElement, currentPath) {
|
|
parentElement.innerHTML = ""; // Limpa o conteúdo anterior
|
|
const ul = document.createElement("ul");
|
|
|
|
// Ordena para que as pastas sempre apareçam antes dos arquivos
|
|
const sortedKeys = Object.keys(tree).sort((a, b) => {
|
|
const aIsFile = tree[a]._isFile;
|
|
const bIsFile = tree[b]._isFile;
|
|
if (aIsFile === bIsFile) return a.localeCompare(b); // Ordena alfabeticamente se ambos forem do mesmo tipo
|
|
return aIsFile ? 1 : -1; // Pastas (-1) vêm antes de arquivos (1)
|
|
});
|
|
|
|
for (const key of sortedKeys) {
|
|
if (key === '_isFile') continue; // Pula a propriedade de metadados
|
|
|
|
const node = tree[key];
|
|
const li = document.createElement("li");
|
|
const newPath = `${currentPath}/${key}`;
|
|
|
|
if (node._isFile) {
|
|
// --- LÓGICA PARA ARQUIVOS ---
|
|
li.className = "file-item draggable-sample"; // CORREÇÃO: Adiciona classe para consistência
|
|
li.innerHTML = `<i class="fa-solid fa-volume-high"></i> ${key}`; // Ícone mais apropriado
|
|
li.setAttribute("draggable", true);
|
|
li.dataset.path = newPath; // Guarda o caminho para o drag-and-drop
|
|
|
|
li.addEventListener("click", (e) => {
|
|
e.stopPropagation();
|
|
playSample(newPath, null);
|
|
});
|
|
|
|
li.addEventListener("dragstart", (e) => {
|
|
e.dataTransfer.setData("text/plain", newPath);
|
|
e.dataTransfer.effectAllowed = "copy";
|
|
});
|
|
|
|
ul.appendChild(li);
|
|
|
|
} else {
|
|
// --- LÓGICA CORRIGIDA PARA PASTAS ---
|
|
li.className = "folder-item"; // CORREÇÃO 1: Usa a classe CSS correta
|
|
|
|
// CORREÇÃO 2: Cria o <span> clicável para o nome da pasta, que o CSS e o main.js esperam
|
|
const folderNameSpan = document.createElement("span");
|
|
folderNameSpan.className = "folder-name";
|
|
folderNameSpan.innerHTML = `<i class="folder-icon fa-solid fa-folder"></i> ${key}`;
|
|
li.appendChild(folderNameSpan);
|
|
|
|
const nestedUl = document.createElement("ul");
|
|
nestedUl.className = "file-list"; // CORREÇÃO: Adiciona classe para o CSS
|
|
|
|
// Chama a função recursivamente para os conteúdos da pasta
|
|
renderFileTree(node, nestedUl, newPath);
|
|
li.appendChild(nestedUl);
|
|
|
|
// CORREÇÃO 3: Remove o addEventListener de clique daqui. O main.js já cuida disso.
|
|
|
|
ul.appendChild(li);
|
|
}
|
|
}
|
|
parentElement.appendChild(ul);
|
|
}
|
|
|
|
export async function showOpenProjectModal() {
|
|
const openProjectModal = document.getElementById("open-project-modal");
|
|
const serverProjectsList = document.getElementById("server-projects-list");
|
|
serverProjectsList.innerHTML = "<p>Carregando...</p>";
|
|
openProjectModal.classList.add("visible");
|
|
try {
|
|
const response = await fetch("metadata/mmp-manifest.json");
|
|
if (!response.ok) throw new Error("Arquivo mmp-manifest.json não encontrado.");
|
|
const projects = await response.json();
|
|
|
|
serverProjectsList.innerHTML = "";
|
|
if (projects.length === 0) {
|
|
serverProjectsList.innerHTML = '<p style="color:var(--text-dark);">Nenhum projeto encontrado no servidor.</p>';
|
|
}
|
|
|
|
projects.forEach((projectName) => {
|
|
const projectItem = document.createElement("div");
|
|
projectItem.className = "project-item";
|
|
projectItem.textContent = projectName;
|
|
projectItem.addEventListener("click", async () => {
|
|
const success = await loadProjectFromServer(projectName);
|
|
if (success) {
|
|
closeOpenProjectModal();
|
|
}
|
|
});
|
|
serverProjectsList.appendChild(projectItem);
|
|
});
|
|
} catch (error) {
|
|
console.error("Erro ao carregar lista de projetos:", error);
|
|
serverProjectsList.innerHTML = `<p style="color:var(--accent-red);">${error.message}</p>`;
|
|
}
|
|
}
|
|
|
|
export function closeOpenProjectModal() {
|
|
const openProjectModal = document.getElementById("open-project-modal");
|
|
openProjectModal.classList.remove("visible");
|
|
} |