404 lines
15 KiB
HTML
404 lines
15 KiB
HTML
---
|
|
layout: default
|
|
title: Projetos por Pattern Rítmico
|
|
permalink: /pattern/
|
|
---
|
|
|
|
<meta charset="utf-8" />
|
|
|
|
<main class="main-content">
|
|
<div class="publication">{% include sidebar.html %}</div>
|
|
|
|
<div class="container">
|
|
<div class="columns is-mobile is-vcentered" style="margin-bottom: 2rem">
|
|
<div class="column is-auto">
|
|
<h2 class="title is-4">
|
|
<code>Projetos que possuem patterns similares:</code>
|
|
</h2>
|
|
</div>
|
|
<div class="column is-auto">
|
|
<button id="clearFilterButton" class="button is-small is-light">
|
|
Limpar filtro
|
|
</button>
|
|
</div>
|
|
</div> <style>
|
|
/* Estilos para o nosso sequencer de 16 steps */
|
|
.pattern-search-box {
|
|
display: flex;
|
|
flex-wrap: wrap; /* Permite quebrar a linha se necessário */
|
|
gap: 4px;
|
|
cursor: pointer;
|
|
margin-bottom: 2rem;
|
|
padding: 8px;
|
|
background-color: #f5f5f5;
|
|
border: 1px solid #dbdbdb;
|
|
border-radius: 4px;
|
|
display: inline-flex;
|
|
}
|
|
.search-step {
|
|
/* MODIFICADO: Steps menores para caber 16 */
|
|
width: 18px;
|
|
height: 30px;
|
|
background-color: #d9d9d9; /* Cor INATIVA */
|
|
border: 1px solid #999;
|
|
border-radius: 3px;
|
|
transition: background-color 0.1s ease;
|
|
}
|
|
.search-step.is-active {
|
|
background-color: #4caf50; /* Cor ATIVA (verde) */
|
|
}
|
|
|
|
/* NOVO: Adiciona um espaço extra a cada 4 steps para legibilidade */
|
|
.search-step:nth-child(4n):not(:last-child) {
|
|
margin-right: 8px;
|
|
}
|
|
</style>
|
|
|
|
<div class="field">
|
|
<label class="label"><code>Desenhe um pattern (até 16 steps) para buscar:</code></label>
|
|
<div id="pattern-search-box" class="pattern-search-box">
|
|
<div class="search-step" data-index="0"></div>
|
|
<div class="search-step" data-index="1"></div>
|
|
<div class="search-step" data-index="2"></div>
|
|
<div class="search-step" data-index="3"></div>
|
|
<div class="search-step" data-index="4"></div>
|
|
<div class="search-step" data-index="5"></div>
|
|
<div class="search-step" data-index="6"></div>
|
|
<div class="search-step" data-index="7"></div>
|
|
<div class="search-step" data-index="8"></div>
|
|
<div class="search-step" data-index="9"></div>
|
|
<div class="search-step" data-index="10"></div>
|
|
<div class="search-step" data-index="11"></div>
|
|
<div class="search-step" data-index="12"></div>
|
|
<div class="search-step" data-index="13"></div>
|
|
<div class="search-step" data-index="14"></div>
|
|
<div class="search-step" data-index="15"></div>
|
|
</div>
|
|
</div>
|
|
<div id="project-list" class="columns is-multiline">
|
|
|
|
{% comment %}
|
|
... O SEU LOOP LIQUID DE PROJETOS VEM AQUI ...
|
|
NENHUMA MUDANÇA É NECESSÁRIA NO LIQUID.
|
|
Ele continua exatamente como estava, gerando os 'project-item'
|
|
e os 'data-patterns' com chunks de 4 steps.
|
|
{% endcomment %}
|
|
|
|
{% for projeto in site.data.all %}
|
|
|
|
{% assign project_patterns_flat = "" | split: "," %}
|
|
{% assign project_patterns_data = "" | split: "," %}
|
|
|
|
{% for track in projeto.tracks %}
|
|
{% if track.instruments %}
|
|
{% for instrument in track.instruments %}
|
|
|
|
{% assign display_name = instrument.instrument_name %}
|
|
{% if display_name contains "audiofileprocessor" and instrument.patterns %}
|
|
{% assign first_pattern_name = instrument.patterns | map: 'name' | first %}
|
|
{% if first_pattern_name and first_pattern_name != empty %}
|
|
{% assign display_name = first_pattern_name | remove: ".ogg" | remove: ".wav" | remove: ".flac" | remove: ".mp3" %}
|
|
{% elsif instrument.audiofileprocessor.src %}
|
|
{% assign src_parts = instrument.audiofileprocessor.src | split: '/' %}
|
|
{% assign file_name = src_parts | last %}
|
|
{% assign display_name = file_name | remove: ".ogg" | remove: ".wav" | remove: ".flac" | remove: ".mp3" %}
|
|
{% endif %}
|
|
{% endif %}
|
|
{% if display_name == nil or display_name == "" %}
|
|
{% assign display_name = "Instrumento" %}
|
|
{% endif %}
|
|
|
|
|
|
{% if instrument.patterns %}
|
|
{% for pattern in instrument.patterns %}
|
|
{% assign pattern_steps = pattern.steps %}
|
|
{% if pattern_steps and pattern_steps.size > 0 %}
|
|
|
|
{% assign total_steps = pattern_steps.size %}
|
|
{% assign chunk_size = 4 %}
|
|
{% assign num_chunks = total_steps | divided_by: chunk_size %}
|
|
|
|
{% assign remainder = total_steps | modulo: chunk_size %}
|
|
{% if remainder > 0 %}
|
|
{% assign num_chunks = num_chunks | plus: 1 %}
|
|
{% endif %}
|
|
|
|
{% for i in (0..num_chunks) %}
|
|
{% assign start_index = i | times: chunk_size %}
|
|
{% assign current_chunk_array = pattern_steps | slice: start_index, chunk_size %}
|
|
|
|
{% if current_chunk_array.size > 0 %}
|
|
{% assign chunk_string = "" %}
|
|
{% for step in current_chunk_array %}
|
|
{% if step == true or step == 'true' or step == 1 %}
|
|
{% assign chunk_string = chunk_string | append: '1' %}
|
|
{% else %}
|
|
{% assign chunk_string = chunk_string | append: '0' %}
|
|
{% endif %}
|
|
{% endfor %}
|
|
|
|
{% assign data_pair = chunk_string | append: '::' | append: display_name %}
|
|
|
|
{% unless project_patterns_flat contains chunk_string %}
|
|
{% assign project_patterns_flat = project_patterns_flat | push: chunk_string %}
|
|
{% endunless %}
|
|
|
|
{% unless project_patterns_data contains data_pair %}
|
|
{% assign project_patterns_data = project_patterns_data | push: data_pair %}
|
|
{% endunless %}
|
|
{% endif %}
|
|
{% endfor %}
|
|
{% endif %}
|
|
{% endfor %}
|
|
{% endif %}
|
|
{% endfor %}
|
|
{% endif %}
|
|
{% endfor %}
|
|
|
|
{% if project_patterns_flat.size > 0 %}
|
|
{% assign project_patterns_string = project_patterns_flat | join: ',' %}
|
|
|
|
<div
|
|
class="column is-6 project-item"
|
|
data-patterns="{{ project_patterns_string }}"
|
|
>
|
|
<div class="box">
|
|
{% assign file_url = projeto.file | downcase | replace: ' ', '-' |
|
|
replace: 'ç', 'c' | replace: 'ã', 'a' | replace: 'á', 'a' | replace:
|
|
'â', 'a' | replace: 'é', 'e' | replace: 'ê', 'e' | replace: 'í', 'i' |
|
|
replace: 'ó', 'o' | replace: 'ô', 'o' | replace: 'õ', 'o' | replace:
|
|
'ú', 'u' %}
|
|
|
|
<a
|
|
href="../mmp_pages/{{ file_url }}.html"
|
|
class="button is-link is-fullwidth"
|
|
>
|
|
{{ projeto.file }}
|
|
</a>
|
|
|
|
<div style="margin-top: 1rem">
|
|
<p><strong>Patterns (4-steps):</strong></p>
|
|
<div class="tags" style="margin-top: 0.5rem;">
|
|
|
|
{% for data_pair_string in project_patterns_data %}
|
|
{% assign pair_parts = data_pair_string | split: '::' %}
|
|
{% assign p_string = pair_parts[0] %}
|
|
{% assign p_instrument = pair_parts[1] | default: '?' %}
|
|
|
|
<a href="#" class="pattern-item tag is-info is-light" data-pattern="{{ p_string }}" title="Filtrar por {{ p_string }} (de {{ p_instrument }})">
|
|
|
|
<div style="display: flex; flex-direction: row; border: 1px solid #999; padding: 2px; border-radius: 2px; background-color: #fff; margin-right: 5px;">
|
|
{% assign p_array = p_string | split: "" %}
|
|
{% for step_char in p_array %}
|
|
{% assign step_color = '#d9d9d9' %}
|
|
{% if step_char == '1' %}
|
|
{% assign step_color = '#4caf50' %}
|
|
{% endif %}
|
|
<div style="width: 5px; height: 10px; background-color: {{ step_color }}; border-radius: 1px; margin-right: 1px;"></div>
|
|
{% endfor %}
|
|
</div>
|
|
|
|
<span class="is-size-7" style="margin-right: 5px;">{{ p_instrument }}:</span>
|
|
<code>{{ p_string }}</code>
|
|
</a>
|
|
{% endfor %}
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
{% endfor %}
|
|
|
|
</div>
|
|
</div>
|
|
</main>
|
|
|
|
{% comment %}
|
|
SCRIPT FINAL (TOTALMENTE REESCRITO PARA 16-STEPS "AND" FILTER)
|
|
{% endcomment %}
|
|
<script>
|
|
document.addEventListener("DOMContentLoaded", function () {
|
|
const projects = document.querySelectorAll(".project-item");
|
|
const allPatternItems = document.querySelectorAll(".pattern-item");
|
|
const clearFilterButton = document.querySelector("#clearFilterButton");
|
|
const searchSteps = document.querySelectorAll(".search-step"); // Agora tem 16
|
|
|
|
/**
|
|
* "Fonte da verdade": um array de chunks de 4 steps (ex: ["1001", "0010"])
|
|
* que estão ativos no filtro.
|
|
*/
|
|
let activeChunks = [];
|
|
|
|
/**
|
|
* Pega o desenho de 16 steps e o quebra em 4 chunks.
|
|
* @returns {string[]} ex: ["1001", "0010", "0000", "0000"]
|
|
*/
|
|
function getChunksFromSearchBox() {
|
|
let fullPattern = "";
|
|
searchSteps.forEach(step => {
|
|
fullPattern += step.classList.contains("is-active") ? "1" : "0";
|
|
});
|
|
// Quebra a string "10010010..." em ["1001", "0010", ...]
|
|
return fullPattern.match(/.{1,4}/g) || [];
|
|
}
|
|
|
|
/**
|
|
* Pega os chunks ativos (ex: ["1001", "0010"]) e desenha
|
|
* o pattern de 16 steps (ex: "1001001000000000") na caixa.
|
|
*/
|
|
function setSearchBoxFromChunks(chunks) {
|
|
let fullPattern = (chunks || []).join("").padEnd(16, "0");
|
|
const bits = fullPattern.split("");
|
|
|
|
searchSteps.forEach((step, index) => {
|
|
if (bits[index] === "1") {
|
|
step.classList.add("is-active");
|
|
} else {
|
|
step.classList.remove("is-active");
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Filtra a lista de projetos.
|
|
* Um projeto SÓ aparece se ele tiver TODOS os activeChunks.
|
|
*/
|
|
function filterByPattern(chunks) {
|
|
// Se não há chunks ativos (e não vazios), mostra tudo
|
|
const effectiveChunks = chunks.filter(c => c !== "0000");
|
|
if (effectiveChunks.length === 0) {
|
|
projects.forEach(project => project.style.display = "block");
|
|
return;
|
|
}
|
|
|
|
projects.forEach((project) => {
|
|
const projectPatterns = project
|
|
.getAttribute("data-patterns")
|
|
.split(",");
|
|
|
|
// Lógica "AND": .every() verifica se TODOS os chunks são verdadeiros
|
|
const isMatch = effectiveChunks.every(chunk =>
|
|
projectPatterns.includes(chunk)
|
|
);
|
|
|
|
project.style.display = isMatch ? "block" : "none";
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Destaca MÚLTIPLAS tags que estão no filtro "AND".
|
|
*/
|
|
function highlightActiveFilter(chunks) {
|
|
allPatternItems.forEach((item) => {
|
|
const itemPattern = item.getAttribute("data-pattern");
|
|
|
|
// Se o pattern da tag ESTÁ no array de chunks ativos
|
|
if (chunks.includes(itemPattern)) {
|
|
item.classList.remove("is-light"); // Fica sólido
|
|
} else {
|
|
item.classList.add("is-info", "is-light"); // Fica light
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Atualiza a URL com um parâmetro ?p=1001,0010
|
|
*/
|
|
function updateUrl(chunks) {
|
|
const newUrl = new URL(window.location.href);
|
|
// Filtra "0000" antes de salvar na URL
|
|
const effectiveChunks = chunks.filter(c => c !== "0000");
|
|
|
|
if (effectiveChunks.length > 0) {
|
|
newUrl.searchParams.set("p", effectiveChunks.join(","));
|
|
} else {
|
|
newUrl.searchParams.delete("p");
|
|
}
|
|
window.history.replaceState({}, "", newUrl);
|
|
}
|
|
|
|
/**
|
|
* A NOVA função principal que sincroniza tudo.
|
|
*/
|
|
function runFilter() {
|
|
// 1. Lê o desenho e pega os chunks ativos
|
|
const chunksFromBox = getChunksFromSearchBox();
|
|
activeChunks = chunksFromBox.filter(c => c !== "0000");
|
|
|
|
// 2. Filtra os projetos (lógica "AND")
|
|
filterByPattern(activeChunks);
|
|
|
|
// 3. Destaca as tags
|
|
highlightActiveFilter(activeChunks);
|
|
|
|
// 4. Atualiza a URL
|
|
updateUrl(activeChunks);
|
|
}
|
|
|
|
// ========================================================
|
|
// Event Listeners (Gatilhos)
|
|
// ========================================================
|
|
|
|
// 1. Ao carregar a página (lê a URL)
|
|
const urlParams = new URLSearchParams(window.location.search);
|
|
let patternFromUrl = urlParams.get("p");
|
|
|
|
if (patternFromUrl) {
|
|
activeChunks = patternFromUrl.split(","); // ex: ["1001", "0010"]
|
|
setSearchBoxFromChunks(activeChunks); // Desenha "100100100000..."
|
|
filterByPattern(activeChunks);
|
|
highlightActiveFilter(activeChunks);
|
|
}
|
|
|
|
// 2. Ao clicar numa TAG (na lista de projetos)
|
|
allPatternItems.forEach((item) => {
|
|
item.addEventListener("click", function (event) {
|
|
event.preventDefault();
|
|
const selectedPattern = item.getAttribute("data-pattern");
|
|
|
|
// Lógica: Clicar numa tag a "adiciona" ao filtro "AND"
|
|
|
|
// Pega o que já está desenhado
|
|
let currentChunks = getChunksFromSearchBox().filter(c => c !== "0000");
|
|
|
|
// Se já está lá, remove (toggle)
|
|
if (currentChunks.includes(selectedPattern)) {
|
|
currentChunks = currentChunks.filter(c => c !== selectedPattern);
|
|
}
|
|
// Se não está, adiciona (se houver espaço)
|
|
else if (currentChunks.length < 4) {
|
|
currentChunks.push(selectedPattern);
|
|
}
|
|
|
|
activeChunks = currentChunks;
|
|
|
|
// Atualiza tudo
|
|
setSearchBoxFromChunks(activeChunks);
|
|
filterByPattern(activeChunks);
|
|
highlightActiveFilter(activeChunks);
|
|
updateUrl(activeChunks);
|
|
});
|
|
});
|
|
|
|
// 3. Ao clicar em um STEP da caixa de busca
|
|
searchSteps.forEach(step => {
|
|
step.addEventListener("click", function() {
|
|
// 1. Liga/desliga o step
|
|
step.classList.toggle("is-active");
|
|
|
|
// 2. Roda o filtro principal
|
|
runFilter();
|
|
});
|
|
});
|
|
|
|
// 4. Botão para limpar filtro
|
|
clearFilterButton.addEventListener("click", function () {
|
|
activeChunks = [];
|
|
setSearchBoxFromChunks([]); // Limpa o desenho
|
|
filterByPattern([]); // Mostra todos os projetos
|
|
highlightActiveFilter([]); // Limpa os destaques
|
|
updateUrl([]); // Limpa a URL
|
|
});
|
|
});
|
|
</script> |