Teste de filtros de projetos
Deploy / Deploy (push) Successful in 1m21s
Details
Deploy / Deploy (push) Successful in 1m21s
Details
This commit is contained in:
parent
fc6f447be4
commit
dd837d6d6b
|
|
@ -37,6 +37,26 @@ permalink: /projetos/
|
|||
|
||||
<div class="column is-narrow">
|
||||
<div class="field has-addons">
|
||||
|
||||
<div class="control">
|
||||
<span class="button is-static is-small is-rounded">
|
||||
<i class="fa-solid fa-star"></i>
|
||||
</span>
|
||||
</div>
|
||||
<div class="control">
|
||||
<div class="select is-small">
|
||||
<select id="star-filter">
|
||||
<option value="all">Todas Complexidades</option>
|
||||
<option value="5">⭐⭐⭐⭐⭐ (5) Expert</option>
|
||||
<option value="4">⭐⭐⭐⭐ (4+) Avançado</option>
|
||||
<option value="3">⭐⭐⭐ (3+) Intermediário</option>
|
||||
<option value="2">⭐⭐ (2+) Básico</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="control"><span class="mx-1"></span></div>
|
||||
|
||||
<div class="control">
|
||||
<a class="button is-static is-small is-rounded">
|
||||
<i class="fa-solid fa-sort"></i>
|
||||
|
|
@ -46,6 +66,8 @@ permalink: /projetos/
|
|||
<div class="select is-small is-rounded">
|
||||
<select id="sort-select">
|
||||
<option value="default">Ordem Padrão</option>
|
||||
<option value="stars_desc">⭐ Mais Complexos</option>
|
||||
<option value="stars_asc">⭐ Mais Simples</option>
|
||||
<option value="intensity_desc">🔥 Mais Intensos (dB)</option>
|
||||
<option value="intensity_asc">❄️ Mais Calmos (dB)</option>
|
||||
<option value="bpm_desc">⚡ BPM (Rápido)</option>
|
||||
|
|
@ -53,6 +75,7 @@ permalink: /projetos/
|
|||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -260,7 +283,7 @@ permalink: /projetos/
|
|||
<script>
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
// ===============================================
|
||||
// 1. CONFIGURAÇÃO E MODAL (Existente)
|
||||
// 1. CONFIGURAÇÃO E MODAL
|
||||
// ===============================================
|
||||
const modal = document.getElementById('preview-modal');
|
||||
const iframe = document.getElementById('preview-iframe');
|
||||
|
|
@ -304,17 +327,21 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||
document.addEventListener('keydown', (e) => { if (e.key === "Escape") closeModal(); });
|
||||
|
||||
// ===============================================
|
||||
// 2. LÓGICA DE INTEGRAÇÃO COM IA (Novo)
|
||||
// 2. LÓGICA DE DADOS (IA / FILTROS / ORDENAÇÃO)
|
||||
// ===============================================
|
||||
|
||||
// URL para o JSON que você gerou com o Python. Ajuste se necessário.
|
||||
const JSON_URL = '/mmpSearch/src_mmpSearch/saida_analises/db_final_completo.json';
|
||||
|
||||
const cards = document.querySelectorAll('.project-card');
|
||||
const genreContainer = document.getElementById('genre-filters');
|
||||
const sortSelect = document.getElementById('sort-select');
|
||||
const starFilterSelect = document.getElementById('star-filter'); // NOVO SELETOR
|
||||
const projectsContainer = document.getElementById('projects-container');
|
||||
|
||||
// Estado global dos filtros
|
||||
let currentGenre = 'all';
|
||||
let currentMinStars = 'all';
|
||||
|
||||
// Inicializa a carga de dados
|
||||
fetch(JSON_URL)
|
||||
.then(response => {
|
||||
|
|
@ -328,19 +355,19 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||
})
|
||||
.catch(err => {
|
||||
console.warn("Aviso: Dados da IA não puderam ser carregados.", err);
|
||||
// Oculta os filtros se não houver dados
|
||||
const filterBox = document.querySelector('.box.has-background-white-ter');
|
||||
if(filterBox) filterBox.style.display = 'none';
|
||||
});
|
||||
|
||||
// Função auxiliar para gerar estrelas HTML
|
||||
function gerarEstrelas(num) {
|
||||
let html = '<span class="has-text-warning" title="Nível de Complexidade Técnica">';
|
||||
for (let i = 0; i < 5; i++) {
|
||||
if (i < num) {
|
||||
html += '<i class="fa-solid fa-star"></i>'; // Estrela cheia
|
||||
// Garante que num seja inteiro
|
||||
const n = Math.round(num);
|
||||
let html = '<span class="has-text-warning" title="Nível de Complexidade: '+n+'/5">';
|
||||
for (let i = 1; i <= 5; i++) {
|
||||
if (i <= n) {
|
||||
html += '<i class="fa-solid fa-star"></i>';
|
||||
} else {
|
||||
html += '<i class="fa-regular fa-star"></i>'; // Estrela vazia
|
||||
html += '<i class="fa-regular fa-star" style="opacity:0.4"></i>';
|
||||
}
|
||||
}
|
||||
html += '</span>';
|
||||
|
|
@ -348,7 +375,6 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||
}
|
||||
|
||||
function enrichCards(data) {
|
||||
// 1. Cria um mapa para busca rápida
|
||||
const mapDados = {};
|
||||
data.forEach(item => {
|
||||
const keyArquivo = normalizarChaveJS(item.arquivo.replace('.wav','').replace('.mp3',''));
|
||||
|
|
@ -362,56 +388,55 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||
|
||||
cards.forEach(card => {
|
||||
const cardKey = normalizarChaveJS(card.dataset.title);
|
||||
// 2. Busca instantânea
|
||||
const info = mapDados[cardKey];
|
||||
|
||||
if (info) {
|
||||
// --- 1. Metadados para Filtros ---
|
||||
card.dataset.genre = (info.analise_ia && info.analise_ia.genero_macro) ? info.analise_ia.genero_macro : "Unknown";
|
||||
card.dataset.intensity = (info.analise_tecnica && info.analise_tecnica.intensidade_db) ? parseFloat(info.analise_tecnica.intensidade_db) : 0;
|
||||
card.dataset.bpm_real = (info.analise_tecnica && info.analise_tecnica.bpm) ? parseFloat(info.analise_tecnica.bpm) : 0;
|
||||
|
||||
// --- 2. Lógica das Estrelas ---
|
||||
let numeroEstrelas = 0;
|
||||
// Verifica se existe o objeto complexidade e o valor estrelas
|
||||
if (info.analise_tecnica && info.analise_tecnica.complexidade && info.analise_tecnica.complexidade.estrelas) {
|
||||
numeroEstrelas = info.analise_tecnica.complexidade.estrelas;
|
||||
// --- 1. Extração de Dados ---
|
||||
const genero = (info.analise_ia?.genero_macro) || "Unknown";
|
||||
const intensidade = (info.analise_tecnica?.intensidade_db) ? parseFloat(info.analise_tecnica.intensidade_db) : -100;
|
||||
const bpm = (info.analise_tecnica?.bpm) ? parseFloat(info.analise_tecnica.bpm) : 0;
|
||||
|
||||
// Extração segura das estrelas
|
||||
let estrelas = 0;
|
||||
if (info.analise_tecnica?.complexidade?.estrelas) {
|
||||
estrelas = parseInt(info.analise_tecnica.complexidade.estrelas);
|
||||
}
|
||||
const estrelasHTML = gerarEstrelas(numeroEstrelas);
|
||||
|
||||
// --- 3. Injeção Visual (HTML) ---
|
||||
// --- 2. Atualiza Dataset do HTML (Para filtros funcionarem) ---
|
||||
card.dataset.genre = genero;
|
||||
card.dataset.intensity = intensidade;
|
||||
card.dataset.bpm_real = bpm;
|
||||
card.dataset.stars = estrelas; // Importante para ordenação
|
||||
|
||||
// --- 3. Renderização Visual ---
|
||||
const bpmContainer = card.querySelector('.bpm-container');
|
||||
|
||||
if (bpmContainer) {
|
||||
// Cria container para as novas tags
|
||||
const iaTagsDiv = document.createElement('div');
|
||||
iaTagsDiv.className = "tags is-centered mt-1 mb-3";
|
||||
iaTagsDiv.style.opacity = "0.9";
|
||||
iaTagsDiv.style.flexDirection = "column"; // Organiza em linhas (estrelas em cima, tags em baixo)
|
||||
iaTagsDiv.style.flexDirection = "column";
|
||||
|
||||
let htmlFinal = '';
|
||||
|
||||
// A) Adiciona as Estrelas
|
||||
htmlFinal += `<div class="mb-1" style="font-size: 0.8rem;">${estrelasHTML}</div>`;
|
||||
// Renderiza Estrelas (mesmo que seja 0, mostra estrelas vazias)
|
||||
htmlFinal += `<div class="mb-1" style="font-size: 0.8rem;">${gerarEstrelas(estrelas)}</div>`;
|
||||
|
||||
// Container para as tags (Genero + Tom)
|
||||
htmlFinal += '<div class="tags is-centered">';
|
||||
|
||||
// B) Tag de Gênero IA
|
||||
if (info.analise_ia.genero_macro && info.analise_ia.genero_macro !== "Unknown") {
|
||||
const genero = info.analise_ia.genero_macro;
|
||||
// Tag Gênero
|
||||
if (genero !== "Unknown") {
|
||||
let colorClass = 'is-primary';
|
||||
if(genero === 'Electronic') colorClass = 'is-info';
|
||||
if(genero === 'Hip Hop') colorClass = 'is-warning';
|
||||
if(genero === 'Rock') colorClass = 'is-danger';
|
||||
|
||||
htmlFinal += `<span class="tag ${colorClass} is-light is-rounded mr-1" style="font-size: 0.65rem;" title="Gênero IA">
|
||||
htmlFinal += `<span class="tag ${colorClass} is-light is-rounded mr-1" style="font-size: 0.65rem;">
|
||||
🤖 ${genero}
|
||||
</span>`;
|
||||
}
|
||||
|
||||
// C) Tag de Tom (Musical Key)
|
||||
if (info.analise_tecnica.tom) {
|
||||
// Tag Tom
|
||||
if (info.analise_tecnica?.tom) {
|
||||
const nota = info.analise_tecnica.tom;
|
||||
const escala = info.analise_tecnica.escala === 'minor' ? 'm' : '';
|
||||
htmlFinal += `<span class="tag is-white is-rounded" style="font-size: 0.65rem; border: 1px solid #ddd; color: #555;">
|
||||
|
|
@ -419,70 +444,86 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||
</span>`;
|
||||
}
|
||||
|
||||
htmlFinal += '</div>'; // Fecha container tags
|
||||
|
||||
htmlFinal += '</div>';
|
||||
iaTagsDiv.innerHTML = htmlFinal;
|
||||
bpmContainer.appendChild(iaTagsDiv);
|
||||
}
|
||||
} else {
|
||||
// Se não achou dados
|
||||
// Valores padrão se não achar dados
|
||||
card.dataset.genre = "Outros";
|
||||
card.dataset.intensity = -1;
|
||||
card.dataset.intensity = -100;
|
||||
card.dataset.stars = 0;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function createGenreButtons(data) {
|
||||
// Extrai lista única de gêneros encontrados
|
||||
const genres = new Set();
|
||||
data.forEach(item => {
|
||||
if(item.analise_ia && item.analise_ia.genero_macro && item.analise_ia.genero_macro !== "Unknown") {
|
||||
if(item.analise_ia?.genero_macro && item.analise_ia.genero_macro !== "Unknown") {
|
||||
genres.add(item.analise_ia.genero_macro);
|
||||
}
|
||||
});
|
||||
|
||||
// Cria botões HTML
|
||||
const genresArray = Array.from(genres).sort();
|
||||
genresArray.forEach(genre => {
|
||||
const btn = document.createElement('button');
|
||||
btn.className = 'button is-small is-rounded';
|
||||
btn.className = 'button is-small is-rounded is-white'; // Começa branco
|
||||
btn.textContent = genre;
|
||||
btn.dataset.genre = genre;
|
||||
|
||||
btn.addEventListener('click', () => {
|
||||
// Lógica de Ativação Visual
|
||||
// UI Update
|
||||
const allBtns = genreContainer.querySelectorAll('.button');
|
||||
allBtns.forEach(b => {
|
||||
b.classList.remove('is-active', 'is-info');
|
||||
// Volta botões inativos para branco
|
||||
if(b !== btn) b.classList.add('is-white');
|
||||
b.classList.add('is-white');
|
||||
});
|
||||
|
||||
btn.classList.remove('is-white');
|
||||
btn.classList.add('is-active', 'is-info');
|
||||
|
||||
filterCards(genre);
|
||||
// Logic Update
|
||||
currentGenre = genre;
|
||||
applyFilters();
|
||||
});
|
||||
|
||||
genreContainer.appendChild(btn);
|
||||
});
|
||||
|
||||
// Re-bind do botão "Todos"
|
||||
// Botão Todos
|
||||
const allBtn = genreContainer.querySelector('[data-genre="all"]');
|
||||
allBtn.addEventListener('click', () => {
|
||||
genreContainer.querySelectorAll('.button').forEach(b => b.classList.remove('is-active', 'is-info'));
|
||||
genreContainer.querySelectorAll('.button').forEach(b => {
|
||||
b.classList.remove('is-active', 'is-info');
|
||||
b.classList.add('is-white');
|
||||
});
|
||||
allBtn.classList.remove('is-white');
|
||||
allBtn.classList.add('is-active', 'is-info');
|
||||
filterCards('all');
|
||||
|
||||
currentGenre = 'all';
|
||||
applyFilters();
|
||||
});
|
||||
}
|
||||
|
||||
function filterCards(selectedGenre) {
|
||||
cards.forEach(card => {
|
||||
// Encontra a coluna pai para esconder tudo (layout grid)
|
||||
// Lógica Unificada de Filtros
|
||||
function applyFilters() {
|
||||
cards.forEach(card => {
|
||||
const column = card.closest('.project-column');
|
||||
|
||||
// 1. Checa Gênero
|
||||
const cardGenre = card.dataset.genre;
|
||||
const matchGenre = (currentGenre === 'all' || cardGenre === currentGenre);
|
||||
|
||||
if (selectedGenre === 'all' || cardGenre === selectedGenre) {
|
||||
// 2. Checa Estrelas (Mínimo)
|
||||
const cardStars = parseInt(card.dataset.stars) || 0;
|
||||
let matchStars = true;
|
||||
if (currentMinStars !== 'all') {
|
||||
const min = parseInt(currentMinStars);
|
||||
matchStars = (cardStars >= min);
|
||||
}
|
||||
|
||||
// Exibe apenas se passar nos DOIS filtros
|
||||
if (matchGenre && matchStars) {
|
||||
column.style.display = 'block';
|
||||
} else {
|
||||
column.style.display = 'none';
|
||||
|
|
@ -490,6 +531,14 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||
});
|
||||
}
|
||||
|
||||
// Evento do Dropdown de Estrelas
|
||||
if(starFilterSelect) {
|
||||
starFilterSelect.addEventListener('change', (e) => {
|
||||
currentMinStars = e.target.value;
|
||||
applyFilters();
|
||||
});
|
||||
}
|
||||
|
||||
// Ordenação
|
||||
sortSelect.addEventListener('change', (e) => {
|
||||
const criteria = e.target.value;
|
||||
|
|
@ -499,25 +548,26 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||
const cardA = colA.querySelector('.project-card');
|
||||
const cardB = colB.querySelector('.project-card');
|
||||
|
||||
// Valores padrão caso não tenha dados
|
||||
const intensityA = parseFloat(cardA.dataset.intensity) || 0;
|
||||
const intensityB = parseFloat(cardB.dataset.intensity) || 0;
|
||||
const intensityA = parseFloat(cardA.dataset.intensity) || -100;
|
||||
const intensityB = parseFloat(cardB.dataset.intensity) || -100;
|
||||
const bpmA = parseFloat(cardA.dataset.bpm_real) || 0;
|
||||
const bpmB = parseFloat(cardB.dataset.bpm_real) || 0;
|
||||
const starsA = parseInt(cardA.dataset.stars) || 0;
|
||||
const starsB = parseInt(cardB.dataset.stars) || 0;
|
||||
|
||||
// Lógica de comparação
|
||||
if (criteria === 'intensity_desc') return intensityB - intensityA;
|
||||
if (criteria === 'intensity_asc') return intensityA - intensityB;
|
||||
if (criteria === 'bpm_desc') return bpmB - bpmA;
|
||||
if (criteria === 'bpm_asc') return bpmA - bpmB;
|
||||
// Novas ordenações
|
||||
if (criteria === 'stars_desc') return starsB - starsA;
|
||||
if (criteria === 'stars_asc') return starsA - starsB;
|
||||
|
||||
// Padrão (Ordem alfabética do título original)
|
||||
const titleA = cardA.dataset.title.toLowerCase();
|
||||
const titleB = cardB.dataset.title.toLowerCase();
|
||||
return titleA.localeCompare(titleB);
|
||||
});
|
||||
|
||||
// Re-anexa os elementos na nova ordem
|
||||
columns.forEach(col => projectsContainer.appendChild(col));
|
||||
});
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue