[🛠] Adicionar calendário e estatísticas de atividade à sidebar do blog no GitHub Pages
✨ Resumo do GPT-5.5
Registro de como, logo depois de retomar o blog, anexei à sidebar um calendário de posts e estatísticas de atividade por categoria, além de navegação pelo mês do post atual e por arquivos mensais.
Depois de organizar /devlog/github-pages-blog/github-pages-blog-restart-system/, o problema seguinte apareceu imediatamente.
Eu tinha começado a escrever posts de novo. Mas ainda faltava a sensação de que o blog tinha voltado à vida. Apenas uma lista de categorias não mostrava bem quando este blog se moveu, em quais dias os registros se acumularam e que fluxo recente existia.
Para voltar a escrever Daily Review, a sensação de data é importante.
No fim, este blog se concentra em “em que dia deixei o quê”. Mas um blog no GitHub Pages não tem uma navegação por datas que aparece naturalmente como no Naver Blog. Por ser um blog estático, eu precisava criar isso diretamente.
Por isso a funcionalidade anexada esta noite não era uma simples decoração.
Foi um trabalho para transformar a sidebar de enfeite auxiliar da lista de posts em uma ferramenta de navegação que mostra datas e fluxo de atividade.
O primeiro item anexado foi um calendário pequeno e direto
O primeiro commit foi f6971fc.
f6971fc feat: add sidebar activity widgets
Nessa hora, criei dois arquivos novos.
_includes/sidebar-calendar.html
_includes/sidebar-nav-stats.html
Anexei o include do calendário ao sidebar.html.
<section class="sidebar-calendar"
data-sidebar-calendar
data-calendar-lang="pt-BR"
data-calendar-posts-src="/assets/data/calendar-posts-pt-BR.json"
data-calendar-weekdays="["Dom","Seg","Ter","Qua","Qui","Sex","Sáb"]"
data-calendar-label-suffix="calendário de publicações"
data-calendar-post-count-label="post(s)"
data-calendar-post-list-label="posts"
data-initial-month="2026-05"
data-focus-date="2026-05-26"
data-current-path="/pt-BR/devlog/github-pages-blog/github-pages-blog-sidebar-calendar/"
data-min-month="2024-12"
data-max-month="2026-06"
aria-label="2026.05 calendário de publicações">
<div class="sidebar-calendar__archive" data-calendar-archive aria-label="Contagem de publicações por ano e mês">
<div class="sidebar-calendar__years" data-calendar-years></div>
<div class="sidebar-calendar__months" data-calendar-months></div>
</div>
<div class="sidebar-calendar__grid" data-calendar-grid>
<span class="sidebar-calendar__weekday">Dom</span>
<span class="sidebar-calendar__weekday">Seg</span>
<span class="sidebar-calendar__weekday">Ter</span>
<span class="sidebar-calendar__weekday">Qua</span>
<span class="sidebar-calendar__weekday">Qui</span>
<span class="sidebar-calendar__weekday">Sex</span>
<span class="sidebar-calendar__weekday">Sáb</span>
<span class="sidebar-calendar__day sidebar-calendar__day--blank" aria-hidden="true"></span>
<span class="sidebar-calendar__day sidebar-calendar__day--blank" aria-hidden="true"></span>
<span class="sidebar-calendar__day sidebar-calendar__day--blank" aria-hidden="true"></span>
<span class="sidebar-calendar__day sidebar-calendar__day--blank" aria-hidden="true"></span>
<span class="sidebar-calendar__day sidebar-calendar__day--blank" aria-hidden="true"></span>
<span class="sidebar-calendar__day"><span class="sidebar-calendar__day-number">1</span></span>
<span class="sidebar-calendar__day"><span class="sidebar-calendar__day-number">2</span></span>
<span class="sidebar-calendar__day"><span class="sidebar-calendar__day-number">3</span></span>
<span class="sidebar-calendar__day"><span class="sidebar-calendar__day-number">4</span></span>
<span class="sidebar-calendar__day"><span class="sidebar-calendar__day-number">5</span></span>
<span class="sidebar-calendar__day"><span class="sidebar-calendar__day-number">6</span></span>
<span class="sidebar-calendar__day"><span class="sidebar-calendar__day-number">7</span></span>
<span class="sidebar-calendar__day"><span class="sidebar-calendar__day-number">8</span></span>
<span class="sidebar-calendar__day"><span class="sidebar-calendar__day-number">9</span></span>
<span class="sidebar-calendar__day"><span class="sidebar-calendar__day-number">10</span></span>
<span class="sidebar-calendar__day"><span class="sidebar-calendar__day-number">11</span></span>
<span class="sidebar-calendar__day"><span class="sidebar-calendar__day-number">12</span></span>
<span class="sidebar-calendar__day"><span class="sidebar-calendar__day-number">13</span></span>
<span class="sidebar-calendar__day"><span class="sidebar-calendar__day-number">14</span></span>
<span class="sidebar-calendar__day"><span class="sidebar-calendar__day-number">15</span></span>
<span class="sidebar-calendar__day"><span class="sidebar-calendar__day-number">16</span></span>
<span class="sidebar-calendar__day"><span class="sidebar-calendar__day-number">17</span></span>
<span class="sidebar-calendar__day"><span class="sidebar-calendar__day-number">18</span></span>
<span class="sidebar-calendar__day"><span class="sidebar-calendar__day-number">19</span></span>
<span class="sidebar-calendar__day"><span class="sidebar-calendar__day-number">20</span></span>
<span class="sidebar-calendar__day"><span class="sidebar-calendar__day-number">21</span></span>
<span class="sidebar-calendar__day"><span class="sidebar-calendar__day-number">22</span></span>
<span class="sidebar-calendar__day"><span class="sidebar-calendar__day-number">23</span></span>
<span class="sidebar-calendar__day"><span class="sidebar-calendar__day-number">24</span></span>
<span class="sidebar-calendar__day"><span class="sidebar-calendar__day-number">25</span></span>
<span class="sidebar-calendar__day sidebar-calendar__day--focus"><span class="sidebar-calendar__day-number">26</span></span>
<span class="sidebar-calendar__day"><span class="sidebar-calendar__day-number">27</span></span>
<span class="sidebar-calendar__day"><span class="sidebar-calendar__day-number">28</span></span>
<span class="sidebar-calendar__day"><span class="sidebar-calendar__day-number">29</span></span>
<span class="sidebar-calendar__day"><span class="sidebar-calendar__day-number">30</span></span>
<span class="sidebar-calendar__day"><span class="sidebar-calendar__day-number">31</span></span>
</div>
<section class="sidebar-calendar__post-list sidebar-calendar__post-list--dynamic" data-calendar-post-list aria-live="polite" hidden></section>
</section>
O primeiro calendário foi feito apenas com Liquid, sem JavaScript.
A partir de site.posts, excluí posts ocultos e calculei o primeiro dia da semana e o último dia do mês atual. Até o cálculo de fevereiro em ano bissexto foi tratado dentro do Liquid.
Dentro do mês, os dias com posts viram links, e os dias sem posts ficam apenas como números. O primeiro critério era site.time. Ou seja, naquele momento, o calendário era um widget de sidebar que mostrava “a situação dos posts do mês atual”.
Mesmo só isso já teve efeito imediato.
Surgiu a sensação de que o blog estava se movendo de novo. Diferente de olhar apenas uma lista de títulos, o calendário mostra a densidade dos registros. Dá para perceber de uma vez em quais dias os posts se concentraram, quais dias ficaram vazios e onde está o hoje.
Também acrescentei informação de atividade às categorias
Se eu anexasse apenas o calendário, o fluxo por datas apareceria, mas o fluxo por categoria continuaria opaco.
Por isso também criei sidebar-nav-stats.html.
Esse include enxerga a URL do item da sidebar como um caminho de categoria e filtra de novo os posts que pertencem a essa categoria.
Por exemplo, se for /daily-review, ele mostra a quantidade de posts da categoria daily-review; se for /diary/ai, ele deixa apenas os posts que incluem tanto diary quanto ai.
A saída é simples.
quantidade de posts · data do post mais recente
Gostei disso porque a sidebar saiu de um simples sumário.
Dá para ver quantos textos existem em Como foi o dia de hoje?, quando o último texto de Inteligência artificial subiu e se GitHub Pages Blog está sendo operado de fato. Se o blog está morto ou vivo aparece melhor pela data recente do que pela quantidade de posts.
Ajustei imediatamente a densidade mobile
Assim que anexei o calendário, a densidade no mobile virou problema.
A sidebar tem espaço no desktop, mas no mobile ela desce para baixo do corpo do texto ou se mistura ao menu. Se as células do calendário forem grandes ou os rótulos de quantidade de posts forem longos, um widget toma espaço demais da tela.
Por isso, em 17d074d e b401d8b, reduzi logo a densidade dos rótulos de atividade da sidebar e do calendário.
17d074d fix: tighten sidebar activity labels
b401d8b [Fix] | Sidebar calendar: Improve mobile density
No SCSS, fixei as células de data com aspect-ratio: 1, usei fonte pequena e radius de 4px. As informações de atividade das categorias ficaram pequenas, em uma única linha.
Aqui, o importante era não transformar o calendário no protagonista.
O calendário é um dispositivo que ajuda a navegar pelo blog. Ele não pode ficar maior que o texto. Especialmente em um blog de registros, a sidebar deve dar informação, mas não atrapalhar a leitura.
Mudei para o mês baseado no post atual
Logo depois, apareceu um problema mais importante.
Se o calendário usa site.time como base, mesmo ao ler um post de 2025 ele mostra o calendário de maio de 2026. Assim, o calendário não explica o contexto do post atual.
Por isso, em ccb58d5, mudei a data de referência.
ccb58d5 [Fix] | Sidebar: Refine calendar behavior
O ponto central é esta parte.
Se a página tem date, ele mostra o mês dessa data. Em páginas sem data, continua usando site.time.
Com essa alteração, a natureza do calendário mudou.
O primeiro calendário era “a situação do blog neste mês”. Agora, ele mostra “o tempo em que o post que estou lendo está colocado”. Ao ler um Daily Review antigo, dá para ver o fluxo de registros daquele mês e também encontrar que outros posts existiam no mesmo mês.
Isso combina muito mais com um blog de registros centrado em datas.
Vários posts no mesmo dia foram desdobrados em lista
No mesmo commit, também anexei a lista de posts por data.
Se houver apenas um post no dia, basta fazer a data apontar para esse post. Mas, quando há vários posts no mesmo dia, surge um problema. Só no primeiro dia da retomada, por exemplo, há um Daily Review e um arquivo de conversa com IA na mesma data.
Por isso, quando uma data tem vários posts, o link da data não vai direto para um post. Ele se move para a lista de posts daquele dia.
<section id="sidebar-calendar-2026-05-25-posts" class="sidebar-calendar__post-list">
<h4 class="sidebar-calendar__post-list-title">Posts de 25 de maio</h4>
<ul>
...
</ul>
</section>
A regra nesse momento era simples.
1 post: ir para esse post
2 ou mais posts: ir para a lista de posts daquele dia
Não era uma regra perfeita, mas era uma forma de resolver imediatamente o problema de vários posts na mesma data. Ainda assim, o ponto importante é que o problema não foi escondido.
O sistema precisa reconhecer que pode haver vários posts em uma única data. Se Daily Review, conversa com IA e registro de desenvolvimento podem sair no mesmo dia, esse tratamento é necessário.
Também anexei uma JavaScript enhancement
Com apenas o calendário em Liquid, a navegação centrada no mês atual funciona, mas é incômodo transitar entre meses.
Por isso, em b06b6d6, anexei JavaScript.
b06b6d6 [Feat] | Sidebar calendar: Add archive navigation
O arquivo novo foi este.
assets/js/custom/sidebar-calendar.js
E ele foi registrado em after_footer_scripts, no _config.yml.
after_footer_scripts:
- /assets/js/custom/dark-theme.js
- /assets/js/custom/sidebar-calendar.js
No lado do Liquid, os dados dos posts são enviados como JSON.
<script type="application/json" data-calendar-posts>
[
{
"title": "...",
"url": "...",
"date": "2026-05-25"
}
]
</script>
O JavaScript lê esses dados e cria postsByDate, postCountByMonth, postCountByYear e latestPostMonthByYear. Depois renderiza botões de mês anterior/próximo, month input, botões de quantidade de posts por ano/mês e listas dinâmicas por data.
Gostei dessa estrutura porque ela não abandona o fallback.
Com JavaScript, fica confortável trocar de mês e navegar pelo arquivo. Sem JavaScript, o Liquid já renderiza o mês baseado no post atual e a lista fallback para datas com vários posts.
Em um blog estático, esse equilíbrio é importante.
O que mudou hoje
O fluxo que foi da noite até a madrugada ficou assim.
f6971fc adição do calendário da sidebar e estatísticas de atividade por categoria
17d074d ajuste de densidade dos rótulos de atividade da sidebar
b401d8b ajuste de densidade mobile do calendário da sidebar
ccb58d5 tratamento de mês baseado no post atual e lista de datas com vários posts
b06b6d6 JavaScript enhancement para navegação por arquivos mensais
Os arquivos centrais são estes.
_includes/sidebar.html
_includes/sidebar-calendar.html
_includes/sidebar-nav-stats.html
assets/js/custom/sidebar-calendar.js
_sass/custom/customOverride.scss
_config.yml
Em uma linha, o resumo é este.
Anexei à sidebar do blog uma camada de navegação que mostra datas e fluxo de atividade por categoria.
Resultado
Agora a sidebar do blog não é apenas uma lista de categorias.
Ela mostra o mês ao qual o post atual pertence, marca os dias com posts e desdobra em lista quando há vários posts no mesmo dia. Os itens de categoria mostram quantidade de posts e data do post mais recente. Com JavaScript ligado, é possível percorrer o arquivo do blog por ano e mês.
Do ponto de vista de portfólio, o ponto deste trabalho é ter aumentado a navegabilidade sem servidor.
Não há DB separado nem API. Com site.posts do Jekyll, Liquid, SCSS e um JavaScript pequeno, cobri um ponto fraco do blog estático. Registros têm datas. Quando essas datas aparecem na UI, o blog deixa de parecer um monte de textos e passa a parecer um sistema que se move no tempo.
O calendário anexado hoje é o começo disso.
Deixe um comentário