575 lines
21 KiB
Markdown
575 lines
21 KiB
Markdown
---
|
|
layout: default
|
|
title: Projetos por Pattern Rítmico
|
|
permalink: /pattern/
|
|
---
|
|
|
|
<meta charset="utf-8" />
|
|
|
|
<main class="main-content">
|
|
<div class="publication">
|
|
<div class="container">
|
|
<br />
|
|
|
|
<div class="tabs is-centered is-boxed is-medium mb-6">
|
|
{% include sidebar.html %}
|
|
</div>
|
|
|
|
<div class="columns is-centered">
|
|
<div class="column is-8">
|
|
<div
|
|
class="box has-background-white-ter has-text-centered shadow-sm"
|
|
style="border: 1px solid #cfe8fc; height: fit-content !important; min-height: unset;"
|
|
>
|
|
<h2 class="title is-5 has-text-grey-dark mb-3">
|
|
<span class="icon has-text-info"
|
|
><i class="fa-solid fa-drum"></i
|
|
></span>
|
|
Busca por Pattern Rítmico
|
|
</h2>
|
|
<p class="subtitle is-7 has-text-grey mb-4">
|
|
Desenhe um ritmo (16 steps) abaixo ou clique nos patterns dos
|
|
instrumentos:
|
|
</p>
|
|
|
|
<div
|
|
id="pattern-search-box"
|
|
style="
|
|
display: flex;
|
|
gap: 6px;
|
|
justify-content: center;
|
|
flex-wrap: wrap;
|
|
margin-bottom: 1rem;
|
|
"
|
|
>
|
|
{% for i in (0..15) %} {% assign mod = i | modulo: 4 %} {% if i >
|
|
0 and mod == 0 %}
|
|
<div style="width: 8px"></div>
|
|
{% endif %}
|
|
<div
|
|
class="search-step"
|
|
data-index="{{i}}"
|
|
title="Step {{ i | plus: 1 }}"
|
|
style="
|
|
width: 25px;
|
|
height: 45px;
|
|
background: #e8e8e8;
|
|
border: 1px solid #ccc;
|
|
border-radius: 4px;
|
|
cursor: pointer;
|
|
transition: all 0.1s;
|
|
"
|
|
></div>
|
|
{% endfor %}
|
|
</div>
|
|
|
|
<button
|
|
id="clearFilterButton"
|
|
class="button is-small is-danger is-light is-rounded"
|
|
>
|
|
<span class="icon"><i class="fa-solid fa-trash"></i></span>
|
|
<span>Limpar Desenho</span>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div id="project-list" class="columns is-multiline">
|
|
{% for projeto in site.data.all %} {% assign project_patterns_flat = ""
|
|
| split: "," %} {% for track in projeto.tracks %} {% if
|
|
track.instruments %} {% for instrument in track.instruments %} {% 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 %} {% unless project_patterns_flat contains chunk_string %} {%
|
|
assign project_patterns_flat = project_patterns_flat | push:
|
|
chunk_string %} {% 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-12-mobile is-6-tablet is-4-desktop is-3-widescreen project-item"
|
|
data-patterns="{{ project_patterns_string }}"
|
|
>
|
|
<div
|
|
class="card project-card"
|
|
style="
|
|
height: 100%;
|
|
background-color: #f0f8ff;
|
|
border: 1px solid #cfe8fc;
|
|
border-radius: 12px;
|
|
display: flex;
|
|
flex-direction: column;
|
|
"
|
|
>
|
|
{% 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' %} {% assign page_url = '../mmp_pages/' | append:
|
|
file_url | append: '.html' %}
|
|
|
|
<a
|
|
href="{{ page_url }}"
|
|
style="text-decoration: none; display: block"
|
|
>
|
|
<div class="card-content has-text-centered p-4 pb-0">
|
|
<div
|
|
style="
|
|
width: 40px;
|
|
height: 40px;
|
|
background-color: #fff;
|
|
border-radius: 50%;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
margin: 0 auto 0.5rem auto;
|
|
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.05);
|
|
"
|
|
>
|
|
<span class="icon" style="color: #3273dc"
|
|
><i class="fa-solid fa-music"></i
|
|
></span>
|
|
</div>
|
|
<p
|
|
class="title is-6 mb-3"
|
|
style="color: #205081; word-break: break-word"
|
|
>
|
|
{{ projeto.file }}
|
|
</p>
|
|
</div>
|
|
</a>
|
|
|
|
<div class="card-content px-4 pb-4 pt-2" style="flex: 1">
|
|
<div
|
|
class="patterns-visualizer p-3"
|
|
style="
|
|
background: #fff;
|
|
border-radius: 8px;
|
|
border: 1px dashed #cfe8fc;
|
|
text-align: left;
|
|
"
|
|
>
|
|
<p
|
|
class="is-size-7 has-text-grey mb-2 filter-status-label"
|
|
style="font-weight: 600; text-align: center"
|
|
>
|
|
Patterns por Instrumento:
|
|
</p>
|
|
|
|
<div style="display: flex; flex-direction: column; gap: 8px">
|
|
{% for track in projeto.tracks %} {% if track.instruments %}
|
|
{% for instrument in track.instruments %} {% if
|
|
instrument.patterns %} {% assign inst_patterns = "" | split:
|
|
"," %} {% 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 %} {% if chunk_string != "0000" %} {% unless
|
|
inst_patterns contains chunk_string %} {% assign inst_patterns
|
|
= inst_patterns | push: chunk_string %} {% endunless %} {%
|
|
endif %} {% endif %} {% endfor %} {% endif %} {% endfor %} {%
|
|
if inst_patterns.size > 0 %}
|
|
<div
|
|
class="instrument-row"
|
|
style="
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
border-bottom: 1px solid #f5f5f5;
|
|
padding-bottom: 4px;
|
|
"
|
|
>
|
|
{% assign instrument_slug = instrument.instrument_name |
|
|
replace: ' ', '+' %}
|
|
<a
|
|
href="{{ '/instruments/?instrument=' | append: instrument_slug | relative_url }}"
|
|
class="tag is-white is-light instrument-link"
|
|
style="
|
|
font-size: 0.6rem;
|
|
color: #555;
|
|
max-width: 85px;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
white-space: nowrap;
|
|
text-decoration: none;
|
|
border: 1px solid transparent;
|
|
"
|
|
title="Ver projetos com {{ instrument.instrument_name }}"
|
|
>
|
|
{{ instrument.instrument_name }}
|
|
</a>
|
|
|
|
<div style="display: flex; gap: 3px">
|
|
{% for p_str in inst_patterns %}
|
|
<div
|
|
class="pattern-mini-grid js-pattern-trigger"
|
|
data-pattern-val="{{ p_str }}"
|
|
title="Filtrar por: {{ p_str }}"
|
|
>
|
|
{% assign bits = p_str | split: '' %} {% for bit in bits
|
|
%}
|
|
<div
|
|
style="width: 4px; height: 8px; background-color: {% if bit == '1' %}#4caf50{% else %}#eee{% endif %};"
|
|
></div>
|
|
{% endfor %}
|
|
</div>
|
|
{% endfor %}
|
|
</div>
|
|
</div>
|
|
{% endif %} {% endif %} {% endfor %} {% endif %} {% endfor %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<footer
|
|
class="card-footer"
|
|
style="
|
|
border-top: 1px solid #cfe8fc;
|
|
background-color: #fff;
|
|
border-radius: 0 0 12px 12px;
|
|
overflow: hidden;
|
|
"
|
|
>
|
|
<a
|
|
href="#"
|
|
class="card-footer-item js-open-modal"
|
|
data-target-url="{{ page_url }}"
|
|
data-modal-title="Detalhes: {{ projeto.file }}"
|
|
data-full-btn-text="Ir para Página"
|
|
data-full-btn-link="{{ page_url }}"
|
|
style="
|
|
color: #5b7da3;
|
|
font-size: 0.8rem;
|
|
font-weight: 600;
|
|
border-right: 1px solid #eee;
|
|
"
|
|
>Ver</a
|
|
>
|
|
{% assign creation_url = '/mmpSearch/creation.html?project=' |
|
|
append: projeto.file %} {% assign embed_url = creation_url |
|
|
append: '&embed=true' %}
|
|
<a
|
|
href="#"
|
|
class="card-footer-item js-open-modal"
|
|
data-target-url="{{ embed_url }}"
|
|
data-modal-title="Editor: {{ projeto.file }}"
|
|
data-full-btn-text="Abrir Editor"
|
|
data-full-btn-link="{{ creation_url }}"
|
|
style="color: #3273dc; font-size: 0.8rem; font-weight: 600"
|
|
>Editar</a
|
|
>
|
|
</footer>
|
|
</div>
|
|
</div>
|
|
{% endif %} {% endfor %}
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
</main>
|
|
|
|
<style>
|
|
.search-step.is-active {
|
|
background-color: #4caf50 !important;
|
|
border-color: #388e3c !important;
|
|
box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.2);
|
|
}
|
|
.pattern-mini-grid {
|
|
display: flex;
|
|
gap: 1px;
|
|
padding: 2px;
|
|
border: 1px solid #ddd;
|
|
border-radius: 2px;
|
|
cursor: pointer;
|
|
transition: all 0.2s ease;
|
|
background-color: #fafafa;
|
|
}
|
|
.pattern-mini-grid:hover {
|
|
transform: scale(1.2);
|
|
border-color: #3273dc;
|
|
z-index: 10;
|
|
}
|
|
.pattern-mini-grid.match-highlight {
|
|
border-color: #4caf50 !important;
|
|
background-color: #e8f5e9;
|
|
box-shadow: 0 0 0 1px #4caf50;
|
|
}
|
|
.instrument-link:hover {
|
|
background-color: #eef6fc !important;
|
|
color: #3273dc !important;
|
|
border-color: #3273dc !important;
|
|
}
|
|
</style>
|
|
|
|
<div id="preview-modal" class="modal">
|
|
<div class="modal-background"></div>
|
|
<div class="modal-card" style="width: 90%; max-width: 800px">
|
|
<header
|
|
class="modal-card-head"
|
|
style="background-color: #f0f8ff; border-bottom: 1px solid #cfe8fc"
|
|
>
|
|
<p
|
|
class="modal-card-title"
|
|
id="modal-title"
|
|
style="color: #205081; font-weight: bold"
|
|
>
|
|
Preview
|
|
</p>
|
|
<button class="delete" aria-label="close"></button>
|
|
</header>
|
|
<section
|
|
class="modal-card-body p-0"
|
|
style="height: 500px; background-color: #fff"
|
|
>
|
|
<iframe
|
|
id="preview-iframe"
|
|
src=""
|
|
style="width: 100%; height: 100%; border: none"
|
|
></iframe>
|
|
</section>
|
|
<footer
|
|
class="modal-card-foot"
|
|
style="
|
|
justify-content: flex-end;
|
|
background-color: #fff;
|
|
border-top: 1px solid #cfe8fc;
|
|
"
|
|
>
|
|
<button class="button" id="close-modal-btn">Fechar</button>
|
|
<a href="#" id="full-edit-btn" target="_blank" class="button is-info"
|
|
>Abrir</a
|
|
>
|
|
</footer>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
document.addEventListener("DOMContentLoaded", function () {
|
|
const projects = document.querySelectorAll(".project-item");
|
|
const clearFilterButton = document.querySelector("#clearFilterButton");
|
|
const searchSteps = document.querySelectorAll(".search-step");
|
|
let activeChunks = [];
|
|
|
|
function getChunksFromSearchBox() {
|
|
let fullPattern = "";
|
|
searchSteps.forEach(
|
|
(step) =>
|
|
(fullPattern += step.classList.contains("is-active") ? "1" : "0")
|
|
);
|
|
return fullPattern.match(/.{1,4}/g) || [];
|
|
}
|
|
|
|
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");
|
|
});
|
|
}
|
|
|
|
// --- FUNÇÃO CRUCIAL: FILTRA PROJETOS E RESUME O CONTEÚDO INTERNO ---
|
|
function filterByPattern(chunks) {
|
|
const effectiveChunks = chunks.filter((c) => c !== "0000");
|
|
|
|
// RESET GLOBAL (Se não há filtro)
|
|
if (effectiveChunks.length === 0) {
|
|
projects.forEach((project) => {
|
|
project.style.display = "block";
|
|
// Mostra tudo dentro do card
|
|
project
|
|
.querySelectorAll(".instrument-row")
|
|
.forEach((row) => (row.style.display = "flex"));
|
|
project.querySelectorAll(".pattern-mini-grid").forEach((grid) => {
|
|
grid.style.display = "flex";
|
|
grid.classList.remove("match-highlight");
|
|
});
|
|
// Reseta label
|
|
const label = project.querySelector(".filter-status-label");
|
|
if (label) label.textContent = "Patterns por Instrumento:";
|
|
});
|
|
return;
|
|
}
|
|
|
|
// COM FILTRO ATIVO
|
|
projects.forEach((project) => {
|
|
const projectPatternsStr = project.getAttribute("data-patterns");
|
|
const projectPatterns = projectPatternsStr.split(",");
|
|
|
|
// 1. O projeto tem TODOS os patterns buscados?
|
|
const isMatch = effectiveChunks.every((chunk) =>
|
|
projectPatterns.includes(chunk)
|
|
);
|
|
|
|
if (!isMatch) {
|
|
project.style.display = "none";
|
|
} else {
|
|
project.style.display = "block";
|
|
|
|
// 2. Filtragem Interna: Mostrar apenas o que bateu
|
|
const rows = project.querySelectorAll(".instrument-row");
|
|
let matchCount = 0;
|
|
|
|
rows.forEach((row) => {
|
|
const grids = row.querySelectorAll(".pattern-mini-grid");
|
|
let rowHasVisible = false;
|
|
|
|
grids.forEach((grid) => {
|
|
const val = grid.dataset.patternVal;
|
|
// Se o pattern faz parte da busca, mostra. Se não, esconde.
|
|
if (effectiveChunks.includes(val)) {
|
|
grid.style.display = "flex";
|
|
grid.classList.add("match-highlight");
|
|
rowHasVisible = true;
|
|
} else {
|
|
grid.style.display = "none";
|
|
grid.classList.remove("match-highlight");
|
|
}
|
|
});
|
|
|
|
// Se a linha do instrumento não tem nenhum pattern visível, esconde a linha toda
|
|
row.style.display = rowHasVisible ? "flex" : "none";
|
|
if (rowHasVisible) matchCount++;
|
|
});
|
|
|
|
// Atualiza label para dar feedback
|
|
const label = project.querySelector(".filter-status-label");
|
|
if (label) label.textContent = "Patterns encontrados:";
|
|
}
|
|
});
|
|
}
|
|
|
|
function updateUrl(chunks) {
|
|
const newUrl = new URL(window.location.href);
|
|
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);
|
|
}
|
|
|
|
function runFilter() {
|
|
const chunksFromBox = getChunksFromSearchBox();
|
|
activeChunks = chunksFromBox.filter((c) => c !== "0000");
|
|
filterByPattern(activeChunks);
|
|
updateUrl(activeChunks);
|
|
}
|
|
|
|
// --- TRIGGERS ---
|
|
document.querySelectorAll(".js-pattern-trigger").forEach((trigger) => {
|
|
trigger.addEventListener("click", function (e) {
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
const pattern = this.dataset.patternVal;
|
|
let currentChunks = getChunksFromSearchBox().filter(
|
|
(c) => c !== "0000"
|
|
);
|
|
|
|
if (currentChunks.includes(pattern))
|
|
currentChunks = currentChunks.filter((c) => c !== pattern);
|
|
else {
|
|
if (currentChunks.length < 4) currentChunks.push(pattern);
|
|
}
|
|
|
|
activeChunks = currentChunks;
|
|
setSearchBoxFromChunks(activeChunks);
|
|
filterByPattern(activeChunks);
|
|
updateUrl(activeChunks);
|
|
});
|
|
});
|
|
|
|
searchSteps.forEach((step) => {
|
|
step.addEventListener("click", function () {
|
|
step.classList.toggle("is-active");
|
|
runFilter();
|
|
});
|
|
});
|
|
|
|
clearFilterButton.addEventListener("click", function () {
|
|
activeChunks = [];
|
|
setSearchBoxFromChunks([]);
|
|
filterByPattern([]);
|
|
updateUrl([]);
|
|
});
|
|
|
|
const urlParams = new URLSearchParams(window.location.search);
|
|
let patternFromUrl = urlParams.get("p");
|
|
if (patternFromUrl) {
|
|
activeChunks = patternFromUrl.split(",");
|
|
setSearchBoxFromChunks(activeChunks);
|
|
filterByPattern(activeChunks);
|
|
}
|
|
|
|
// Modal logic (igual)
|
|
const modal = document.getElementById("preview-modal");
|
|
const iframe = document.getElementById("preview-iframe");
|
|
const modalTitle = document.getElementById("modal-title");
|
|
const fullEditBtn = document.getElementById("full-edit-btn");
|
|
const closeButtons = document.querySelectorAll(
|
|
".modal-background, .modal-card-head .delete, #close-modal-btn"
|
|
);
|
|
|
|
function openModal(url, title, btnText, btnLink) {
|
|
if (!modal) return;
|
|
modalTitle.textContent = title;
|
|
iframe.src = url;
|
|
fullEditBtn.textContent = btnText;
|
|
fullEditBtn.href = btnLink;
|
|
modal.classList.add("is-active");
|
|
document.documentElement.classList.add("is-clipped");
|
|
}
|
|
function closeModal() {
|
|
modal.classList.remove("is-active");
|
|
document.documentElement.classList.remove("is-clipped");
|
|
iframe.src = "";
|
|
}
|
|
document.querySelectorAll(".js-open-modal").forEach((btn) => {
|
|
btn.addEventListener("click", (e) => {
|
|
e.preventDefault();
|
|
openModal(
|
|
btn.dataset.targetUrl,
|
|
btn.dataset.modalTitle,
|
|
btn.dataset.fullBtnText,
|
|
btn.dataset.fullBtnLink
|
|
);
|
|
});
|
|
});
|
|
iframe.addEventListener("load", () => {
|
|
try {
|
|
const iframeDoc =
|
|
iframe.contentDocument || iframe.contentWindow.document;
|
|
const style = iframeDoc.createElement("style");
|
|
style.textContent = `.tabs, .navbar, .sidebar-wrapper, .main-header { display: none !important; } .publication { padding-top: 0 !important; } body { background-color: #fff !important; }`;
|
|
iframeDoc.head.appendChild(style);
|
|
} catch (e) {}
|
|
});
|
|
closeButtons.forEach((el) => el.addEventListener("click", closeModal));
|
|
document.addEventListener("keydown", (e) => {
|
|
if (e.key === "Escape") closeModal();
|
|
});
|
|
});
|
|
</script>
|