-
Notifications
You must be signed in to change notification settings - Fork 0
Technical Architecture
A Arquitetura Técnica do Sistema de Funcionalidades Modulares do Contramaré explica como os componentes interagem em nível de código para proporcionar um sistema flexível e otimizado.
graph TD
subgraph "Configuração"
A[_config.yml]
A1[features]
A2[category_feature_map]
A --> A1
A --> A2
end
subgraph "Processamento"
B[Jekyll Hooks]
C[Plugin feature_filter.rb]
D[Pré-computa Categorias]
E[Filtra Posts]
F[Armazena em site.data]
B --> C
C --> D
D --> E
E --> F
end
subgraph "Templates"
G[Filtros Liquid]
H[posts_by_active_features]
I[category_is_active]
J[feature_stats]
G --> H
G --> I
G --> J
end
subgraph "Proteção de Conteúdo"
K[Condicionais em Layouts]
L[Condicionais no Menu]
M[Página Content Unavailable]
K --> M
L -.-> K
end
A1 --> D
A2 --> D
F --> G
H --> K
I --> K
contramare/
├── _config.yml # Configuração principal
├── _plugins/
│ └── feature_filter.rb # Plugin de filtragem
├── _includes/
│ ├── header.html # Menu com condicionais
│ ├── content_unavailable.html # Mensagem para função inativa
│ └── last_publications.html # Lista de posts filtrada
├── _layouts/
│ ├── post.html # Proteção de posts individuais
│ └── quotes.html # Layout específico para frases
└── pages/
├── blog.html # Página com filtragem
└── quotes.html # Página com proteção
O centro de controle do sistema onde as funcionalidades são definidas:
# Controle de funcionalidades
features:
quotes_page: false
blog_page: true
contact_page: true
about_page: true
# Mapeamento de categorias para funcionalidades
category_feature_map:
"Frases": "quotes_page"
"Blog": "blog_page"
"Reflexões": "blog_page"Este plugin é dividido em duas partes principais:
module FeatureFilterOptimized
# Hook executado após carregar todos os posts
Jekyll::Hooks.register :site, :post_read do |site|
Jekyll.logger.info "FeatureFilter:", "Processando posts por features ativas..."
process_posts_by_features(site)
end
def self.process_posts_by_features(site)
features = site.config['features'] || {}
category_map = site.config['category_feature_map'] || {}
# Pré-computa quais categorias estão ativas
active_categories = Set.new
category_map.each do |category, feature_key|
active_categories << category if features[feature_key] == true
end
# Filtra posts baseado nas features ativas
active_posts = site.posts.docs.select do |post|
post_categories = extract_categories(post)
next true if post_categories.empty?
post_categories.any? do |category|
!category_map.key?(category) || active_categories.include?(category)
end
end
# Disponibiliza dados pre-computados para templates
site.data['filtered_posts'] = active_posts
site.data['active_categories'] = active_categories.to_a
site.data['feature_stats'] = {
'total_posts' => site.posts.docs.length,
'active_posts' => active_posts.length,
'filtered_count' => site.posts.docs.length - active_posts.length
}
end
def self.extract_categories(post)
categories = post.data['categories']
return [] if categories.nil?
[categories].flatten.compact.map(&:to_s)
end
endmodule FeatureFilterLiquid
def posts_by_active_features(posts = nil)
site = @context.registers[:site]
# Se não passou posts específicos, retorna os pre-computados
return site.data['filtered_posts'] || [] if posts.nil?
# Filtra posts específicos usando dados pre-computados
active_categories = Set.new(site.data['active_categories'] || [])
category_map = site.config['category_feature_map'] || {}
posts.select do |post|
post_categories = FeatureFilterOptimized.extract_categories(post)
next true if post_categories.empty?
post_categories.any? do |category|
!category_map.key?(category) || active_categories.include?(category)
end
end
end
def category_is_active(category)
return true if category.nil? || category.empty?
site = @context.registers[:site]
active_categories = site.data['active_categories'] || []
category_map = site.config['category_feature_map'] || {}
# Categoria ativa se não está mapeada OU está na lista de ativas
!category_map.key?(category.to_s) || active_categories.include?(category.to_s)
end
def feature_stats
@context.registers[:site].data['feature_stats'] || {}
end
end
Liquid::Template.register_filter(FeatureFilterLiquid)Template exibido quando uma funcionalidade está desativada:
<div class="main container d-flex flex-column justify-content-center align-items-center" style="min-height: 60vh;">
<h2>Conteúdo Temporariamente Indisponível</h2>
<p>Este tipo de conteúdo está temporariamente desabilitado.</p>
<p><a href="{{ site.baseurl }}/">← Voltar ao início</a></p>
</div>Proteção para posts individuais:
{% assign post_category = page.categories | first %}
{% assign category_active = post_category | category_is_active %}
{% if category_active %}
<!-- Conteúdo normal do post -->
<article>
<h1>{{ page.title }}</h1>
{{ content }}
</article>
{% else %}
<!-- Mensagem de indisponibilidade -->
{% include content_unavailable.html %}
{% endif %}Navegação adaptativa baseada em funcionalidades:
<nav class="navbar">
<ul class="nav">
<li class="nav-item">
<a class="nav-link" href="/">HOME</a>
</li>
{% if site.features.blog_page %}
<li class="nav-item">
<a class="nav-link" href="/blog/">BLOG</a>
</li>
{% endif %}
{% if site.features.quotes_page %}
<li class="nav-item">
<a class="nav-link" href="/quotes/">FRASES</a>
</li>
{% endif %}
{% if site.features.contact_page %}
<li class="nav-item">
<a class="nav-link" href="/contact/">CONTATO</a>
</li>
{% endif %}
{% if site.features.about_page %}
<li class="nav-item">
<a class="nav-link" href="/about/">SOBRE</a>
</li>
{% endif %}
</ul>
</nav>Exibição filtrada de posts recentes:
<section class="recent-posts">
<h2>Publicações Recentes</h2>
{% if site.features.blog_page %}
{% assign filtered_posts = site.posts | posts_by_active_features %}
<div class="row">
{% for post in filtered_posts limit:3 %}
<div class="col-md-4">
<div class="card">
<h3>{{ post.title }}</h3>
<p>{{ post.excerpt | truncate: 100 }}</p>
<a href="{{ post.url }}">Leia mais</a>
</div>
</div>
{% endfor %}
</div>
{% else %}
<p>Publicações em breve.</p>
{% endif %}
</section>- Jekyll inicia o build do site
- Hook
post_readé executado após carregar todos os posts - Plugin
feature_filter.rbanalisa funcionalidades ativas - Plugin prepara lista de categorias ativas baseado no mapeamento
- Posts são filtrados segundo as regras estabelecidas
- Resultados são armazenados em
site.datapara acesso rápido
- Templates Jekyll são processados
- Filtros Liquid
posts_by_active_featuresecategory_is_activesão aplicados - Posts filtrados são exibidos em listas
- Posts individuais são protegidos conforme sua categoria
- Menus são adaptados às funcionalidades ativas
O sistema usa pré-computação para evitar repetir o mesmo trabalho:
# Armazena dados computed uma única vez
site.data['filtered_posts'] = active_posts
site.data['active_categories'] = active_categories.to_aUso de Set para comparação O(1) de categorias:
# Set para busca eficiente O(1)
active_categories = Set.new
category_map.each do |category, feature_key|
active_categories << category if features[feature_key] == true
endProcessa apenas subcoleções quando necessário:
def posts_by_active_features(posts = nil)
# Se não passou posts específicos, retorna os pre-computados
return site.data['filtered_posts'] || [] if posts.nil?
# Caso contrário, filtra apenas a subcoleção
# ...
endO sistema separa claramente suas responsabilidades:
-
Configuração:
_config.yml(único ponto de controle) -
Processamento:
feature_filter.rb(lógica encapsulada) - Templates: Filtros Liquid (interface para designers)
- Proteção: Condicionais em layouts e includes
Usa hooks do Jekyll para integração não-intrusiva:
Jekyll::Hooks.register :site, :post_read do |site|
# ...
endAdiciona funcionalidades ao Liquid sem modificar suas classes internas:
Liquid::Template.register_filter(FeatureFilterLiquid)O sistema foi projetado para ser facilmente extensível:
- Adicione a chave em
features - Mapeie categorias se necessário
- Adicione condicionais no menu
- Implemente proteção na página
Para adicionar novos filtros personalizados:
module FeatureFilterLiquid
def posts_by_custom_rule(posts)
# Implementação personalizada
end
# Registre o novo filtro
Liquid::Template.register_filter(FeatureFilterLiquid)
endPara coletar métricas adicionais:
site.data['feature_stats'] = {
'total_posts' => site.posts.docs.length,
'active_posts' => active_posts.length,
'filtered_count' => site.posts.docs.length - active_posts.length,
'custom_metric' => custom_calculation
}- Veja como ativar funcionalidades
- Entenda o mapeamento de categorias
- Explore o sistema de filtragem de posts
Custom footer