Upgrade interface do MMPSearch
Deploy / Deploy (push) Successful in 1m52s Details

This commit is contained in:
JotaChina 2025-11-30 17:38:39 -03:00
parent 0d0cd2d7db
commit 6b199bd3fb
21 changed files with 2438 additions and 1547 deletions

View File

@ -1,9 +0,0 @@
ALICE MMPSearch
This is a repository with the purpose of creating a site using Jekyll to serve as a LMMS Beat File Library.
The intuitive is to be able to collect information from the files by indexing it and allows search with the most diverse filters.
It is part of the master's research in Computer Science at the Federal University of São João del Rei, focused on independent underground music production and the use of open source technologies.
The mainstream only exists because the underground created the scene.

View File

@ -0,0 +1,104 @@
<div
class="instrument-wrapper mb-4 p-2"
style="border-left: 3px solid #3298dc; background: #fff"
data-plugin-name="{{ instrument.instrument_name | downcase }}"
data-params="{{ instrument | jsonify | escape }}"
>
<li style="list-style: none">
<details {% if should_open %}open{% endif %}>
<summary style="cursor: pointer; outline: none; margin-bottom: 0.5rem">
<div style="display: inline-flex; align-items: center; gap: 8px">
{% assign display_name = instrument.instrument_name %} {% assign
plugin_name = instrument.instrument_name | downcase %} {% assign
is_sample = false %} {% if plugin_name == 'audiofileprocessor' or
instrument.audiofileprocessor %}{% assign is_sample = true %}{% endif
%} {% if is_sample %} {% if display_name contains "audiofileprocessor"
and instrument.patterns %} {% assign first_pattern =
instrument.patterns | first %} {% if first_pattern.name %}{% assign
display_name = first_pattern.name %}{% endif %} {% elsif
instrument.audiofileprocessor.src %} {% assign src_parts =
instrument.audiofileprocessor.src | split: '/' %} {% assign
display_name = src_parts | last %} {% endif %} {% assign display_name
= display_name | remove: ".ogg" | remove: ".wav" %} {% endif %} {%
assign instrument_slug = display_name | replace: ' ', '+' %}
<a
href="{{ '/instruments/?instrument=' | append: instrument_slug | relative_url }}"
class="tag is-info is-light"
>
<strong>{{ display_name }}</strong>
{% unless is_sample %}
<span class="ml-1" style="font-size: 0.7em">(Synth 🎹)</span>{%
endunless %}
</a>
</div>
</summary>
{% for pattern in instrument.patterns %} {% assign pattern_steps =
pattern.steps %} {% if pattern_steps and pattern_steps.size > 0 %}
<div
class="mt-2 ml-4"
style="display: flex; align-items: center; gap: 4px"
>
<div
class="patterns-container"
style="display: flex; flex-direction: row; flex-wrap: wrap; gap: 4px"
>
{% 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 %}
<a
href="{{ '/pattern/?p=' | append: chunk_string | relative_url }}"
style="display: inline-block; opacity: 0.8"
>
<div
style="
display: flex;
border: 1px solid #ccc;
padding: 1px;
background: #fff;
"
>
{% for step_active in current_chunk_array %}
<div
style="width: 4px; height: 8px; margin-right: 1px; background-color: {% if step_active == true or step_active == 1 %}#4caf50{% else %}#ddd{% endif %};"
></div>
{% endfor %}
</div>
</a>
{% endif %} {% endfor %}
</div>
</div>
{% endif %} {% endfor %}
</details>
<div class="playback-controls mt-2 pl-4">
{% if is_sample %} {% assign sample_src =
instrument.audiofileprocessor.src | default: "" | strip %} {% if
sample_src != "" %} {% assign audio_filename_with_path = 'src/samples/' |
append: sample_src %}
<audio
controls
class="js-sample-player"
style="height: 25px; width: 200px"
>
<source
src="{{ audio_filename_with_path | relative_url }}"
type="audio/ogg"
/>
</audio>
{% endif %} {% else %}
<button class="button is-small is-primary is-outlined js-play-synth-btn">
Testar
</button>
{% endif %}
</div>
</li>
</div>

View File

@ -1,14 +1,27 @@
<link rel="stylesheet" href="{{ 'assets/css/sidebar.css' | relative_url }}">
<div class="subheader">
<div class="submenu">
<a href="{{ site.baseurl }}">🏠 Home</a>
<a href="{{ site.baseurl }}quantasVezesAparecemInstrumentos">🔁 Repetições</a>
<a href="{{ site.baseurl }}projetosPorTrack/">📁 Projetos por tipo de track</a>
<a href="{{ site.baseurl }}beatsDisponiveis/">🎧 Beats Disponíveis</a>
<a href="{{ site.baseurl }}mmp_pages/">🎼 Projetos</a>
<a href="{{ site.baseurl }}">🔎 Buscas</a>´
<a href="{{ site.baseurl }}creation.html">🧠 Crie seu projeto</a>
<a href="{{ site.baseurl }}about/"> Sobre</a>
</div>
</div>
<ul>
<li>
<a href="{{ '/mmp_pages/' | relative_url }}"
><span class="icon is-small"><i class="fa-solid fa-folder-open"></i></span
><span>Projetos Disponíveis</span></a
>
</li>
<li class="is-active">
<a href="{{ '/projetosPorTrack/' | relative_url }}"
><span class="icon is-small"
><i class="fa-solid fa-magnifying-glass"></i></span
><span>Buscas</span></a
>
</li>
<li>
<a href="{{ '/beats/' | relative_url }}"
><span class="icon is-small"><i class="fa-solid fa-headphones"></i></span
><span>Beats</span></a
>
</li>
<li>
<a href="{{ '/creation/' | relative_url }}" class="has-text-primary"
><span class="icon is-small"><i class="fa-solid fa-plus-circle"></i></span
><span>Crie seu projeto</span></a
>
</li>
</ul>

File diff suppressed because it is too large Load Diff

View File

View File

