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="column is-narrow">
|
||||||
<div class="field has-addons">
|
<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">
|
<div class="control">
|
||||||
<a class="button is-static is-small is-rounded">
|
<a class="button is-static is-small is-rounded">
|
||||||
<i class="fa-solid fa-sort"></i>
|
<i class="fa-solid fa-sort"></i>
|
||||||
|
|
@ -46,6 +66,8 @@ permalink: /projetos/
|
||||||
<div class="select is-small is-rounded">
|
<div class="select is-small is-rounded">
|
||||||
<select id="sort-select">
|
<select id="sort-select">
|
||||||
<option value="default">Ordem Padrão</option>
|
<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_desc">🔥 Mais Intensos (dB)</option>
|
||||||
<option value="intensity_asc">❄️ Mais Calmos (dB)</option>
|
<option value="intensity_asc">❄️ Mais Calmos (dB)</option>
|
||||||
<option value="bpm_desc">⚡ BPM (Rápido)</option>
|
<option value="bpm_desc">⚡ BPM (Rápido)</option>
|
||||||
|
|
@ -53,6 +75,7 @@ permalink: /projetos/
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -260,7 +283,7 @@ permalink: /projetos/
|
||||||
<script>
|
<script>
|
||||||
document.addEventListener('DOMContentLoaded', () => {
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
// ===============================================
|
// ===============================================
|
||||||
// 1. CONFIGURAÇÃO E MODAL (Existente)
|
// 1. CONFIGURAÇÃO E MODAL
|
||||||
// ===============================================
|
// ===============================================
|
||||||
const modal = document.getElementById('preview-modal');
|
const modal = document.getElementById('preview-modal');
|
||||||
const iframe = document.getElementById('preview-iframe');
|
const iframe = document.getElementById('preview-iframe');
|
||||||
|
|
@ -304,17 +327,21 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||||
document.addEventListener('keydown', (e) => { if (e.key === "Escape") closeModal(); });
|
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 JSON_URL = '/mmpSearch/src_mmpSearch/saida_analises/db_final_completo.json';
|
||||||
|
|
||||||
const cards = document.querySelectorAll('.project-card');
|
const cards = document.querySelectorAll('.project-card');
|
||||||
const genreContainer = document.getElementById('genre-filters');
|
const genreContainer = document.getElementById('genre-filters');
|
||||||
const sortSelect = document.getElementById('sort-select');
|
const sortSelect = document.getElementById('sort-select');
|
||||||
|
const starFilterSelect = document.getElementById('star-filter'); // NOVO SELETOR
|
||||||
const projectsContainer = document.getElementById('projects-container');
|
const projectsContainer = document.getElementById('projects-container');
|
||||||
|
|
||||||
|
// Estado global dos filtros
|
||||||
|
let currentGenre = 'all';
|
||||||
|
let currentMinStars = 'all';
|
||||||
|
|
||||||
// Inicializa a carga de dados
|
// Inicializa a carga de dados
|
||||||
fetch(JSON_URL)
|
fetch(JSON_URL)
|
||||||
.then(response => {
|
.then(response => {
|
||||||
|
|
@ -328,19 +355,19 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||||
})
|
})
|
||||||
.catch(err => {
|
.catch(err => {
|
||||||
console.warn("Aviso: Dados da IA não puderam ser carregados.", 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');
|
const filterBox = document.querySelector('.box.has-background-white-ter');
|
||||||
if(filterBox) filterBox.style.display = 'none';
|
if(filterBox) filterBox.style.display = 'none';
|
||||||
});
|
});
|
||||||
|
|
||||||
// Função auxiliar para gerar estrelas HTML
|
|
||||||
function gerarEstrelas(num) {
|
function gerarEstrelas(num) {
|
||||||
let html = '<span class="has-text-warning" title="Nível de Complexidade Técnica">';
|
// Garante que num seja inteiro
|
||||||
for (let i = 0; i < 5; i++) {
|
const n = Math.round(num);
|
||||||
if (i < num) {
|
let html = '<span class="has-text-warning" title="Nível de Complexidade: '+n+'/5">';
|
||||||
html += '<i class="fa-solid fa-star"></i>'; // Estrela cheia
|
for (let i = 1; i <= 5; i++) {
|
||||||
|
if (i <= n) {
|
||||||
|
html += '<i class="fa-solid fa-star"></i>';
|
||||||
} else {
|
} 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>';
|
html += '</span>';
|
||||||
|
|
@ -348,7 +375,6 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
function enrichCards(data) {
|
function enrichCards(data) {
|
||||||
// 1. Cria um mapa para busca rápida
|
|
||||||
const mapDados = {};
|
const mapDados = {};
|
||||||
data.forEach(item => {
|
data.forEach(item => {
|
||||||
const keyArquivo = normalizarChaveJS(item.arquivo.replace('.wav','').replace('.mp3',''));
|
const keyArquivo = normalizarChaveJS(item.arquivo.replace('.wav','').replace('.mp3',''));
|
||||||
|
|
@ -362,56 +388,55 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||||
|
|
||||||
cards.forEach(card => {
|
cards.forEach(card => {
|
||||||
const cardKey = normalizarChaveJS(card.dataset.title);
|
const cardKey = normalizarChaveJS(card.dataset.title);
|
||||||
// 2. Busca instantânea
|
|
||||||
const info = mapDados[cardKey];
|
const info = mapDados[cardKey];
|
||||||
|
|
||||||
if (info) {
|
if (info) {
|
||||||
// --- 1. Metadados para Filtros ---
|
// --- 1. Extração de Dados ---
|
||||||
card.dataset.genre = (info.analise_ia && info.analise_ia.genero_macro) ? info.analise_ia.genero_macro : "Unknown";
|
const genero = (info.analise_ia?.genero_macro) || "Unknown";
|
||||||
card.dataset.intensity = (info.analise_tecnica && info.analise_tecnica.intensidade_db) ? parseFloat(info.analise_tecnica.intensidade_db) : 0;
|
const intensidade = (info.analise_tecnica?.intensidade_db) ? parseFloat(info.analise_tecnica.intensidade_db) : -100;
|
||||||
card.dataset.bpm_real = (info.analise_tecnica && info.analise_tecnica.bpm) ? parseFloat(info.analise_tecnica.bpm) : 0;
|
const bpm = (info.analise_tecnica?.bpm) ? parseFloat(info.analise_tecnica.bpm) : 0;
|
||||||
|
|
||||||
// --- 2. Lógica das Estrelas ---
|
// Extração segura das estrelas
|
||||||
let numeroEstrelas = 0;
|
let estrelas = 0;
|
||||||
// Verifica se existe o objeto complexidade e o valor estrelas
|
if (info.analise_tecnica?.complexidade?.estrelas) {
|
||||||
if (info.analise_tecnica && info.analise_tecnica.complexidade && info.analise_tecnica.complexidade.estrelas) {
|
estrelas = parseInt(info.analise_tecnica.complexidade.estrelas);
|
||||||
numeroEstrelas = 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');
|
const bpmContainer = card.querySelector('.bpm-container');
|
||||||
|
|
||||||
if (bpmContainer) {
|
if (bpmContainer) {
|
||||||
// Cria container para as novas tags
|
|
||||||
const iaTagsDiv = document.createElement('div');
|
const iaTagsDiv = document.createElement('div');
|
||||||
iaTagsDiv.className = "tags is-centered mt-1 mb-3";
|
iaTagsDiv.className = "tags is-centered mt-1 mb-3";
|
||||||
iaTagsDiv.style.opacity = "0.9";
|
iaTagsDiv.style.flexDirection = "column";
|
||||||
iaTagsDiv.style.flexDirection = "column"; // Organiza em linhas (estrelas em cima, tags em baixo)
|
|
||||||
|
|
||||||
let htmlFinal = '';
|
let htmlFinal = '';
|
||||||
|
|
||||||
// A) Adiciona as Estrelas
|
// Renderiza Estrelas (mesmo que seja 0, mostra estrelas vazias)
|
||||||
htmlFinal += `<div class="mb-1" style="font-size: 0.8rem;">${estrelasHTML}</div>`;
|
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">';
|
htmlFinal += '<div class="tags is-centered">';
|
||||||
|
|
||||||
// B) Tag de Gênero IA
|
// Tag Gênero
|
||||||
if (info.analise_ia.genero_macro && info.analise_ia.genero_macro !== "Unknown") {
|
if (genero !== "Unknown") {
|
||||||
const genero = info.analise_ia.genero_macro;
|
|
||||||
let colorClass = 'is-primary';
|
let colorClass = 'is-primary';
|
||||||
if(genero === 'Electronic') colorClass = 'is-info';
|
if(genero === 'Electronic') colorClass = 'is-info';
|
||||||
if(genero === 'Hip Hop') colorClass = 'is-warning';
|
if(genero === 'Hip Hop') colorClass = 'is-warning';
|
||||||
if(genero === 'Rock') colorClass = 'is-danger';
|
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}
|
🤖 ${genero}
|
||||||
</span>`;
|
</span>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
// C) Tag de Tom (Musical Key)
|
// Tag Tom
|
||||||
if (info.analise_tecnica.tom) {
|
if (info.analise_tecnica?.tom) {
|
||||||
const nota = info.analise_tecnica.tom;
|
const nota = info.analise_tecnica.tom;
|
||||||
const escala = info.analise_tecnica.escala === 'minor' ? 'm' : '';
|
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;">
|
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>`;
|
</span>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
htmlFinal += '</div>'; // Fecha container tags
|
htmlFinal += '</div>';
|
||||||
|
|
||||||
iaTagsDiv.innerHTML = htmlFinal;
|
iaTagsDiv.innerHTML = htmlFinal;
|
||||||
bpmContainer.appendChild(iaTagsDiv);
|
bpmContainer.appendChild(iaTagsDiv);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Se não achou dados
|
// Valores padrão se não achar dados
|
||||||
card.dataset.genre = "Outros";
|
card.dataset.genre = "Outros";
|
||||||
card.dataset.intensity = -1;
|
card.dataset.intensity = -100;
|
||||||
|
card.dataset.stars = 0;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function createGenreButtons(data) {
|
function createGenreButtons(data) {
|
||||||
// Extrai lista única de gêneros encontrados
|
|
||||||
const genres = new Set();
|
const genres = new Set();
|
||||||
data.forEach(item => {
|
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);
|
genres.add(item.analise_ia.genero_macro);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Cria botões HTML
|
|
||||||
const genresArray = Array.from(genres).sort();
|
const genresArray = Array.from(genres).sort();
|
||||||
genresArray.forEach(genre => {
|
genresArray.forEach(genre => {
|
||||||
const btn = document.createElement('button');
|
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.textContent = genre;
|
||||||
btn.dataset.genre = genre;
|
btn.dataset.genre = genre;
|
||||||
|
|
||||||
btn.addEventListener('click', () => {
|
btn.addEventListener('click', () => {
|
||||||
// Lógica de Ativação Visual
|
// UI Update
|
||||||
const allBtns = genreContainer.querySelectorAll('.button');
|
const allBtns = genreContainer.querySelectorAll('.button');
|
||||||
allBtns.forEach(b => {
|
allBtns.forEach(b => {
|
||||||
b.classList.remove('is-active', 'is-info');
|
b.classList.remove('is-active', 'is-info');
|
||||||
// Volta botões inativos para branco
|
b.classList.add('is-white');
|
||||||
if(b !== btn) b.classList.add('is-white');
|
|
||||||
});
|
});
|
||||||
|
|
||||||
btn.classList.remove('is-white');
|
btn.classList.remove('is-white');
|
||||||
btn.classList.add('is-active', 'is-info');
|
btn.classList.add('is-active', 'is-info');
|
||||||
|
|
||||||
filterCards(genre);
|
// Logic Update
|
||||||
|
currentGenre = genre;
|
||||||
|
applyFilters();
|
||||||
});
|
});
|
||||||
|
|
||||||
genreContainer.appendChild(btn);
|
genreContainer.appendChild(btn);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Re-bind do botão "Todos"
|
// Botão Todos
|
||||||
const allBtn = genreContainer.querySelector('[data-genre="all"]');
|
const allBtn = genreContainer.querySelector('[data-genre="all"]');
|
||||||
allBtn.addEventListener('click', () => {
|
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');
|
allBtn.classList.add('is-active', 'is-info');
|
||||||
filterCards('all');
|
|
||||||
|
currentGenre = 'all';
|
||||||
|
applyFilters();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function filterCards(selectedGenre) {
|
// Lógica Unificada de Filtros
|
||||||
cards.forEach(card => {
|
function applyFilters() {
|
||||||
// Encontra a coluna pai para esconder tudo (layout grid)
|
cards.forEach(card => {
|
||||||
const column = card.closest('.project-column');
|
const column = card.closest('.project-column');
|
||||||
|
|
||||||
|
// 1. Checa Gênero
|
||||||
const cardGenre = card.dataset.genre;
|
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';
|
column.style.display = 'block';
|
||||||
} else {
|
} else {
|
||||||
column.style.display = 'none';
|
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
|
// Ordenação
|
||||||
sortSelect.addEventListener('change', (e) => {
|
sortSelect.addEventListener('change', (e) => {
|
||||||
const criteria = e.target.value;
|
const criteria = e.target.value;
|
||||||
|
|
@ -499,25 +548,26 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||||
const cardA = colA.querySelector('.project-card');
|
const cardA = colA.querySelector('.project-card');
|
||||||
const cardB = colB.querySelector('.project-card');
|
const cardB = colB.querySelector('.project-card');
|
||||||
|
|
||||||
// Valores padrão caso não tenha dados
|
const intensityA = parseFloat(cardA.dataset.intensity) || -100;
|
||||||
const intensityA = parseFloat(cardA.dataset.intensity) || 0;
|
const intensityB = parseFloat(cardB.dataset.intensity) || -100;
|
||||||
const intensityB = parseFloat(cardB.dataset.intensity) || 0;
|
|
||||||
const bpmA = parseFloat(cardA.dataset.bpm_real) || 0;
|
const bpmA = parseFloat(cardA.dataset.bpm_real) || 0;
|
||||||
const bpmB = parseFloat(cardB.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_desc') return intensityB - intensityA;
|
||||||
if (criteria === 'intensity_asc') return intensityA - intensityB;
|
if (criteria === 'intensity_asc') return intensityA - intensityB;
|
||||||
if (criteria === 'bpm_desc') return bpmB - bpmA;
|
if (criteria === 'bpm_desc') return bpmB - bpmA;
|
||||||
if (criteria === 'bpm_asc') return bpmA - bpmB;
|
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 titleA = cardA.dataset.title.toLowerCase();
|
||||||
const titleB = cardB.dataset.title.toLowerCase();
|
const titleB = cardB.dataset.title.toLowerCase();
|
||||||
return titleA.localeCompare(titleB);
|
return titleA.localeCompare(titleB);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Re-anexa os elementos na nova ordem
|
|
||||||
columns.forEach(col => projectsContainer.appendChild(col));
|
columns.forEach(col => projectsContainer.appendChild(col));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue