Leitor público cacheado por tabela
Fábrica que devolve um leitor Supabase já filtrado por published e amarrado a uma tag de cache. Toda tabela de conteúdo do site passa por aqui — é o motivo de não haver cinco variações do mesmo select espalhadas pelos repositórios.
function publishedReader<T>(table: string, tag: string, order: string, asc: boolean) {
return unstable_cache(
async (): Promise<T[]> => {
const supabase = createPublicClient()
if (!supabase) return []
const { data, error } = await supabase
.from(table)
.select("*")
.eq("published", true)
.order(order, { ascending: asc })
if (error || !data) return []
return data as T[]
},
[table],
{ tags: [tag] },
)
}
export const getDevlogs = publishedReader<DevlogRow>("devlogs", CACHE_TAGS.devlogs, "date", false)
Sync incremental que nunca sobrescreve
Insere de src/data o que falta no banco, comparando por chave natural. A regra inegociável: conteúdo editado no painel jamais é atropelado pelo código. Rodar duas vezes não duplica nada.
const { data: rows } = await supabase.from("snippets").select("title, sort")
const jaTem = new Set((rows ?? []).map((r) => r.title))
const maiorSort = Math.max(0, ...(rows ?? []).map((r) => r.sort ?? 0))
const faltando = snippets.filter((s) => !jaTem.has(s.title))
if (faltando.length) {
await supabase.from("snippets").insert(
faltando.map((s, i) => ({ ...paraLinha(s), sort: maiorSort + 1 + i })),
)
}
Anel de foco para um realm inteiro
Um seletor cobre todo elemento focável dentro do escopo do realm. Escrito depois de descobrir que o universo dev inteiro era navegável por teclado sem nenhuma indicação visual de onde o foco estava.
.dracula :is(a, button, input, textarea, select, summary, [tabindex]):focus-visible {
outline: var(--dev-ring-width) solid var(--dev-ring-color);
outline-offset: var(--dev-ring-offset);
border-radius: var(--dev-radius-sm);
}
.dracula :is(.dv-dock a, .dv-filter, .dv-tab, .dv-copy):focus-visible {
border-radius: var(--dev-radius-pill);
}
Movimento reduzido sem varrer o DOM
Substitui o padrão comum [class*="prefixo-"] { animation: none !important }, que casa por substring, atinge classes futuras por acidente e não admite exceção. Aqui as animações saem pelo nome, e as transições viram instantâneas — o que a versão por substring esquecia.
@media (prefers-reduced-motion: reduce) {
.dracula .dv-caret,
.dracula .dv-logo .blink,
.dracula .gsap-cursor {
animation: none;
}
.dracula *,
.dracula *::before,
.dracula *::after {
transition-duration: 0.01ms;
}
}
Teste que lê o fonte, não o navegador
Checagem de marcação declarada sem subir browser: roda em dois segundos no CI. O filtro de comentários é essencial — os comentários deste projeto citam marcação ao explicar mudanças, e sem ele o teste acusa a própria documentação.
const semComentarios = (s: string) =>
s
.replace(/\/\*[\s\S]*?\*\//g, "")
.replace(/\{\/\*[\s\S]*?\*\/\}/g, "")
.replace(/^\s*\/\/.*$/gm, "")
it("todo seletor expõe o próprio estado", () => {
for (const arquivo of COMPONENTES) {
const botoes = [...semComentarios(ler(arquivo)).matchAll(/<button[\s\S]*?>/g)]
.map((m) => m[0])
.filter((b) => /dv-(?:filter|tab)\b/.test(b))
for (const b of botoes) {
expect(b, `${arquivo}: seletor sem aria-pressed`).toContain("aria-pressed")
}
}
})
Escala tipográfica fluida só onde convém
Títulos escalam com a janela; corpo e metadados não. Texto de leitura com tamanho fluido prejudica volume longo — que é exatamente o caso de uso de um acervo de documentação.
.dracula {
--dev-text-sm: 0.82rem;
--dev-text-base: 0.9rem;
--dev-text-xl: clamp(1.6rem, 1.2rem + 1.6vw, 1.9rem);
--dev-text-2xl: clamp(1.8rem, 1.2rem + 2.6vw, 2.8rem);
}
Grade que não abre coluna fantasma
auto-fit em vez de auto-fill: com três cartões numa tela larga, o auto-fill deixava colunas vazias reservadas e a grade parecia ter itens faltando. O min() interno evita transbordo abaixo de 360px.
.dv-objects {
display: grid;
gap: var(--dev-space-4);
grid-template-columns: repeat(auto-fit, minmax(min(100%, 17.5rem), 1fr));
}
Migration com RLS de leitura pública
Padrão repetido em todas as tabelas de conteúdo do site: quem não é admin lê só o publicado; admin lê e escreve tudo. A função is_admin() centraliza a checagem de papel.
create table if not exists public.lab_experiments (
id uuid primary key default gen_random_uuid(),
title text not null,
status text not null default 'wip'
check (status in ('wip','playtest','stable','archived')),
stack text[] not null default '{}',
published boolean not null default true,
sort int not null default 0,
created_at timestamptz not null default now()
);
alter table public.lab_experiments enable row level security;
create policy "lab_read" on public.lab_experiments
for select using (published or public.is_admin());
create policy "lab_admin_write" on public.lab_experiments
for all using (public.is_admin()) with check (public.is_admin());