@ -1,42 +1,73 @@
/* ==========================================================================
SIDEBAR.CSS (Vertical)
========================================================================== */
/* Wrapper que segura a barra lateral na esquerda */
.sidebar-wrapper {
background-color: #fff;
border-right: 1px solid #e1e4e8;
height: 100%;
min-height: calc(100vh - 60px); /* Ajuste conforme altura do seu header */
padding: 1.5rem 1rem;
box-shadow: 2px 0 10px rgba(0,0,0,0.02);
}
/* Título opcional acima do menu */
.sidebar-header {
font-size: 0.85rem;
text-transform: uppercase;
letter-spacing: 1px;
color: #888;
margin-bottom: 1rem;
padding-left: 0.5rem;
font-weight: bold;
}
/* Container dos links */
.submenu {
display: flex;
flex-wrap: wrap;
justify-content: center;
gap: 0.5rem;
background-color: #f4f4f4;
padding: 1rem;
border-radius: 8px;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
max-width: 100%;
box-sizing: border-box;
flex-direction: column; /* Força vertical */
gap: 0.25rem;
width: 100%;
}
/* Estilo dos Links */
.submenu a {
display: flex;
align-items: center;
text-decoration: none;
padding: 0.4rem 0.8rem;
border-radius: 5px;
color: #333;
background-color: #fff;
transition: all 0.3s ease;
padding: 0.75rem 1rem;
border-radius: 6px;
color: #4a4a4a;
font-weight: 500;
border: 1px solid #ddd;
font-size: 0.95rem;
white-space: nowrap;
flex-shrink: 0;
transition: all 0.2s ease;
border-left: 3px solid transparent;
}
/* Hover */
.submenu a:hover {
background-color: #007acc;
color: white;
border-color: #007acc;
background-color: #f5f7fa;
color: #3273dc; /* Azul padrão do Bulma */
border-left-color: #3273dc;
padding-left: 1.2rem; /* Pequeno movimento para a direita */
}
@media screen and (max-width: 600px) {
.submenu {
justify-content: flex-start;
}
.submenu a {
font-size: 0.85rem;
padding: 0.3rem 0.6rem;
}
/* Link Ativo (opcional, se você tiver lógica para adicionar classe 'is-active') */
.submenu a.is-active {
background-color: #eef3fc;
color: #3273dc;
font-weight: 600;
border-left-color: #3273dc;
}
/* Ícones (se houver) */
.submenu a i, .submenu a span.icon {
margin-right: 10px;
color: #888;
width: 20px;
text-align: center;
}
.submenu a:hover i {
color: #3273dc;
}

View File

@ -1,137 +1,306 @@
---
layout: default
title: Projetos com Instrumentos
title: Projetos por Instrumento
permalink: /instruments/
---
<meta charset="utf-8">
<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;">
<!-- Título -->
<div class="column is-auto">
<h2 class="title is-4"><code>Projetos e seus instrumentos:</code></h2>
<div class="container">
<br />
<div class="tabs is-centered is-boxed is-medium mb-6">
{% include sidebar.html %}
</div>
<!-- Botão Limpar Filtro -->
<div class="column is-auto">
<button id="clearFilterButton" class="button is-small is-light">
Limpar filtro
</button>
</div>
</div>
<!-- Projetos -->
<div id="project-list" class="columns is-multiline">
{% for projeto in site.data.all %}
<div class="column is-6 project-item" data-project-id="{{ projeto.file }}">
<div class="box">
<!-- Botão do projeto -->
{% 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' %}
<details class="box mb-5 p-0 collapse-card" open
style="border: 1px solid #cfe8fc; overflow: hidden; background-color: #fff; box-shadow: 0 2px 5px rgba(0,0,0,0.05); height: fit-content !important; min-height: unset;">
<a href="../mmp_pages/{{ file_url }}.html" class="button is-link is-fullwidth">
{{ projeto.file }}
</a>
<summary class="p-4 is-flex is-justify-content-space-between is-align-items-center"
style="cursor: pointer; background-color: #f0f8ff; transition: background-color 0.2s; user-select: none;">
<div class="is-flex is-align-items-center">
<span class="icon has-text-info mr-2"><i class="fa-solid fa-guitar"></i></span>
<span class="has-text-grey-dark has-text-weight-bold">Todos os Instrumentos Disponíveis</span>
<span id="filter-counter" class="tag is-info is-light ml-3 is-hidden">0 selecionados</span>
</div>
<span class="icon has-text-grey-light chevron-icon"><i class="fa-solid fa-chevron-down"></i></span>
</summary>
<!-- Lista de Instrumentos clicáveis -->
<div class="instruments">
{% assign instruments_exibidos = "" %}
{% for track in projeto.tracks %}
{% if track.instruments %}
{% for instrument in track.instruments %}
{% unless instruments_exibidos contains instrument.instrument_name %}
{% capture instruments_exibidos %}{{ instruments_exibidos }},{{ instrument.instrument_name }}{% endcapture %}
<div class="p-4" style="background-color: #fff; border-top: 1px solid #cfe8fc;">
<div class="tags is-centered are-medium mb-0">
{% assign all_instruments_string = "" %}
<!-- Gerar link para o instrumento -->
{% assign instrument_slug = instrument.instrument_name %}
<a href="{{ '/instruments/?instrument=' | append: instrument_slug | encodeURIComponent | relative_url }}" class="button is-link instrument-button" style="margin: 0.5rem;">
{{ instrument.instrument_name }}
</a>
{% endunless %}
{% for p in site.data.all %}
{% for track in p.tracks %}
{% if track.instruments %}
{% for inst in track.instruments %}
{% if inst.instrument_name and inst.instrument_name != "" %}
{% unless all_instruments_string contains inst.instrument_name %}
{% assign all_instruments_string = all_instruments_string | append: inst.instrument_name | append: "|||" %}
{% endunless %}
{% endif %}
{% endfor %}
{% elsif track.instrument_name and track.instrument_name != "" %}
{% unless all_instruments_string contains track.instrument_name %}
{% assign all_instruments_string = all_instruments_string | append: track.instrument_name | append: "|||" %}
{% endunless %}
{% endif %}
{% endfor %}
{% endfor %}
{% endif %}
{% endfor %}
</div>
{% assign unique_instruments = all_instruments_string | split: "|||" | sort %}
{% for item in unique_instruments %}
{% if item != "" %}
<a href="#" class="tag is-white filter-item clickable-tag"
data-value="{{ item }}"
style="border: 1px solid #deeaf6; color: #5b7da3; margin-bottom: 0.5rem; transition: all 0.2s;">
{{ item }}
</a>
{% endif %}
{% endfor %}
</div>
<div class="has-text-centered mt-3">
<p class="help has-text-grey">Clique para filtrar.</p>
</div>
</div>
</details>
<div class="columns is-mobile is-vcentered mb-5">
<div class="column is-auto">
<h2 class="title is-4 has-text-grey-dark">
<span class="icon has-text-info mr-2"><i class="fa-solid fa-filter"></i></span>
Filtro: <code id="filter-display-name" style="color: #d63384;">(todos)</code>
</h2>
</div>
{% endfor %}
<div class="column is-narrow">
<button id="clearFilterButton" class="button is-small is-danger is-light">
<span class="icon is-small"><i class="fa-solid fa-xmark"></i></span>
<span>Limpar Tudo</span>
</button>
</div>
</div>
<div id="project-list" class="columns is-multiline">
{% for projeto in site.data.all %}
{% assign project_insts = "" %}
{% for track in projeto.tracks %}
{% if track.instruments %}
{% for inst in track.instruments %}
{% assign project_insts = project_insts | append: inst.instrument_name | append: "," %}
{% endfor %}
{% elsif track.instrument_name %}
{% assign project_insts = project_insts | append: track.instrument_name | append: "," %}
{% endif %}
{% endfor %}
<div class="column is-12-mobile is-6-tablet is-4-desktop is-3-widescreen project-item"
data-instruments="{{ project_insts }}">
<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; flex: 1; display: flex; flex-direction: column;">
<div class="card-content has-text-centered p-4" style="flex: 1; display: flex; flex-direction: column;">
<div style="width: 50px; height: 50px; 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 fa-lg"></i></span>
</div>
<p class="title is-6 mb-2" style="color: #205081; word-break: break-word; font-weight: 700; line-height: 1.2;">
{{ projeto.file }}
</p>
{% if projeto.bpm %}
<div class="mb-3">
<span class="tag is-dark is-rounded is-light" style="font-size: 0.7rem; font-weight: bold; border: 1px solid #ccc;">
🎵 {{ projeto.bpm }} BPM
</span>
</div>
{% else %}
<div class="mb-3" style="height: 24px;"></div>
{% endif %}
<div style="flex: 1;"></div>
{% assign unique_proj_insts = project_insts | split: "," | uniq %}
{% if unique_proj_insts.size > 0 %}
<div class="tags is-centered is-gapless mb-0 mt-2" style="gap: 4px; justify-content: center;">
{% for item in unique_proj_insts %}
{% if item != "" %}
<span class="tag is-white filter-item clickable-tag" data-value="{{ item }}"
style="font-size: 0.65rem; border: 1px solid #deeaf6; color: #5b7da3; padding: 0 6px; height: 1.5em; text-decoration: none; cursor: pointer;">
{{ item | truncate: 15 }}
</span>
{% endif %}
{% endfor %}
</div>
{% endif %}
</div>
</a>
<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; transition: background 0.2s;">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>
{% endfor %}
</div>
</div>
</div>
</main>
<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>
<style>
.project-card:hover { transform: translateY(-5px); box-shadow: 0 8px 20px rgba(50, 115, 220, 0.15); border-color: #3273dc !important; background-color: #fff !important; }
.clickable-tag:hover { background-color: #e3effd !important; color: #3273dc !important; border-color: #3273dc !important; transform: scale(1.05); }
.tag.is-active-filter { background-color: #3273dc !important; color: #fff !important; border-color: #3273dc !important; font-weight: bold; box-shadow: 0 2px 5px rgba(50, 115, 220, 0.3); }
.collapse-card summary { list-style: none; transition: background 0.2s; }
.collapse-card summary::-webkit-details-marker { display: none; }
.collapse-card[open] summary .chevron-icon { transform: rotate(180deg); }
.chevron-icon { transition: transform 0.3s ease; }
</style>
<script>
document.addEventListener("DOMContentLoaded", function() {
const instrumentButtons = document.querySelectorAll('.instrument-button');
const projectItems = document.querySelectorAll('.project-item');
const urlParams = new URLSearchParams(window.location.search);
let instrumentFilter = urlParams.get('instrument'); // Pega o parâmetro 'instrument' da URL, se houver
document.addEventListener('DOMContentLoaded', function () {
const projects = document.querySelectorAll('.project-item');
const filterDisplayName = document.getElementById('filter-display-name');
const filterCounter = document.getElementById('filter-counter');
let activeFilters = [];
// Decodificando o valor do instrumento para garantir que espaços e caracteres especiais sejam tratados
if (instrumentFilter) {
instrumentFilter = decodeURIComponent(instrumentFilter);
}
function applyFilters() {
if (activeFilters.length > 0) {
filterDisplayName.textContent = activeFilters.join(" + ");
filterCounter.textContent = activeFilters.length + " selecionados";
filterCounter.classList.remove('is-hidden');
} else {
filterDisplayName.textContent = "(todos)";
filterCounter.classList.add('is-hidden');
}
// Função para aplicar o filtro de instrumento
function filterProjects() {
projectItems.forEach(project => {
const projectId = project.getAttribute('data-project-id');
let projectContainsInstrument = false;
// Atualiza visual das tags
document.querySelectorAll('.filter-item').forEach(tag => {
const val = tag.getAttribute('data-value');
if (activeFilters.includes(val)) {
tag.classList.add('is-active-filter');
} else {
tag.classList.remove('is-active-filter');
}
});
// Verificar se algum instrumento do projeto corresponde ao filtro
project.querySelectorAll('.instrument-button').forEach(button => {
const instrumentSlug = button.getAttribute('href').split('=')[1]; // Pega o instrumento do link
projects.forEach(project => {
const projectInstStr = project.getAttribute('data-instruments');
// Cria array de instrumentos deste projeto
const projectInsts = projectInstStr.split(',').map(s => s.trim());
// Decodificando o slug do instrumento para comparar corretamente
const decodedSlug = decodeURIComponent(instrumentSlug);
// Se o projeto contém o instrumento desejado, exibe o projeto
if (decodedSlug === instrumentFilter) {
projectContainsInstrument = true;
if (activeFilters.length === 0) {
project.style.display = 'block';
} else {
// Lógica OR: Se tiver pelo menos um dos instrumentos filtrados, exibe
const hasMatch = activeFilters.some(filter => projectInsts.includes(filter));
project.style.display = hasMatch ? 'block' : 'none';
}
});
// Ocultar ou exibir o projeto com base no filtro
if (instrumentFilter && !projectContainsInstrument) {
project.style.display = 'none'; // Oculta o projeto
} else {
project.style.display = 'block'; // Exibe o projeto
}
});
}
filterProjects(); // Aplica o filtro de instrumentos assim que a página é carregada
// Botão para limpar filtro
const clearFilterButton = document.querySelector('#clearFilterButton');
if (clearFilterButton) {
clearFilterButton.addEventListener('click', function () {
// Limpa o filtro e mostra todos os projetos
projectItems.forEach(project => {
project.style.display = 'block'; // Exibe todos os projetos
});
// Remove o parâmetro 'instrument' da URL
const newUrl = new URL(window.location.href);
newUrl.searchParams.delete('instrument');
if (activeFilters.length > 0) {
newUrl.searchParams.set('instrument', activeFilters.join(','));
} else {
newUrl.searchParams.delete('instrument');
}
window.history.replaceState({}, '', newUrl);
}
function toggleFilter(val) {
const index = activeFilters.indexOf(val);
if (index > -1) activeFilters.splice(index, 1);
else activeFilters.push(val);
applyFilters();
}
// Inicializa
const urlParams = new URLSearchParams(window.location.search);
const instParam = urlParams.get('instrument');
if (instParam) {
activeFilters = instParam.split(',').map(s => s.trim()).filter(s => s !== "");
applyFilters();
}
// Eventos
document.querySelectorAll('.filter-item').forEach(tag => {
tag.addEventListener('click', function(e) {
e.preventDefault();
e.stopPropagation(); // Evita clique no card se for dentro dele
const val = this.getAttribute('data-value');
toggleFilter(val);
});
});
}
});
document.querySelector('#clearFilterButton').addEventListener('click', function () {
activeFilters = [];
applyFilters();
});
// Modal
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) {
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>

View File

@ -1,99 +0,0 @@
---
layout: default
title: "Projetos por Instrumento"
permalink: /instruments/
---
<meta charset="utf-8">
<main class="main-content">
<div class="publication">
{% include sidebar.html %}
<div class="container">
<br>
<div class="columns is-mobile is-vcentered" style="margin-bottom: 2rem;">
<!-- Título -->
<div class="column is-auto">
<h2 class="title is-4"><code>Instrumentos disponíveis:</code></h2>
</div>
<!-- Botão Limpar Filtro -->
<div class="column is-auto">
<button id="clearFilterButton" class="button is-small is-light">
Limpar filtro
</button>
</div>
</div>
{% assign instruments_exibidos = "" %}
{% for item in site.data.all %}
{% for track in item.tracks %}
{% if track.instruments %}
{% for instrument in track.instruments %}
{% unless instruments_exibidos contains instrument.instrument_name %}
{% capture instruments_exibidos %}{{ instruments_exibidos }},{{ instrument.instrument_name }}{% endcapture %}
<!-- Gerar link para o instrumento -->
{% assign instrument_slug = instrument.instrument_name %}
<a href="{{ '/instruments/?instrument=' | append: instrument_slug | relative_url }}" class="button is-link instrument-button" style="margin-bottom: 1rem;">
{{ instrument.instrument_name }}
</a>
{% endunless %}
{% endfor %}
{% endif %}
{% endfor %}
{% endfor %}
</div>
</div>
</main>
<script>
document.addEventListener("DOMContentLoaded", function() {
const instrumentButtons = document.querySelectorAll('.instrument-button');
const urlParams = new URLSearchParams(window.location.search);
let instrumentFilter = urlParams.get('instrument'); // Pega o parâmetro 'instrument' da URL, se houver
// Função para aplicar o filtro de instrumento
function filterInstruments() {
instrumentButtons.forEach(button => {
const instrumentSlug = button.getAttribute('href').split('=')[1]; // Obtém o slug do instrumento do link
// Se o botão de instrumento não corresponder ao filtro da URL, esconde-o
if (instrumentFilter && instrumentSlug !== instrumentFilter) {
button.style.display = 'none';
} else {
button.style.display = 'inline-block'; // Mostra o botão do instrumento se corresponder ao filtro
}
// Se o botão do instrumento corresponder ao filtro, adiciona a classe de destaque
if (instrumentSlug === instrumentFilter) {
button.classList.add('is-info');
} else {
button.classList.remove('is-info');
}
});
}
filterInstruments(); // Aplica o filtro de instrumentos assim que a página é carregada
// Botão para limpar filtro
const clearFilterButton = document.querySelector('#clearFilterButton');
if (clearFilterButton) {
clearFilterButton.addEventListener('click', function () {
// Limpa o filtro e mostra todos os botões
instrumentButtons.forEach(button => {
button.style.display = 'inline-block'; // Resetando a exibição de todos os botões
button.classList.remove('is-info'); // Removendo a classe de destaque
});
// Remove o parâmetro 'instrument' da URL
const newUrl = new URL(window.location.href);
newUrl.searchParams.delete('instrument');
window.history.replaceState({}, '', newUrl);
// Reaplica o filtro com todos os instrumentos visíveis
instrumentFilter = null; // Reseta o filtro para que todos os instrumentos apareçam
filterInstruments(); // Reaplica a função de filtro para garantir que todos os botões sejam exibidos
});
}
});
</script>

View File

@ -1,39 +0,0 @@
---
layout: default
title: Arquivos MMP Processados
permalink: /arquivosMMP/
---
<main class="main-content">
<div class="publication">
{% include sidebar.html %}
</div>
<div class="publication">
<div class="container">
<h2>Arquivos MMP disponíveis:</h2>
<ul>
{% for files in site.data %}
{% assign file_data = files %}
{% for item in file_data %}
{% if item.file %}
<li><strong>Arquivo:</strong> {{ item.file }}</li>
{% endif %}
{% if item.bpm %}
<li><strong>BPM:</strong> {{ item.bpm }}</li>
{% endif %}
<ul>
{% for track in item.tracks %}
<li><strong>Nome da Faixa:</strong> {{ track.track_name }} ({{ track.type }})</li>
<ul>
{% for instrument in track.instruments %}
<li><strong>Instrumento:</strong> {{ instrument.instrument_name }}</li>
{% endfor %}
</ul>
{% endfor %}
</ul>
{% endfor %}
{% endfor %}
</ul>
</div>
</div>
</main>

View File

@ -5,27 +5,260 @@ permalink: /mmp_pages/
---
<div class="publication">
{% include sidebar.html %}
<div class="container">
<h2 class="title is-4 mb-5"><code>📁 Projetos disponíveis</code></h2>
<br />
<div class="tabs is-centered is-boxed is-medium mb-6">
{% include sidebar.html %}
</div>
<div class="has-text-centered mb-6">
<h1 class="title is-3 has-text-grey-dark">📁 Projetos Disponíveis</h1>
<p class="subtitle is-6 has-text-grey">
Explore, ouça e reutilize projetos da comunidade LMMS.
</p>
<div style="width: 60px; height: 4px; background-color: #3273dc; margin: 1rem auto; border-radius: 2px;"></div>
</div>
<div class="columns is-multiline">
{% assign mmp_pages = site.pages | where_exp: "page", "page.path contains 'mmp_pages/'" | sort: "title" %}
{% for page in mmp_pages %}
{% if page.url != '/mmp_pages/' %}
<div class="column is-6-tablet is-4-desktop is-3-widescreen">
<a href="{{ page.url | relative_url }}" style="text-decoration: none;">
<div class="card hover-shadow" style="height: 100%;">
<div class="card-content">
<p class="title is-6" style="word-break: break-word;">
{{ page.title | default: page.name | replace: '.html', '' }}
</p>
</div>
</div>
</a>
<div class="column is-12-mobile is-6-tablet is-4-desktop is-3-widescreen">
<div class="card project-card"
style="height: 100%; background-color: #f0f8ff; border: 1px solid #cfe8fc; border-radius: 12px; display: flex; flex-direction: column; position: relative;">
<a href="{{ page.url | relative_url }}" style="text-decoration: none; flex: 1; display: flex; flex-direction: column;">
<div class="card-content has-text-centered p-4" style="flex: 1; display: flex; flex-direction: column;">
<div style="width: 50px; height: 50px; 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 fa-lg"></i>
</span>
</div>
<p class="title is-6 mb-2" style="color: #205081; word-break: break-word; font-weight: 700; line-height: 1.2;">
{{ page.title | default: page.name | replace: '.html', '' }}
</p>
{% if page.bpm %}
<div class="mb-3">
<span class="tag is-dark is-rounded is-light" style="font-size: 0.7rem; font-weight: bold; border: 1px solid #ccc;">
🎵 {{ page.bpm }} BPM
</span>
</div>
{% else %}
<div class="mb-3" style="height: 24px;"></div>
{% endif %}
<div style="flex: 1;"></div>
{% if page.tags %}
<div class="mt-auto pt-2" style="width: 100%; border-top: 1px dashed #eef6fc;">
{% for category in page.tags %}
{% assign cat_name = category[0] %}
{% assign cat_items = category[1] %}
{% assign ignore_cat = false %}
{% if cat_name == 'TAG' or cat_name == 'tag' %}{% assign ignore_cat = true %}{% endif %}
{% assign has_items = false %}
{% for item in cat_items %}{% if item != "" %}{% assign has_items = true %}{% endif %}{% endfor %}
{% if ignore_cat == false and has_items %}
<details class="category-reveal mb-1" style="width: 100%;">
<summary class="tag is-white"
style="width: 100%; justify-content: space-between; cursor: pointer; border: 1px solid #deeaf6; color: #5b7da3; padding: 2px 8px; min-height: 22px; margin-bottom: 2px;">
<div style="display: flex; align-items: center; gap: 6px;">
<span style="font-size: 0.7rem;">
{% if cat_name == 'plugin' %}🔌
{% elsif cat_name == 'sample' %}🎤
{% elsif cat_name == 'bassline' %}🎹
{% elsif cat_name == 'automation' %}🎚️
{% else %}🏷️
{% endif %}
</span>
<span style="font-weight: 700; font-size: 0.6rem; text-transform: uppercase; letter-spacing: 0.5px;">
{{ cat_name }}
</span>
</div>
<span class="icon is-small" style="font-size: 0.6rem; opacity: 0.7;">
<i class="fa-solid fa-chevron-down"></i>
</span>
</summary>
<div class="tags is-centered mt-1 mb-2 px-1" style="gap: 3px;">
{% for tag in cat_items %}
{% if tag != "" %}
{% assign tag_slug = tag | replace: ' ', '+' %}
{% assign search_url = '/search/?q=' | append: tag_slug | relative_url %}
{% if cat_name == 'plugin' %}{% assign search_url = '/plugin/?plugin=' | append: tag_slug | relative_url %}{% endif %}
{% if cat_name == 'sample' %}{% assign search_url = '/sample/?sample=' | append: tag_slug | relative_url %}{% endif %}
{% if cat_name == 'bassline' %}{% assign search_url = '/bassline/?bassline=' | append: tag_slug | relative_url %}{% endif %}
{% if cat_name == 'automation' %}{% assign search_url = '/automation/?automation=' | append: tag_slug | relative_url %}{% endif %}
<a href="{{ search_url }}"
class="tag is-light is-info clickable-tag"
style="font-size: 0.6rem; height: 1.5em; border: 1px solid #cfe8fc; text-decoration: none; padding: 0 6px;">
{{ tag | truncate: 18 }}
</a>
{% endif %}
{% endfor %}
</div>
</details>
{% endif %}
{% endfor %}
</div>
{% endif %}
</div>
</a>
<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 | relative_url }}"
data-modal-title="Detalhes: {{ page.file }}"
data-full-btn-text="Ir para Página"
data-full-btn-link="{{ page.url | relative_url }}"
style="color: #5b7da3; font-size: 0.8rem; font-weight: 600; border-right: 1px solid #eee; transition: background 0.2s;">
Ver
</a>
{% assign creation_url = '/mmpSearch/creation.html?project=' | append: page.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: {{ page.file }}"
data-full-btn-text="Abrir Editor"
data-full-btn-link="{{ creation_url }}"
style="color: #3273dc; font-size: 0.8rem; font-weight: 600; transition: background 0.2s;">
Editar
</a>
</footer>
</div>
</div>
{% endif %}
{% endfor %}
</div>
<br><br>
</div>
</div>
<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">
<span>Abrir</span>
<span class="icon is-small ml-1"><i class="fa-solid fa-up-right-from-square"></i></span>
</a>
</footer>
</div>
</div>
<style>
.project-card:hover {
transform: translateY(-5px);
box-shadow: 0 8px 20px rgba(50, 115, 220, 0.15);
border-color: #3273dc !important;
background-color: #fff !important;
}
.project-card:hover .title {
color: #3273dc !important;
}
.category-reveal summary {
list-style: none;
transition: all 0.2s ease;
}
.category-reveal summary::-webkit-details-marker { display: none; }
.category-reveal summary:hover {
background-color: #f8fbff;
border-color: #3273dc;
}
.category-reveal[open] summary {
background-color: #eef6fc !important;
border-color: #3273dc !important;
color: #3273dc !important;
}
.category-reveal[open] summary .fa-chevron-down { transform: rotate(180deg); }
.category-reveal summary .fa-chevron-down { transition: transform 0.2s ease; }
.clickable-tag { transition: all 0.2s ease; }
.clickable-tag:hover {
background-color: #3273dc !important;
color: #fff !important;
border-color: #3273dc !important;
transform: translateY(-1px);
}
</style>
<script>
document.addEventListener('DOMContentLoaded', () => {
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() {
if(!modal) return;
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();
const url = btn.dataset.targetUrl;
const title = btn.dataset.modalTitle;
const btnText = btn.dataset.fullBtnText;
const btnLink = btn.dataset.fullBtnLink;
openModal(url, title, btnText, btnLink);
});
});
// Tenta esconder o menu dentro do iframe para não duplicar
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>

127
package-lock.json generated
View File

@ -1,127 +0,0 @@
{
"name": "mmpSearch",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"dependencies": {
"pino": "^10.1.0"
}
},
"node_modules/@pinojs/redact": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/@pinojs/redact/-/redact-0.4.0.tgz",
"integrity": "sha512-k2ENnmBugE/rzQfEcdWHcCY+/FM3VLzH9cYEsbdsoqrvzAKRhUZeRNhAZvB8OitQJ1TBed3yqWtdjzS6wJKBwg=="
},
"node_modules/atomic-sleep": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/atomic-sleep/-/atomic-sleep-1.0.0.tgz",
"integrity": "sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==",
"engines": {
"node": ">=8.0.0"
}
},
"node_modules/on-exit-leak-free": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/on-exit-leak-free/-/on-exit-leak-free-2.1.2.tgz",
"integrity": "sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==",
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/pino": {
"version": "10.1.0",
"resolved": "https://registry.npmjs.org/pino/-/pino-10.1.0.tgz",
"integrity": "sha512-0zZC2ygfdqvqK8zJIr1e+wT1T/L+LF6qvqvbzEQ6tiMAoTqEVK9a1K3YRu8HEUvGEvNqZyPJTtb2sNIoTkB83w==",
"dependencies": {
"@pinojs/redact": "^0.4.0",
"atomic-sleep": "^1.0.0",
"on-exit-leak-free": "^2.1.0",
"pino-abstract-transport": "^2.0.0",
"pino-std-serializers": "^7.0.0",
"process-warning": "^5.0.0",
"quick-format-unescaped": "^4.0.3",
"real-require": "^0.2.0",
"safe-stable-stringify": "^2.3.1",
"sonic-boom": "^4.0.1",
"thread-stream": "^3.0.0"
},
"bin": {
"pino": "bin.js"
}
},
"node_modules/pino-abstract-transport": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/pino-abstract-transport/-/pino-abstract-transport-2.0.0.tgz",
"integrity": "sha512-F63x5tizV6WCh4R6RHyi2Ml+M70DNRXt/+HANowMflpgGFMAym/VKm6G7ZOQRjqN7XbGxK1Lg9t6ZrtzOaivMw==",
"dependencies": {
"split2": "^4.0.0"
}
},
"node_modules/pino-std-serializers": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-7.0.0.tgz",
"integrity": "sha512-e906FRY0+tV27iq4juKzSYPbUj2do2X2JX4EzSca1631EB2QJQUqGbDuERal7LCtOpxl6x3+nvo9NPZcmjkiFA=="
},
"node_modules/process-warning": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/process-warning/-/process-warning-5.0.0.tgz",
"integrity": "sha512-a39t9ApHNx2L4+HBnQKqxxHNs1r7KF+Intd8Q/g1bUh6q0WIp9voPXJ/x0j+ZL45KF1pJd9+q2jLIRMfvEshkA==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/fastify"
},
{
"type": "opencollective",
"url": "https://opencollective.com/fastify"
}
]
},
"node_modules/quick-format-unescaped": {
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/quick-format-unescaped/-/quick-format-unescaped-4.0.4.tgz",
"integrity": "sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg=="
},
"node_modules/real-require": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/real-require/-/real-require-0.2.0.tgz",
"integrity": "sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==",
"engines": {
"node": ">= 12.13.0"
}
},
"node_modules/safe-stable-stringify": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz",
"integrity": "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==",
"engines": {
"node": ">=10"
}
},
"node_modules/sonic-boom": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-4.2.0.tgz",
"integrity": "sha512-INb7TM37/mAcsGmc9hyyI6+QR3rR1zVRu36B0NeGXKnOOLiZOfER5SA+N7X7k3yUYRzLWafduTDvJAfDswwEww==",
"dependencies": {
"atomic-sleep": "^1.0.0"
}
},
"node_modules/split2": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz",
"integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==",
"engines": {
"node": ">= 10.x"
}
},
"node_modules/thread-stream": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/thread-stream/-/thread-stream-3.1.0.tgz",
"integrity": "sha512-OqyPZ9u96VohAyMfJykzmivOrY2wfMSf3C5TtFJVgN+Hm6aj+voFhlK+kZEIv2FBh1X6Xp3DlnCOfEQ3B2J86A==",
"dependencies": {
"real-require": "^0.2.0"
}
}
}
}

