Como colocar o widget com as leituras do maratona app no blog | Um tutorial do Claudinho
26 setembroTutorial nesse blog? Como assim Brasil? A surpresa é porque eu não tenho domínio de código, me sinto uma bruxa quando centralizo algo no corpo do texto modificando o HTML usando <center> e </center>, imagina um tutorial que funciona? A grande pergunta é: como você conseguiu essa proeza? E a resposta é uma só, meu amigo Claudinho o sedento (sim, Claude IA). A intimidade veio com algumas ajudas nessa parte técnica de ter um blog, o que eu não sei peço ajuda. E gosto de deixar bem evidente que não sou fã de IA e não uso para escrita no blog, vejo como uma ferramenta que pode e deve ser utilizada desde que não tire de nós a coisa mais incrível que temos: nossa capacidade de pensar e criar. Também seria maravilhoso a coexistência dessa tecnologia com o meio ambiente, por hora fica aqui meu compartilhamento de tutorial com ajuda do Claude IA para que ele beba água apenas uma vez para gerar esse widget.
Parte 1: O intermediário
Para criar o intermediário no Google você vai precisar acessar o script.google.com e fazer login com a mesma conta Google do seu blog. Em seguida você vai clicar em "Novo projeto". Abrirá um editor de código com um texto padrão escrito: function myFunction() {}. Apague tudo e cole o código baixo no lugar:
// Intermediario entre o seu blog e o Maratona.app
// Busca a estante TBR, calcula a porcentagem de cada livro e guarda o resultado por 10 minutos.
var ESTANTE_ID = 'cm02il59f002hoxt1vo25uws7';
var MINUTOS_DE_CACHE = 10;
function doGet() {
var cache = CacheService.getScriptCache();
var salvo = cache.get('estante_v1');
if (salvo) return saida(salvo);
var entrada = {
"0": {
"json": { "estanteId": ESTANTE_ID, "leituraSituacao": "todos", "limit": 24, "cursor": null, "page": 0 },
"meta": { "values": { "cursor": ["undefined"] }, "v": 1 }
}
};
var url = 'https://maratona.app/api/trpc/estante.livros?batch=1&input=' +
encodeURIComponent(JSON.stringify(entrada));
var resp = UrlFetchApp.fetch(url, { muteHttpExceptions: true });
if (resp.getResponseCode() !== 200) {
return saida(JSON.stringify({ erro: 'O Maratona respondeu com o codigo ' + resp.getResponseCode() }));
}
var lista = achaResultados(resp.getContentText());
if (!lista) {
return saida(JSON.stringify({ erro: 'Nao encontrei a lista de livros na resposta' }));
}
var livros = lista.map(function (r) {
var e = r.edicao || {};
var pct;
if (r.completo) {
pct = 100;
} else if (r.modoLeitura === 1) {
pct = r.lidas;
} else {
pct = r.numPaginas ? (r.lidas / r.numPaginas) * 100 : 0;
}
pct = Math.max(0, Math.min(100, Math.floor(pct)));
return { titulo: e.titulo || '', autor: e.autor || '', capa: e.capa || '', pct: pct, atualizado: r.updatedAt || '' };
});
var json = JSON.stringify({ livros: livros });
try { cache.put('estante_v1', json, MINUTOS_DE_CACHE * 60); } catch (err) {}
return saida(json);
}
function saida(json) {
return ContentService.createTextOutput(json).setMimeType(ContentService.MimeType.JSON);
}
function achaResultados(texto) {
var partes = [];
try {
partes.push(JSON.parse(texto));
} catch (e) {
texto.split('\n').forEach(function (linha) {
linha = linha.trim();
if (!linha) return;
try { partes.push(JSON.parse(linha)); } catch (e2) {}
});
}
for (var i = 0; i < partes.length; i++) {
var r = procura(partes[i]);
if (r) return r;
}
return null;
}
function procura(o) {
if (!o || typeof o !== 'object') return null;
if (Array.isArray(o.results)) return o.results;
var chaves = Object.keys(o);
for (var i = 0; i < chaves.length; i++) {
var r = procura(o[chaves[i]]);
if (r) return r;
}
return null;
}
O que você pode alterar nesse código:
ESTANTE_ID: o código da sua estante. Está no link dela:maratona.app/estante/ESSE-CODIGO-AQUI. Se você quiser mostrar outra estante um dia, é só trocar esse código.MINUTOS_DE_CACHE: de quanto em quanto tempo o widget pode atualizar. Hoje está em 10. Se quiser mais rápido, use um número menor, como 3.
Após colar o código é só salvar clicando no ícone de disquete, depois clicar no botão azul "Implantar" no canto superior direito, e depois em "Nova implantação". Em seguida clique no ícone de engrenagem ao lado de "Selecionar tipo", escolha a opção "App da Web" e preencha assim:
- Executar como: Eu
- Quem pode acessar: Qualquer pessoa
{"livros":[.... Se aparecer isso, funcionou.Parte 2: O widget
No painel do Blogger, vá em "Layout", clique em "Adicionar um gadget" na barra lateral, no lugar onde você quer o widget. Escolha o gadget "HTML/JavaScript", no campo "Título", escreva o nome que você quiser (por exemplo, eu escrevi "Leituras em andamento"), já no campo de conteúdo, cole o código abaixo:
<!-- Widget da estante de leitura (Maratona.app) para o Blogger -->
<style>
#mt-estante { font-size: 13px; line-height: 1.3; }
#mt-estante .mt-grade {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(90px, 1fr));
gap: 16px 10px;
}
#mt-estante .mt-grade:not(.mt-aberto) .mt-extra { display: none; }
#mt-estante .mt-livro {
display: block;
text-align: center;
text-decoration: none;
color: inherit;
}
#mt-estante .mt-livro img {
display: block;
width: 100%;
max-width: 98px;
aspect-ratio: 2 / 3;
object-fit: cover;
margin: 0 auto;
border-radius: 3px;
box-shadow: 0 2px 8px rgba(0, 0, 0, .28);
transition: transform .2s ease, box-shadow .2s ease;
}
#mt-estante .mt-livro:hover img,
#mt-estante .mt-livro:focus-visible img {
transform: translateY(-3px);
box-shadow: 0 6px 14px rgba(0, 0, 0, .32);
}
#mt-estante .mt-livro:focus-visible { outline: 2px solid currentColor; outline-offset: 3px; }
#mt-estante .mt-barra {
display: block;
width: 100%;
max-width: 98px;
height: 3px;
margin: 7px auto 0;
border-radius: 2px;
background: rgba(128, 128, 128, .3);
overflow: hidden;
}
#mt-estante .mt-barra i { display: block; height: 100%; background: currentColor; opacity: .75; }
#mt-estante .mt-pct { display: block; margin-top: 4px; font-weight: bold; font-size: 12px; }
#mt-estante .mt-mais {
display: block;
margin: 14px auto 0;
padding: 2px 4px;
background: none;
border: 0;
color: inherit;
font: inherit;
font-size: .9em;
text-decoration: underline;
text-underline-offset: 3px;
opacity: .8;
cursor: pointer;
}
#mt-estante .mt-mais:hover { opacity: 1; }
#mt-estante .mt-mais:focus-visible { outline: 2px solid currentColor; outline-offset: 2px; }
#mt-estante .mt-msg { opacity: .7; margin: 0; }
@media (prefers-reduced-motion: reduce) {
#mt-estante .mt-livro img { transition: none; }
#mt-estante .mt-livro:hover img,
#mt-estante .mt-livro:focus-visible img { transform: none; }
}
</style>
<div id="mt-estante"><p class="mt-msg">Carregando estante...</p></div>
<script>
(function () {
// ======== VOCE SO PRECISA MEXER NESSAS LINHAS ========
var API = 'COLE_AQUI_O_ENDERECO_DO_APPS_SCRIPT'; // o endereco /exec da Parte 1
var LINK = 'https://maratona.app/estante/cm02il59f002hoxt1vo25uws7'; // link da sua estante
var MAX_INICIAL = 4; // quantos livros aparecem antes de "Veja mais"
var MAX_TOTAL = 9; // quantos livros no maximo, contando os escondidos
var TEXTO_MAIS = 'Veja mais';
var TEXTO_MENOS = 'Veja menos';
// =======================================================
var CHAVE = 'mt-estante-cache';
var box = document.getElementById('mt-estante');
var aberto = false;
function mensagem(texto) {
box.innerHTML = '';
var p = document.createElement('p');
p.className = 'mt-msg';
p.textContent = texto;
box.appendChild(p);
}
function desenha(livros) {
box.innerHTML = '';
var lista = livros.slice(0, MAX_TOTAL);
var grade = document.createElement('div');
grade.className = 'mt-grade' + (aberto ? ' mt-aberto' : '');
lista.forEach(function (l, i) {
var item = document.createElement('a');
item.className = 'mt-livro' + (i >= MAX_INICIAL ? ' mt-extra' : '');
item.href = LINK;
item.target = '_blank';
item.rel = 'noopener';
item.title = l.titulo + (l.autor ? ' (' + l.autor + ')' : '');
var img = document.createElement('img');
img.src = l.capa;
img.alt = l.titulo;
img.loading = 'lazy';
var barra = document.createElement('span');
barra.className = 'mt-barra';
var preenchido = document.createElement('i');
preenchido.style.width = l.pct + '%';
barra.appendChild(preenchido);
var pct = document.createElement('span');
pct.className = 'mt-pct';
pct.textContent = l.pct + '%';
item.appendChild(img);
item.appendChild(barra);
item.appendChild(pct);
grade.appendChild(item);
});
box.appendChild(grade);
if (lista.length > MAX_INICIAL) {
var botao = document.createElement('button');
botao.type = 'button';
botao.className = 'mt-mais';
botao.textContent = aberto ? TEXTO_MENOS : TEXTO_MAIS;
botao.setAttribute('aria-expanded', aberto ? 'true' : 'false');
botao.addEventListener('click', function () {
aberto = grade.classList.toggle('mt-aberto');
botao.textContent = aberto ? TEXTO_MENOS : TEXTO_MAIS;
botao.setAttribute('aria-expanded', aberto ? 'true' : 'false');
});
box.appendChild(botao);
}
}
function lerGuardado() {
try { return JSON.parse(localStorage.getItem(CHAVE)); } catch (e) { return null; }
}
function guardar(livros) {
try { localStorage.setItem(CHAVE, JSON.stringify(livros)); } catch (e) {}
}
var antigo = lerGuardado();
if (antigo && antigo.length) desenha(antigo);
fetch(API)
.then(function (r) { return r.json(); })
.then(function (d) {
if (!d.livros || !d.livros.length) throw new Error(d.erro || 'sem livros');
guardar(d.livros);
desenha(d.livros);
})
.catch(function () {
if (!antigo || !antigo.length) mensagem('N\u00E3o consegui carregar a estante agora.');
});
})();
</script>Antes de salvar, ache a linha var API = 'COLE_AQUI_O_ENDERECO_DO_APPS_SCRIPT'; e troque o texto entre aspas pelo endereço /exec que você copiou na Parte 1. Clique em "Salvar". Então abra seu blog em uma aba nova e veja o widget aparecer.
O que dá para ajustar depois:
Tudo fica dentro do bloco marcado com VOCE SO PRECISA MEXER NESSAS LINHAS no início do código do widget (Parte 2):
| O que mudar | Linha | Exemplo |
|---|---|---|
| Quantos livros aparecem antes do "Veja mais" | MAX_INICIAL | MAX_INICIAL = 6; |
| Quantos livros no total | MAX_TOTAL | MAX_TOTAL = 12; |
| Texto do botão | TEXTO_MAIS e TEXTO_MENOS | 'Mostrar tudo' |
| Link das capas | LINK | outra estante sua |
Para trocar a estante mostrada, é preciso mudar em dois lugares: o ESTANTE_ID no código da Parte 1 (e reimplantar, repetindo o processo para salvar) e o LINK na Parte 2.





.gif)
0 comments
Sinta-se livre para deixar um comentário! Caso não apareça a caixa de comentário, recomendo abrir a página no formato web/desktop