diff --git a/pages/projetos.md b/pages/projetos.md
index 436c57e2..9c1cc426 100755
--- a/pages/projetos.md
+++ b/pages/projetos.md
@@ -342,10 +342,8 @@ document.addEventListener('DOMContentLoaded', () => {
const filterContent = document.getElementById('filter-content');
const filterChevron = document.getElementById('filter-chevron');
- // Define estado inicial baseado na largura da tela
let isFilterOpen = window.innerWidth > 1024;
- // Função para aplicar o estado visual
function updateFilterState() {
if(isFilterOpen) {
filterContent.style.display = 'block';
@@ -356,15 +354,12 @@ document.addEventListener('DOMContentLoaded', () => {
}
}
- // Aplica estado inicial ao carregar
- if (filterContent && filterChevron) {
- updateFilterState();
- }
+ if (filterContent && filterChevron) updateFilterState();
if(filterBtn && filterContent) {
filterBtn.addEventListener('click', () => {
- isFilterOpen = !isFilterOpen; // Inverte o estado
- updateFilterState(); // Aplica a mudança
+ isFilterOpen = !isFilterOpen;
+ updateFilterState();
});
}
@@ -418,6 +413,7 @@ document.addEventListener('DOMContentLoaded', () => {
const genreContainer = document.getElementById('genre-filters');
const sortSelect = document.getElementById('sort-select');
const starFilterSelect = document.getElementById('star-filter');
+ const keyFilterSelect = document.getElementById('key-filter'); // CORREÇÃO 1: Pegar referência
const projectsContainer = document.getElementById('projects-container');
let currentGenre = 'all';
@@ -431,39 +427,22 @@ document.addEventListener('DOMContentLoaded', () => {
})
.catch(console.warn);
- // Função atualizada para Badge de Dificuldade
function renderizarDificuldade(num) {
const n = Math.round(num) || 1;
let label = "Básico";
- let icon = "fa-leaf"; // Ícone padrão
- let colorClass = "is-success"; // Verde
+ let icon = "fa-leaf";
+ let colorClass = "is-success";
- if (n >= 4.5) {
- label = "Expert";
- icon = "fa-fire";
- colorClass = "is-danger"; // Vermelho
- } else if (n >= 3.5) {
- label = "Avançado";
- icon = "fa-bolt";
- colorClass = "is-warning"; // Amarelo/Laranja
- } else if (n >= 2.5) {
- label = "Intermediário";
- icon = "fa-layer-group";
- colorClass = "is-info"; // Azul
- }
+ if (n >= 4.5) { label = "Expert"; icon = "fa-fire"; colorClass = "is-danger"; }
+ else if (n >= 3.5) { label = "Avançado"; icon = "fa-bolt"; colorClass = "is-warning"; }
+ else if (n >= 2.5) { label = "Intermediário"; icon = "fa-layer-group"; colorClass = "is-info"; }
- // Retorna uma tag HTML bonita e visível
- return `
-
- ${label}
-
- `;
+ return ` ${label}`;
}
function enrichCards(data) {
const mapDados = {};
- // Mapeamento dos dados
data.forEach(item => {
const k1 = normalizarChaveJS(item.arquivo.replace('.wav','').replace('.mp3',''));
mapDados[k1] = item;
@@ -473,66 +452,57 @@ document.addEventListener('DOMContentLoaded', () => {
cards.forEach(card => {
const info = mapDados[normalizarChaveJS(card.dataset.title)];
- // --- 1. Definição de Valores Padrão (Safety First) ---
let genero = "Unknown";
+ let subgenerosLista = []; // CORREÇÃO 2: Array para guardar subgêneros
let estrelas = 0;
let intensidade = -100;
let bpm = 0;
let tomHtml = "";
- let tomRaw = "all"; // Valor padrão para o filtro
- let subTagsHTML = ""; // Para os subgêneros
+ let tomRaw = "all";
+ let subTagsHTML = "";
- // --- 2. Só tenta extrair dados SE 'info' existir ---
if (info) {
- // Dados IA
if (info.analise_ia) {
genero = info.analise_ia.genero_macro || "Unknown";
- // Lógica de Subgêneros (Top 2)
+ // Captura subgêneros para o Filtro e Visual
if (Array.isArray(info.analise_ia.nuvem_tags)) {
+ // Filtro: Pega todas as tags relevantes
+ info.analise_ia.nuvem_tags.forEach(t => {
+ if(t.tag) subgenerosLista.push(t.tag);
+ });
+
+ // Visual: Pega top 2 para mostrar
const topTags = info.analise_ia.nuvem_tags.slice(0, 2);
topTags.forEach(t => {
- // Multiplica por 100 para porcentagem legível
const scorePercent = Math.round((t.score || 0) * 100);
- subTagsHTML += `
-
- #${t.tag}
- `;
+ subTagsHTML += `#${t.tag}`;
});
}
}
- // Dados Técnicos
if (info.analise_tecnica) {
intensidade = parseFloat(info.analise_tecnica.intensidade_db || -100);
bpm = parseFloat(info.analise_tecnica.bpm || 0);
- // Correção: Usando Math.round para bater com o visual
estrelas = Math.round(info.analise_tecnica.complexidade?.estrelas || 0);
- // Lógica do Tom (Visual + Filtro)
if (info.analise_tecnica.tom) {
const t = info.analise_tecnica.tom;
const e = info.analise_tecnica.escala === 'minor' ? 'm' : '';
-
- // HTML visual (Badge)
tomHtml = `🎹 ${t}${e}`;
-
- // Valor cru para o filtro (Ex: "C", "Cm", "Ab")
tomRaw = t + e;
}
}
}
- // --- 3. Salva no Dataset para os Filtros ---
card.dataset.genre = genero;
+ // CORREÇÃO 3: Salva subgêneros no dataset como string separada por vírgula
+ card.dataset.subgenres = subgenerosLista.join(',').toLowerCase();
card.dataset.stars = estrelas;
card.dataset.intensity = intensidade;
card.dataset.bpm_real = bpm;
- card.dataset.key = tomRaw; // Novo dataset para o filtro de Tom
+ card.dataset.key = tomRaw;
- // --- 4. Renderização no DOM ---
const bpmContainer = card.querySelector('.bpm-container');
if (bpmContainer) {
const iaDiv = document.createElement('div');
@@ -542,14 +512,12 @@ document.addEventListener('DOMContentLoaded', () => {
iaDiv.style.gap = "6px";
iaDiv.className = "mt-3";
- // Dificuldade
const diffDiv = document.createElement('div');
diffDiv.innerHTML = renderizarDificuldade(estrelas);
iaDiv.appendChild(diffDiv);
- // Tags (Gênero Macro + Tom)
const tagsRow = document.createElement('div');
- tagsRow.className = "tags is-centered mb-1"; // mb-1 para dar espaço pros subgeneros
+ tagsRow.className = "tags is-centered mb-1";
tagsRow.style.gap = "4px";
if(genero !== "Unknown") {
@@ -557,14 +525,12 @@ document.addEventListener('DOMContentLoaded', () => {
if(genero === 'Electronic') color = 'is-info';
if(genero === 'Hip Hop') color = 'is-warning';
if(genero === 'Rock') color = 'is-danger';
-
tagsRow.innerHTML += `🤖 ${genero}`;
}
tagsRow.innerHTML += tomHtml;
iaDiv.appendChild(tagsRow);
- // Nova Linha: Subgêneros
if (subTagsHTML) {
const subTagsRow = document.createElement('div');
subTagsRow.className = "tags is-centered mb-0";
@@ -573,7 +539,6 @@ document.addEventListener('DOMContentLoaded', () => {
iaDiv.appendChild(subTagsRow);
}
- // Limpa e reinsere
bpmContainer.innerHTML = '';
if(card.dataset.bpm_real > 0) {
bpmContainer.innerHTML = `🎵 ${Math.round(card.dataset.bpm_real)} BPM`;
@@ -586,14 +551,23 @@ document.addEventListener('DOMContentLoaded', () => {
function createGenreButtons(data) {
const genres = new Set();
data.forEach(i => {
+ // Macro Gênero
if(i.analise_ia?.genero_macro && i.analise_ia.genero_macro !== "Unknown")
genres.add(i.analise_ia.genero_macro);
+
+ // CORREÇÃO 4: Adicionar Subgêneros aos filtros
+ if(Array.isArray(i.analise_ia?.nuvem_tags)) {
+ i.analise_ia.nuvem_tags.forEach(t => {
+ // Adiciona se tiver tag e um score razoável (opcional, aqui pegamos tudo)
+ if(t.tag) genres.add(t.tag);
+ });
+ }
});
Array.from(genres).sort().forEach(g => {
const btn = document.createElement('button');
btn.className = 'button is-small is-rounded is-white';
- btn.textContent = g;
+ btn.textContent = g; // Exibe o nome do gênero
btn.onclick = () => {
document.querySelectorAll('#genre-filters .button').forEach(b => {
b.classList.remove('is-active', 'is-info');
@@ -607,7 +581,6 @@ document.addEventListener('DOMContentLoaded', () => {
genreContainer.appendChild(btn);
});
- // Reset All Button
const allBtn = genreContainer.querySelector('[data-genre="all"]');
allBtn.onclick = () => {
document.querySelectorAll('#genre-filters .button').forEach(b => {
@@ -623,13 +596,26 @@ document.addEventListener('DOMContentLoaded', () => {
function applyFilters() {
cards.forEach(c => {
- const col = c.closest('.project-column');
- const g = c.dataset.genre;
- const s = parseInt(c.dataset.stars || 0);
- const k = c.dataset.key || 'all'; // Pega o tom salvo no card
const currentKey = document.getElementById('key-filter')?.value || 'all';
+ const col = c.closest('.project-column');
- const matchG = (currentGenre === 'all' || g === currentGenre);
+ const g = c.dataset.genre; // Gênero Macro
+ const sub = c.dataset.subgenres || ""; // Lista de subgêneros (string)
+
+ const s = parseInt(c.dataset.stars || 0);
+ const k = c.dataset.key || 'all';
+
+ // CORREÇÃO 5: Lógica de Filtro Aprimorada
+ // Verifica se o gênero selecionado bate com o Macro OU se está contido nos subgêneros
+ let matchG = false;
+ if (currentGenre === 'all') {
+ matchG = true;
+ } else {
+ // Verifica match exato com Macro OU include na lista de subs
+ if (g === currentGenre) matchG = true;
+ if (sub.includes(currentGenre.toLowerCase())) matchG = true;
+ }
+
const matchS = (currentMinStars === 'all' || s === parseInt(currentMinStars));
const matchK = (currentKey === 'all' || k === currentKey);
@@ -644,6 +630,13 @@ document.addEventListener('DOMContentLoaded', () => {
});
}
+ // CORREÇÃO 6: Adicionando o Event Listener para o Tom
+ if(keyFilterSelect) {
+ keyFilterSelect.addEventListener('change', () => {
+ applyFilters();
+ });
+ }
+
sortSelect.addEventListener('change', (e) => {
const crit = e.target.value;
const cols = Array.from(projectsContainer.children);