View File

@ -1,5 +0,0 @@
{
"dependencies": {
"pino": "^10.1.0"
}
}

View File

@ -1,404 +0,0 @@
---
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>

574
pattern.md Normal file
View File

@ -0,0 +1,574 @@
---
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"
>
<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>

View File

@ -1,125 +0,0 @@
---
layout: default
title: Projetos com a tag Plugin
permalink: /plugin/
---
<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;">
<!-- Título -->
<div class="column is-auto">
<h2 class="title is-4"><code>Projetos que possuem a tag plugin:</code></h2>
</div>
<!-- Botão Limpar Filtro -->
<div class="column is-auto">
<button id="clearFilterButton" class="button is-small is-light">
Limpar filtro
</button>
</div>
</div>
<!-- Projetos -->
<div id="project-list" class="columns is-multiline">
{% for projeto in site.data.all %}
{% if projeto.tags.TAG contains "plugin" %}
<div class="column is-6 project-item" data-plugins="{{ projeto.tags.plugin | join: ',' }}">
<div class="box">
<!-- Botão do projeto -->
{% 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>
<!-- Lista de plugins clicáveis -->
{% if projeto.tags.plugin and projeto.tags.plugin.size > 0 %}
<div style="margin-top: 1rem;">
<p><strong>Plugins:</strong></p>
<ul style="list-style-type: disc; padding-left: 1.25rem;">
{% for plugin in projeto.tags.plugin %}
{% if plugin != "" %}
<li><a href="#" class="plugin-item" data-plugin="{{ plugin }}">{{ plugin }}</a></li>
{% endif %}
{% endfor %}
</ul>
</div>
{% endif %}
</div>
</div>
{% endif %}
{% endfor %}
</div>
</div>
</main>
<script>
document.addEventListener('DOMContentLoaded', function () {
const projects = document.querySelectorAll('.project-item');
// Função para aplicar filtro por plugin
function filterByPlugin(pluginName) {
projects.forEach(project => {
const projectPlugins = project.getAttribute('data-plugins').split(',');
if (projectPlugins.includes(pluginName)) {
project.style.display = 'block';
} else {
project.style.display = 'none';
}
});
}
// Lê o plugin da URL se houver
const urlParams = new URLSearchParams(window.location.search);
const pluginFromUrl = urlParams.get('plugin');
if (pluginFromUrl) {
filterByPlugin(pluginFromUrl);
}
// Ao clicar num plugin na lista
const pluginItems = document.querySelectorAll('.plugin-item');
pluginItems.forEach(item => {
item.addEventListener('click', function (event) {
event.preventDefault();
const selectedPlugin = item.getAttribute('data-plugin');
filterByPlugin(selectedPlugin);
// Atualiza a URL sem recarregar a página
const newUrl = new URL(window.location.href);
newUrl.searchParams.set('plugin', selectedPlugin);
window.history.replaceState({}, '', newUrl);
});
});
// Botão para limpar filtro
const clearFilterButton = document.querySelector('#clearFilterButton');
clearFilterButton.addEventListener('click', function () {
projects.forEach(project => {
project.style.display = 'block';
});
// Remove o filtro da URL
const newUrl = new URL(window.location.href);
newUrl.searchParams.delete('plugin');
window.history.replaceState({}, '', newUrl);
});
});
</script>

504
plugin.md Normal file
View File

@ -0,0 +1,504 @@
---
layout: default
title: Projetos com a tag Plugin
permalink: /plugin/
---
<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>
<details
class="box mb-5 p-0 collapse-card"
open
style="
border: 1px solid #cfe8fc;
overflow: hidden;
background-color: #fff;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.05);
height: fit-content !important;
min-height: unset;
"
>
<summary
class="p-4 is-flex is-justify-content-space-between is-align-items-center"
style="cursor: pointer; background-color: #f8fbff; user-select: none"
>
<div class="is-flex is-align-items-center">
<span class="icon has-text-info mr-2"
><i class="fa-solid fa-list"></i
></span>
<span class="has-text-grey-dark has-text-weight-bold"
>Todos os Plugins Disponíveis</span
>
<span
id="filter-counter"
class="tag is-info is-light ml-3 is-hidden"
>0 selecionados</span
>
</div>
<span class="icon has-text-grey-light chevron-icon"
><i class="fa-solid fa-chevron-down"></i
></span>
</summary>
<div
class="p-4"
style="background-color: #fff; border-top: 1px solid #cfe8fc"
>
<div class="tags is-centered are-medium mb-0">
{% assign all_items_string = "" %} {% for p in site.data.all %} {%
if p.tags.plugin %} {% for item in p.tags.plugin %} {% if item != ""
%} {% unless all_items_string contains item %} {% assign
all_items_string = all_items_string | append: item | append: "|||"
%} {% endunless %} {% endif %} {% endfor %} {% endif %} {% endfor %}
{% assign unique_items = all_items_string | split: "|||" | sort %}
{% for item in unique_items %} {% if item != "" %}
<a
href="#"
class="tag is-white plugin-filter-item clickable-tag"
data-value="{{ item }}"
style="
border: 1px solid #deeaf6;
color: #5b7da3;
margin-bottom: 0.5rem;
transition: all 0.2s;
"
>
{{ item }}
</a>
{% endif %} {% endfor %}
</div>
</div>
</details>
<div class="columns is-mobile is-vcentered mb-5">
<div class="column is-auto">
<h2 class="title is-4 has-text-grey-dark">
<span class="icon has-text-info mr-2"
><i class="fa-solid fa-filter"></i
></span>
Filtro:
<code id="filter-display-name" style="color: #d63384">(todos)</code>
</h2>
</div>
<div class="column is-narrow">
<button
id="clearFilterButton"
class="button is-small is-danger is-light"
>
<span class="icon is-small"><i class="fa-solid fa-xmark"></i></span>
<span>Limpar Tudo</span>
</button>
</div>
</div>
<div id="project-list" class="columns is-multiline">
{% for projeto in site.data.all %} {% if projeto.tags.TAG contains
"plugin" %}
<div
class="column is-12-mobile is-6-tablet is-4-desktop is-3-widescreen project-item"
data-plugins="{{ projeto.tags.plugin | join: ',' }}"
>
<div
class="card project-card"
style="
height: 100%;
background-color: #f0f8ff;
border: 1px solid #cfe8fc;
border-radius: 12px;
display: flex;
flex-direction: column;
position: relative;
"
>
{% 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;
flex: 1;
display: flex;
flex-direction: column;
"
>
<div
class="card-content has-text-centered p-4"
style="flex: 1; display: flex; flex-direction: column"
>
<div
style="
width: 50px;
height: 50px;
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 fa-lg"></i
></span>
</div>
<p
class="title is-6 mb-2"
style="
color: #205081;
word-break: break-word;
font-weight: 700;
line-height: 1.2;
"
>
{{ projeto.file }}
</p>
{% if projeto.bpm %}
<div class="mb-3">
<span
class="tag is-dark is-rounded is-light"
style="
font-size: 0.7rem;
font-weight: bold;
border: 1px solid #ccc;
"
>
🎵 {{ projeto.bpm }} BPM
</span>
</div>
{% else %}
<div class="mb-3" style="height: 24px"></div>
{% endif %}
<div style="flex: 1"></div>
{% if projeto.tags.plugin and projeto.tags.plugin.size > 0 %}
<div
class="tags is-centered is-gapless mb-0 mt-2"
style="gap: 4px; justify-content: center"
>
{% for item in projeto.tags.plugin %} {% if item != "" %}
<span
class="tag is-white project-tag-item clickable-tag"
data-value="{{ item }}"
style="
font-size: 0.65rem;
border: 1px solid #deeaf6;
color: #5b7da3;
padding: 0 6px;
height: 1.5em;
text-decoration: none;
cursor: pointer;
"
>
{{ item | truncate: 15 }}
</span>
{% endif %} {% endfor %}
</div>
{% endif %}
</div>
</a>
<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;
transition: background 0.2s;
"
>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>
<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>
<style>
.project-card:hover {
transform: translateY(-5px);
box-shadow: 0 8px 20px rgba(50, 115, 220, 0.15);
border-color: #3273dc !important;
background-color: #fff !important;
}
/* Tag normal */
.clickable-tag:hover {
background-color: #e3effd !important;
color: #3273dc !important;
border-color: #3273dc !important;
transform: scale(1.05);
}
/* Tag ATIVA (Selecionada) */
.tag.is-active-filter {
background-color: #3273dc !important;
color: #fff !important;
border-color: #3273dc !important;
font-weight: bold;
box-shadow: 0 2px 5px rgba(50, 115, 220, 0.3);
}
/* Animação do Accordion */
.collapse-card summary {
list-style: none;
transition: background 0.2s;
}
.collapse-card summary::-webkit-details-marker {
display: none;
}
.collapse-card[open] summary .chevron-icon {
transform: rotate(180deg);
}
.chevron-icon {
transition: transform 0.3s ease;
}
</style>
<script>
document.addEventListener("DOMContentLoaded", function () {
const projects = document.querySelectorAll(".project-item");
const filterDisplayName = document.getElementById("filter-display-name");
const filterCounter = document.getElementById("filter-counter");
// --- ESTADO GLOBAL DOS FILTROS ---
let activeFilters = []; // Array de strings
// --- FUNÇÃO PRINCIPAL DE FILTRAGEM ---
function applyFilters() {
// 1. Atualiza Texto do Título
if (activeFilters.length > 0) {
filterDisplayName.textContent = activeFilters.join(" + ");
filterCounter.textContent = activeFilters.length + " selecionados";
filterCounter.classList.remove("is-hidden");
} else {
filterDisplayName.textContent = "(todos)";
filterCounter.classList.add("is-hidden");
}
// 2. Atualiza visual das Tags (Nuvem e Cards)
document.querySelectorAll("[data-value]").forEach((tag) => {
const val = tag.getAttribute("data-value");
if (activeFilters.includes(val)) {
tag.classList.add("is-active-filter");
} else {
tag.classList.remove("is-active-filter");
}
});
// 3. Mostra/Esconde Projetos
projects.forEach((project) => {
const projectPluginsStr = project.getAttribute("data-plugins");
const projectPlugins = projectPluginsStr
.split(",")
.map((s) => s.trim());
if (activeFilters.length === 0) {
// Sem filtro: mostra tudo
project.style.display = "block";
} else {
// Com filtro: Lógica "OU" (Mostra se tiver pelo menos UM dos selecionados)
// Se quiser lógica "E" (tem que ter TODOS), troque .some() por .every()
const hasMatch = activeFilters.some((filter) =>
projectPlugins.includes(filter)
);
project.style.display = hasMatch ? "block" : "none";
}
});
// 4. Atualiza URL
const newUrl = new URL(window.location.href);
if (activeFilters.length > 0) {
newUrl.searchParams.set("plugin", activeFilters.join(","));
} else {
newUrl.searchParams.delete("plugin");
}
window.history.replaceState({}, "", newUrl);
}
// --- GERENCIADOR DE CLIQUES (TOGGLE) ---
function toggleFilter(val) {
const index = activeFilters.indexOf(val);
if (index > -1) {
activeFilters.splice(index, 1); // Remove se já existe
} else {
activeFilters.push(val); // Adiciona se não existe
}
applyFilters();
}
// --- INICIALIZAÇÃO ---
// 1. Lê URL ao carregar
const urlParams = new URLSearchParams(window.location.search);
const pluginParam = urlParams.get("plugin");
if (pluginParam) {
// Suporta ?plugin=a,b,c
activeFilters = pluginParam
.split(",")
.map((s) => s.trim())
.filter((s) => s !== "");
applyFilters();
}
// 2. Eventos de Clique (Nuvem e Cards)
// Usamos event delegation ou selecionamos todos
const allClickableTags = document.querySelectorAll(
".plugin-filter-item, .project-tag-item"
);
allClickableTags.forEach((tag) => {
tag.addEventListener("click", function (e) {
e.preventDefault();
const val = this.getAttribute("data-value");
toggleFilter(val);
});
});
// 3. Botão Limpar
document
.querySelector("#clearFilterButton")
.addEventListener("click", function () {
activeFilters = [];
applyFilters();
});
// --- MODAL (Padrão) ---
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) {
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>

View File

@ -1,46 +0,0 @@
---
layout: default
title: Projetos com Instrumentos Similares
permalink: /quaisProjetos/
---
<meta charset="utf-8">
<main class="main-content">
<div class="publication">
{% include sidebar.html %}
</div>
<div class="container">
<h2>Arquivos que possuem instrumentos similares:</h2>
{% assign tags_exibidas = "" %}
{% for item in site.data.all %}
{% for tag in item.tags.TAG %}
{% unless tags_exibidas contains tag %}
{% capture tags_exibidas %}{{ tags_exibidas }},{{ tag }}{% endcapture %}
<div class="dropdown is-hoverable" style="margin-bottom: 1rem;">
<div class="dropdown-trigger">
<button class="button" aria-haspopup="true" aria-controls="dropdown-menu-{{ forloop.index }}">
<span>{{ tag }}</span>
<span class="icon is-small">
<i class="fas fa-angle-down" aria-hidden="true"></i>
</span>
</button>
</div>
<div class="dropdown-menu" id="dropdown-menu-{{ forloop.index }}" role="menu">
<div class="dropdown-content">
{% for arquivo in site.data.all %}
{% if arquivo.tags.TAG contains tag %}
<a href="../mmp_pages/{{ arquivo.file | downcase | replace: ' ', '-' | replace: 'ç', 'c' | replace: 'ã', 'a' | replace: 'í', 'i'
| replace: 'ó', 'o' | replace: 'ú', 'u'}}.html" class="dropdown-item">{{ arquivo.file | downcase }}</a>
{% endif %}
{% endfor %}
</div>
</div>
</div>
{% endunless %}
{% endfor %}
{% endfor %}
</div>
</main>

View File

@ -3,37 +3,55 @@ layout: default
title: Projetos por tipo de track
permalink: /projetosPorTrack/
---
<meta charset="utf-8">
<main class="main-content">
<div class="publication">
{% include sidebar.html %}
<div class="container">
<br>
Arquivos que possuem instrumentos similares:
<br><br>
<div class="container">
<br>
<div class="tabs is-centered is-boxed is-medium mb-6">
{% include sidebar.html %}
</div>
<a href="{{ '/instruments/' | relative_url }}" class="button is-link" style="margin-bottom: 1rem;">
Ver Projetos por Instrumento
</a>
<div class="columns">
<div class="column is-8 is-offset-2">
<div class="box has-text-centered has-background-white-ter">
<h2 class="title is-4 mb-5">Navegar por Categorias</h2>
<br>
Arquivos que possuem tracks similares:
<br><br>
<a href="{{ '/instruments/' | relative_url }}" class="button is-link is-outlined is-medium mb-5">
<span class="icon"><i class="fa-solid fa-guitar"></i></span>
<span>BUSCAR POR INSTRUMENTO</span>
</a>
{% assign tags_exibidas = "" %}
{% for item in site.data.all %}
{% for tag in item.tags.TAG %}
{% unless tags_exibidas contains tag %}
{% capture tags_exibidas %}{{ tags_exibidas }},{{ tag }}{% endcapture %}
<div class="divider"></div>
<a href="../{{ tag | downcase | replace: ' ', '-' }}" class="button is-link" style="margin-bottom: 1rem;">
{{ tag }}
</a>
<a href="{{ '/pattern/' | relative_url }}" class="button is-link is-outlined is-medium mb-5">
<span class="icon"><i class="fa-solid fa-guitar"></i></span>
<span>BUSCAR POR DESENHO DE PATTERN</span>
</a>
<div class="divider">OU POR TIPO DE TRACK</div>
<div class="tags is-centered are-medium mt-4">
{% assign tags_exibidas = "" %}
{% for item in site.data.all %}
{% for tag in item.tags.TAG %}
{% unless tags_exibidas contains tag %}
{% capture tags_exibidas %}{{ tags_exibidas }},{{ tag }}{% endcapture %}
<a href="../{{ tag | downcase | replace: ' ', '-' }}" class="tag is-white project-card"
style="border: 1px solid #cfe8fc; color: #205081; padding: 1.5rem 1rem;">
{{ tag | upcase }}
</a>
{% endunless %}
{% endfor %}
{% endfor %}
</div>
</div>
</div>
</div>
</div>
{% endunless %}
{% endfor %}
{% endfor %}
</div>
</div>
</main>

View File

@ -137,3 +137,13 @@ Um serviço systemd foi criado para hospedar o backend de um servidor em nodeJS
- [ ] Permitir escolha entre download ou salvar no servidor
- [ ] Escolher nome do projeto
ALICE MMPSearch
This is a repository with the purpose of creating a site using Jekyll to serve as a LMMS Beat File Library.
The intuitive is to be able to collect information from the files by indexing it and allows search with the most diverse filters.
It is part of the master's research in Computer Science at the Federal University of São João del Rei, focused on independent underground music production and the use of open source technologies.
The mainstream only exists because the underground created the scene.

View File

@ -3,12 +3,14 @@ layout: default
title: Projetos com a tag Sample
permalink: /sample/
---
<meta charset="utf-8">
<main class="main-content">
<div class="publication">
{% include sidebar.html %}
</div>
<div class="tabs is-centered is-boxed is-medium mb-6">
{% include sidebar.html %}
</div>
<div class="container">
<div class="columns is-mobile is-vcentered" style="margin-bottom: 2rem;">
@ -67,6 +69,7 @@ permalink: /sample/
{% endif %}
{% endfor %}
</div>
</div>
</main>

View File

@ -1,12 +1,14 @@
---
layout: default
title: Beats Disponíveis
permalink: /beatsDisponiveis/
permalink: /beats/
---
<main class="main-content">
<div class="publication">
{% include sidebar.html %}
<div class="tabs is-centered is-boxed is-medium mb-6">
{% include sidebar.html %}
</div>
<div class="container">
<br>
<h2 class="title is-4 mb-5"><code>🎧 Lista de Beats 🎧</code></h2>
@ -66,6 +68,7 @@ permalink: /beatsDisponiveis/
{% endfor %}
</div>
</div>
</div>
</main>