325 lines
11 KiB
HTML
Executable File
325 lines
11 KiB
HTML
Executable File
---
|
|
layout: default
|
|
title: MMPSearch - Projetos
|
|
permalink: /projetos/
|
|
---
|
|
|
|
<div class="publication">
|
|
<div class="container is-fluid">
|
|
<br />
|
|
<div class="tabs is-centered is-boxed is-medium mb-5">
|
|
{% include sidebar.html %}
|
|
</div>
|
|
|
|
<div class="columns is-vcentered mb-4">
|
|
<div class="column">
|
|
<h1 class="title is-3 has-text-grey-dark">📁 Projetos Disponíveis</h1>
|
|
</div>
|
|
<div class="column is-narrow">
|
|
<div class="field is-grouped">
|
|
<div class="control">
|
|
<div class="select is-small is-rounded">
|
|
<select id="sort-select">
|
|
<option value="default">Ordem Alfabética</option>
|
|
<option value="bpm_desc">BPM (Rápido)</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
<div class="control">
|
|
<button
|
|
id="reset-all-filters"
|
|
class="button is-danger is-light is-small"
|
|
>
|
|
Limpar Tudo
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="columns">
|
|
<div class="column is-3">
|
|
<div
|
|
class="box p-3"
|
|
style="background: #fcfcfc; border: 1px solid #eee"
|
|
>
|
|
<div class="field mb-5">
|
|
<label class="label is-size-7 has-text-grey">BUSCA TEXTUAL</label>
|
|
<div class="control has-icons-left">
|
|
<input
|
|
class="input is-small"
|
|
type="text"
|
|
id="search-input"
|
|
placeholder="Nome, plugin..."
|
|
/>
|
|
<span class="icon is-small is-left"
|
|
><i class="fa-solid fa-magnifying-glass"></i
|
|
></span>
|
|
</div>
|
|
</div>
|
|
<hr class="my-3" />
|
|
<details open>
|
|
<summary
|
|
class="menu-label has-text-weight-bold mb-2"
|
|
style="cursor: pointer"
|
|
>
|
|
🥁 Pattern Rítmico
|
|
</summary>
|
|
<div
|
|
id="pattern-search-box"
|
|
style="
|
|
display: flex;
|
|
gap: 4px;
|
|
flex-wrap: wrap;
|
|
justify-content: center;
|
|
"
|
|
></div>
|
|
</details>
|
|
<hr class="my-3" />
|
|
<label class="label is-size-7">FAIXA DE BPM</label>
|
|
<div class="columns is-mobile is-variable is-1">
|
|
<div class="column">
|
|
<input
|
|
class="input is-small has-text-centered"
|
|
type="number"
|
|
id="bpm-min"
|
|
value="0"
|
|
/>
|
|
</div>
|
|
<div class="column">
|
|
<input
|
|
class="input is-small has-text-centered"
|
|
type="number"
|
|
id="bpm-max"
|
|
value="300"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="column is-9">
|
|
<div class="notification is-info is-light mb-4" id="results-count-bar">
|
|
Encontrados
|
|
<span id="visible-count" class="has-text-weight-bold">0</span>
|
|
projetos.
|
|
</div>
|
|
<div id="project-list" class="columns is-multiline"></div>
|
|
<div id="no-results" class="has-text-centered is-hidden mt-6">
|
|
<span class="icon is-large has-text-grey-light"
|
|
><i class="fa-solid fa-face-frown fa-3x"></i
|
|
></span>
|
|
<p class="subtitle mt-3 has-text-grey">Nenhum projeto encontrado.</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<style>
|
|
.search-step {
|
|
width: 22px;
|
|
height: 35px;
|
|
background: #eee;
|
|
border: 1px solid #ccc;
|
|
border-radius: 3px;
|
|
cursor: pointer;
|
|
transition: 0.1s;
|
|
}
|
|
.search-step.is-active {
|
|
background-color: #3273dc !important;
|
|
border-color: #205081 !important;
|
|
}
|
|
.project-card:hover {
|
|
transform: translateY(-5px);
|
|
box-shadow: 0 8px 20px rgba(50, 115, 220, 0.15);
|
|
border-color: #3273dc !important;
|
|
transition: 0.3s;
|
|
}
|
|
.pattern-mini-grid {
|
|
display: inline-flex;
|
|
gap: 1px;
|
|
padding: 2px;
|
|
border: 1px solid #deeaf6;
|
|
border-radius: 2px;
|
|
background: #fff;
|
|
margin-right: 2px;
|
|
}
|
|
.mini-step {
|
|
width: 3px;
|
|
height: 6px;
|
|
border-radius: 1px;
|
|
}
|
|
.mini-step.active {
|
|
background-color: #3273dc;
|
|
}
|
|
.mini-step.inactive {
|
|
background-color: #eee;
|
|
}
|
|
</style>
|
|
|
|
<script>
|
|
document.addEventListener("DOMContentLoaded", function () {
|
|
const projectList = document.getElementById("project-list");
|
|
const searchInput = document.getElementById("search-input");
|
|
const bpmMinInput = document.getElementById("bpm-min");
|
|
const bpmMaxInput = document.getElementById("bpm-max");
|
|
const countSpan = document.getElementById("visible-count");
|
|
const patternBox = document.getElementById("pattern-search-box");
|
|
|
|
let allData = [];
|
|
let activePatternChunks = [];
|
|
|
|
// Cria os 16 quadradinhos do filtro de ritmo
|
|
patternBox.innerHTML = Array.from({ length: 16 })
|
|
.map((_, i) => `<div class="search-step" data-index="${i}"></div>`)
|
|
.join("");
|
|
const searchSteps = document.querySelectorAll(".search-step");
|
|
|
|
fetch(
|
|
'{{ "src_mmpSearch/saida_analises/db_final_completo.json" | relative_url }}',
|
|
)
|
|
.then((r) => r.json())
|
|
.then((data) => {
|
|
allData = data;
|
|
renderCards(allData);
|
|
applyFilters();
|
|
});
|
|
|
|
function renderCards(data) {
|
|
projectList.innerHTML = data
|
|
.map((p) => {
|
|
const fileName = p.file || p.arquivo || "projeto-sem-nome"; // Correção do Erro
|
|
const pBpm = p.bpm || 0;
|
|
|
|
let chunks = [];
|
|
if (p.tracks) {
|
|
p.tracks.forEach((t) => {
|
|
const instruments = t.instruments || [t];
|
|
instruments.forEach((inst) => {
|
|
if (inst.patterns) {
|
|
inst.patterns.forEach((pat) => {
|
|
if (pat.steps) {
|
|
for (let i = 0; i < pat.steps.length; i += 4) {
|
|
const chunk = pat.steps
|
|
.slice(i, i + 4)
|
|
.map((s) => (s ? "1" : "0"))
|
|
.join("");
|
|
if (chunk !== "0000" && !chunks.includes(chunk))
|
|
chunks.push(chunk);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
return `
|
|
<div class="column is-12-mobile is-6-tablet is-4-desktop project-item"
|
|
data-name="${fileName.toLowerCase()}"
|
|
data-bpm="${pBpm}"
|
|
data-patterns="${chunks.join(",")}">
|
|
<div class="card project-card" style="height: 100%; border-radius: 12px; border: 1px solid #cfe8fc; display: flex; flex-direction: column;">
|
|
<a href="{{ '/projeto/?id=' | relative_url }}${fileName}" style="text-decoration: none; flex: 1;">
|
|
<div class="card-content has-text-centered p-4">
|
|
<div style="width: 50px; height: 50px; background: #fff; border-radius: 50%; display: flex; align-items: center; justify-content: center; margin: 0 auto 10px; box-shadow: 0 2px 5px rgba(0,0,0,0.05);">
|
|
<span class="icon" style="color: #3273dc;"><i class="fa-solid fa-music fa-lg"></i></span>
|
|
</div>
|
|
<p class="title is-6 mb-2" style="color: #205081;">${fileName.replace(".html", "")}</p>
|
|
<div class="mb-3"><span class="tag is-dark is-rounded is-light">🎵 ${pBpm} BPM</span></div>
|
|
<div class="patterns-preview">
|
|
${chunks
|
|
.slice(0, 4)
|
|
.map(
|
|
(c) => `
|
|
<div class="pattern-mini-grid" title="Pattern: ${c}">
|
|
${c
|
|
.split("")
|
|
.map(
|
|
(b) =>
|
|
`<div class="mini-step ${b === "1" ? "active" : "inactive"}"></div>`,
|
|
)
|
|
.join("")}
|
|
</div>
|
|
`,
|
|
)
|
|
.join("")}
|
|
</div>
|
|
</div>
|
|
</a>
|
|
<footer class="card-footer" style="border-top: 1px solid #cfe8fc; background: #fff; border-radius: 0 0 12px 12px;">
|
|
<a href="{{ '/projeto/?id=' | relative_url }}${fileName}" class="card-footer-item" style="color: #3273dc; font-size: 0.8rem; font-weight: 600;">Ver Detalhes</a>
|
|
</footer>
|
|
</div>
|
|
</div>`;
|
|
})
|
|
.join("");
|
|
}
|
|
|
|
function applyFilters() {
|
|
const text = searchInput.value.toLowerCase();
|
|
const min = parseInt(bpmMinInput.value) || 0;
|
|
const max = parseInt(bpmMaxInput.value) || 999;
|
|
let count = 0;
|
|
|
|
document.querySelectorAll(".project-item").forEach((item) => {
|
|
const name = item.dataset.name || "";
|
|
const bpm = parseInt(item.dataset.bpm) || 0;
|
|
const pPatterns = item.dataset.patterns
|
|
? item.dataset.patterns.split(",")
|
|
: [];
|
|
|
|
const matchText = name.includes(text);
|
|
const matchBpm = bpm >= min && bpm <= max;
|
|
const matchPattern =
|
|
activePatternChunks.length === 0 ||
|
|
activePatternChunks.every((c) => pPatterns.includes(c));
|
|
|
|
if (matchText && matchBpm && matchPattern) {
|
|
item.style.display = "block";
|
|
count++;
|
|
} else {
|
|
item.style.display = "none";
|
|
}
|
|
});
|
|
countSpan.textContent = count;
|
|
document
|
|
.getElementById("no-results")
|
|
.classList.toggle("is-hidden", count > 0);
|
|
}
|
|
|
|
searchInput.addEventListener("input", applyFilters);
|
|
bpmMinInput.addEventListener("input", applyFilters);
|
|
bpmMaxInput.addEventListener("input", applyFilters);
|
|
|
|
searchSteps.forEach((step) => {
|
|
step.addEventListener("click", function () {
|
|
this.classList.toggle("is-active");
|
|
updatePatternChunks();
|
|
applyFilters();
|
|
});
|
|
});
|
|
|
|
function updatePatternChunks() {
|
|
let full = Array.from(searchSteps)
|
|
.map((s) => (s.classList.contains("is-active") ? "1" : "0"))
|
|
.join("");
|
|
activePatternChunks = (full.match(/.{1,4}/g) || []).filter(
|
|
(c) => c !== "0000",
|
|
);
|
|
}
|
|
|
|
document
|
|
.getElementById("reset-all-filters")
|
|
.addEventListener("click", () => {
|
|
searchInput.value = "";
|
|
bpmMinInput.value = 0;
|
|
bpmMaxInput.value = 300;
|
|
searchSteps.forEach((s) => s.classList.remove("is-active"));
|
|
activePatternChunks = [];
|
|
applyFilters();
|
|
});
|
|
});
|
|
</script>
|