mirror of
https://github.com/fsolla/teqo.git
synced 2026-11-12 22:13:05 +00:00
docs(plan): C166 + C167 + C168 — compartilhar trechos do acervo (link, corte e biblioteca) (Related #1013, #1014, #1015)
This commit is contained in:
parent
fc6846ebea
commit
5097e8cb90
6 changed files with 1984 additions and 0 deletions
386
docs/plans/c166-compartilhar-trecho-link-ui-draft.html
Normal file
386
docs/plans/c166-compartilhar-trecho-link-ui-draft.html
Normal file
|
|
@ -0,0 +1,386 @@
|
|||
<!doctype html>
|
||||
<html lang="pt-BR">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>
|
||||
<title>UI draft — C166: selecionar trecho e compartilhar por link</title>
|
||||
</head>
|
||||
<body class="bg-zinc-950 text-zinc-100 antialiased">
|
||||
<main class="mx-auto max-w-5xl p-6 sm:p-8">
|
||||
<h1 class="text-lg font-medium">
|
||||
UI draft — Acervo: selecionar trecho e compartilhar por link (C166)
|
||||
</h1>
|
||||
<p class="mt-1 text-sm text-zinc-400">
|
||||
A assessoria de comunicação marca um trecho da fala no player e manda o link do YouTube já
|
||||
abrindo no ponto escolhido (copiar ou WhatsApp), com o intervalo escrito na mensagem.
|
||||
</p>
|
||||
<p class="mt-2 text-sm text-zinc-500">
|
||||
Cinza = estrutura existente · <span class="text-amber-400">acento</span> = novo neste item ·
|
||||
barras cinza = conteúdo não especificado. Cenas estáticas: sem interação, sem dados reais.
|
||||
</p>
|
||||
|
||||
<!-- Cena 1 · desktop — detalhe com a barra de seleção de trecho -->
|
||||
<section class="mt-8">
|
||||
<p class="text-xs tracking-wide text-zinc-500 uppercase">
|
||||
Cena 1 · desktop (~1280px) — detalhe com barra de seleção (alças início/fim, duração) +
|
||||
Compartilhar
|
||||
</p>
|
||||
<div class="mt-3 overflow-hidden rounded-lg border border-zinc-800 bg-zinc-900">
|
||||
<div class="px-6 py-5">
|
||||
<p class="text-xs text-zinc-500">← Voltar ao acervo</p>
|
||||
<h2 class="mt-2 text-base font-medium">BREVES COMUNICAÇÕES</h2>
|
||||
<p class="mt-1 text-xs text-zinc-500">
|
||||
11/08/2026 · 18:48 · 4min25s · Presidiu: [placeholder]
|
||||
</p>
|
||||
|
||||
<div class="mt-4 grid grid-cols-[1fr_240px] gap-5">
|
||||
<div>
|
||||
<div
|
||||
class="relative flex aspect-video items-center justify-center rounded-lg border border-zinc-800 bg-zinc-950"
|
||||
>
|
||||
<div
|
||||
class="flex h-12 w-12 items-center justify-center rounded-full bg-zinc-800 text-zinc-300"
|
||||
>
|
||||
▶
|
||||
</div>
|
||||
<p class="absolute bottom-3 left-3 text-xs text-zinc-400">
|
||||
Vídeo da sessão no YouTube
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="mt-3 rounded-lg border border-zinc-800 bg-zinc-950 p-3">
|
||||
<div class="flex flex-wrap items-center justify-between gap-2">
|
||||
<span class="text-xs font-medium text-amber-400">
|
||||
Selecionar trecho — ativo
|
||||
</span>
|
||||
<span class="text-xs text-zinc-400">
|
||||
Trecho:
|
||||
<span class="text-zinc-100 tabular-nums">00:43 → 02:10</span>
|
||||
·
|
||||
<span class="text-zinc-100 tabular-nums">1min27s</span>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="relative mt-4 h-9">
|
||||
<div
|
||||
class="absolute inset-x-0 top-1/2 h-1.5 -translate-y-1/2 rounded bg-zinc-800"
|
||||
></div>
|
||||
<div
|
||||
class="absolute top-1/2 left-[18%] right-[26%] h-1.5 -translate-y-1/2 rounded bg-amber-500/70"
|
||||
></div>
|
||||
<div
|
||||
class="absolute top-1/2 left-[18%] h-6 w-2.5 -translate-x-1/2 -translate-y-1/2 rounded-sm border border-amber-400 bg-zinc-900"
|
||||
></div>
|
||||
<div
|
||||
class="absolute top-1/2 right-[26%] h-6 w-2.5 translate-x-1/2 -translate-y-1/2 rounded-sm border border-amber-400 bg-zinc-900"
|
||||
></div>
|
||||
<span
|
||||
class="absolute -top-0.5 left-[18%] -translate-x-1/2 text-[10px] text-amber-400"
|
||||
>
|
||||
início
|
||||
</span>
|
||||
<span
|
||||
class="absolute -top-0.5 right-[26%] translate-x-1/2 text-[10px] text-amber-400"
|
||||
>
|
||||
fim
|
||||
</span>
|
||||
</div>
|
||||
<div class="mt-2 flex justify-between text-[10px] text-zinc-500">
|
||||
<span>00:00</span>
|
||||
<span class="text-amber-400">00:43</span>
|
||||
<span>02:10</span>
|
||||
<span>04:25</span>
|
||||
</div>
|
||||
<p class="mt-3 text-[11px] text-zinc-500">
|
||||
Clique nas frases: o limite encaixa no segmento (ímã). Arraste as alças para o
|
||||
ajuste fino. Mínimo 5s · máximo 3min — a duração aparece durante a seleção.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="mt-3 flex flex-wrap items-center gap-2">
|
||||
<button
|
||||
class="min-h-11 rounded-lg bg-amber-500 px-4 text-sm font-medium text-zinc-950"
|
||||
>
|
||||
Compartilhar
|
||||
</button>
|
||||
<button
|
||||
class="min-h-11 rounded-lg border border-zinc-700 px-4 text-sm text-zinc-300"
|
||||
>
|
||||
Baixar vídeo (MP4)
|
||||
</button>
|
||||
<button
|
||||
class="min-h-11 rounded-lg border border-zinc-700 px-4 text-sm text-zinc-300"
|
||||
>
|
||||
Abrir fonte
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<p class="mt-5 text-xs tracking-wide text-zinc-500 uppercase">
|
||||
Transcrição (clique nas frases para marcar o trecho)
|
||||
</p>
|
||||
<div class="mt-2 space-y-1">
|
||||
<div class="flex gap-3 rounded-lg px-2 py-1.5">
|
||||
<span class="w-12 shrink-0 text-xs text-zinc-500">00:00</span>
|
||||
<span class="text-sm text-zinc-400">… agradeço, Presidente. …</span>
|
||||
</div>
|
||||
<div
|
||||
class="flex gap-3 rounded-lg border-l-2 border-amber-500/60 bg-amber-500/10 px-2 py-1.5"
|
||||
>
|
||||
<span class="w-12 shrink-0 text-xs text-amber-400">00:43</span>
|
||||
<span class="text-sm text-zinc-100"
|
||||
>… o acesso a medicamentos na Bahia precisa chegar a quem mora no interior
|
||||
…</span
|
||||
>
|
||||
</div>
|
||||
<div
|
||||
class="flex gap-3 rounded-lg border-l-2 border-amber-500/60 bg-amber-500/10 px-2 py-1.5"
|
||||
>
|
||||
<span class="w-12 shrink-0 text-xs text-amber-400">02:10</span>
|
||||
<span class="text-sm text-zinc-100"
|
||||
>… e é preciso garantir o financiamento tripartite …</span
|
||||
>
|
||||
</div>
|
||||
<div class="flex gap-3 rounded-lg px-2 py-1.5">
|
||||
<span class="w-12 shrink-0 text-xs text-zinc-500">03:31</span>
|
||||
<span class="text-sm text-zinc-400">… muito obrigado, Presidente. …</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<aside class="space-y-4">
|
||||
<div>
|
||||
<p class="text-xs tracking-wide text-zinc-500 uppercase">Sumário oficial</p>
|
||||
<div class="mt-2 space-y-1.5">
|
||||
<div class="h-3 w-full rounded bg-zinc-800"></div>
|
||||
<div class="h-3 w-5/6 rounded bg-zinc-800"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<p class="text-xs tracking-wide text-zinc-500 uppercase">Temas</p>
|
||||
<div class="mt-1.5 flex flex-wrap gap-1.5">
|
||||
<span class="rounded-full bg-zinc-800 px-2 py-0.5 text-xs text-zinc-300"
|
||||
>Saúde</span
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<div class="border-t border-zinc-800 pt-3">
|
||||
<p class="text-xs text-zinc-500">Fonte: Câmara dos Deputados · CC BY 4.0</p>
|
||||
</div>
|
||||
</aside>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Cena 2 · desktop — popover aberto, estado "Link copiado" -->
|
||||
<section class="mt-8">
|
||||
<p class="text-xs tracking-wide text-zinc-500 uppercase">
|
||||
Cena 2 · popover de compartilhamento aberto — "Copiar link" (estado "Link copiado") e
|
||||
"Enviar no WhatsApp"
|
||||
</p>
|
||||
<div class="mt-3 rounded-lg border border-zinc-800 bg-zinc-900 px-6 py-5">
|
||||
<div class="max-w-[720px]">
|
||||
<p class="text-xs text-zinc-500">BREVES COMUNICAÇÕES · trecho 00:43 → 02:10</p>
|
||||
<div class="mt-2 flex flex-wrap items-center gap-2">
|
||||
<button
|
||||
class="min-h-11 rounded-lg bg-amber-500 px-4 text-sm font-medium text-zinc-950"
|
||||
>
|
||||
Compartilhar
|
||||
</button>
|
||||
<button class="min-h-11 rounded-lg border border-zinc-700 px-4 text-sm text-zinc-300">
|
||||
Baixar vídeo (MP4)
|
||||
</button>
|
||||
<button class="min-h-11 rounded-lg border border-zinc-700 px-4 text-sm text-zinc-300">
|
||||
Abrir fonte
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="mt-2 w-80 rounded-lg border border-zinc-700 bg-zinc-900 p-1">
|
||||
<div class="flex min-h-11 items-center gap-2 rounded-md px-2 text-sm text-zinc-100">
|
||||
<span class="text-amber-400">✓</span>
|
||||
Link copiado
|
||||
</div>
|
||||
<div class="flex min-h-11 items-center gap-2 rounded-md px-2 text-sm text-zinc-100">
|
||||
<span class="text-zinc-500">→</span>
|
||||
Enviar no WhatsApp
|
||||
</div>
|
||||
<p
|
||||
class="border-t border-zinc-800 px-2 py-2 text-[11px] leading-relaxed text-zinc-500"
|
||||
>
|
||||
Trecho de BREVES COMUNICAÇÕES (11/08/2026): de 00:43 a 02:10<br />
|
||||
youtube.com/watch?v=[id]&t=2634
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<p class="mt-3 text-xs text-zinc-500">
|
||||
Antes do clique a primeira opção lê "Copiar link"; o feedback volta sozinho depois de
|
||||
alguns segundos. O link abre o vídeo em 00:43 da fala (2634s na sessão); o fim vai
|
||||
escrito na mensagem.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Cena 3 · desktop — fala sem YouTube: link indisponível + aviso honesto -->
|
||||
<section class="mt-8">
|
||||
<p class="text-xs tracking-wide text-zinc-500 uppercase">
|
||||
Cena 3 · fala sem YouTube (só VOD) — sem opção de link + aviso honesto (seleção
|
||||
preservada)
|
||||
</p>
|
||||
<div class="mt-3 overflow-hidden rounded-lg border border-zinc-800 bg-zinc-900">
|
||||
<div class="px-6 py-5">
|
||||
<p class="text-xs text-zinc-500">← Voltar ao acervo</p>
|
||||
<h2 class="mt-2 text-base font-medium">BREVES COMUNICAÇÕES</h2>
|
||||
<p class="mt-1 text-xs text-zinc-500">11/08/2026 · 4min25s · só VOD (sem YouTube)</p>
|
||||
|
||||
<div class="mt-4 max-w-[720px]">
|
||||
<div
|
||||
class="flex aspect-video flex-col items-center justify-center gap-2 rounded-lg border border-zinc-800 bg-zinc-950 text-center"
|
||||
>
|
||||
<div
|
||||
class="flex h-12 w-12 items-center justify-center rounded-full bg-zinc-800 text-zinc-300"
|
||||
>
|
||||
▶
|
||||
</div>
|
||||
<p class="text-sm text-zinc-200">Assistir o trecho</p>
|
||||
<p class="max-w-sm text-xs text-zinc-500">
|
||||
O trecho deste vídeo é gerado pela Câmara dos Deputados.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="mt-3 flex flex-wrap items-center gap-2">
|
||||
<button
|
||||
class="min-h-11 rounded-lg bg-amber-500 px-4 text-sm font-medium text-zinc-950"
|
||||
>
|
||||
Baixar vídeo (MP4)
|
||||
</button>
|
||||
<button
|
||||
class="min-h-11 rounded-lg border border-zinc-700 px-4 text-sm text-zinc-300"
|
||||
>
|
||||
Abrir fonte
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="mt-3 rounded-lg border border-zinc-800 bg-zinc-950 px-4 py-3">
|
||||
<p class="text-xs font-medium text-zinc-300">
|
||||
Compartilhar por link exige o vídeo no YouTube
|
||||
</p>
|
||||
<p class="mt-1 text-xs text-zinc-500">
|
||||
Esta fala não tem vídeo no YouTube — não há link externo que abra no ponto. Você
|
||||
ainda pode baixar o MP4 ou abrir a fonte oficial, e a seleção de trecho continua
|
||||
disponível.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="mt-5 text-xs tracking-wide text-zinc-500 uppercase">Transcrição</p>
|
||||
<div class="mt-2 max-w-[720px] space-y-1">
|
||||
<div class="flex gap-3 rounded-lg px-2 py-1.5">
|
||||
<span class="w-12 shrink-0 text-xs text-zinc-500">00:00</span>
|
||||
<span class="text-sm text-zinc-400">… agradeço, Presidente. …</span>
|
||||
</div>
|
||||
<div class="flex gap-3 rounded-lg px-2 py-1.5">
|
||||
<span class="w-12 shrink-0 text-xs text-zinc-500">00:43</span>
|
||||
<span class="text-sm text-zinc-400">… o acesso a medicamentos na Bahia …</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="mt-4 border-t border-zinc-800 pt-3 text-xs text-zinc-500">
|
||||
Fonte: Câmara dos Deputados · CC BY 4.0
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Cena 4 · mobile — seleção + sheet de compartilhamento -->
|
||||
<section class="mt-8">
|
||||
<p class="text-xs tracking-wide text-zinc-500 uppercase">
|
||||
Cena 4 · mobile (~390px) — seleção + sheet de compartilhamento aberto
|
||||
</p>
|
||||
<div class="mt-3 w-[390px] overflow-hidden rounded-lg border border-zinc-800 bg-zinc-900">
|
||||
<div class="flex items-center justify-between border-b border-zinc-800 px-4 py-3">
|
||||
<span class="text-zinc-400">←</span>
|
||||
<span class="text-sm font-medium text-zinc-200">Comunicação</span>
|
||||
<span class="h-6 w-6 rounded-full bg-zinc-800"></span>
|
||||
</div>
|
||||
|
||||
<div class="relative">
|
||||
<div class="px-4 py-4 opacity-60">
|
||||
<p class="text-xs text-zinc-500">Acervo · fala</p>
|
||||
<h2 class="mt-1 text-sm font-medium text-zinc-100">BREVES COMUNICAÇÕES</h2>
|
||||
<div
|
||||
class="mt-3 flex aspect-video items-center justify-center rounded-lg border border-zinc-800 bg-zinc-950"
|
||||
>
|
||||
<div
|
||||
class="flex h-10 w-10 items-center justify-center rounded-full bg-zinc-800 text-zinc-300"
|
||||
>
|
||||
▶
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-3 rounded-lg border border-zinc-800 bg-zinc-950 p-3">
|
||||
<div class="flex items-center justify-between text-xs">
|
||||
<span class="font-medium text-amber-400">Trecho selecionado</span>
|
||||
<span class="text-zinc-100 tabular-nums">00:43 → 02:10</span>
|
||||
</div>
|
||||
<div class="relative mt-3 h-8">
|
||||
<div
|
||||
class="absolute inset-x-0 top-1/2 h-1.5 -translate-y-1/2 rounded bg-zinc-800"
|
||||
></div>
|
||||
<div
|
||||
class="absolute top-1/2 left-[18%] right-[26%] h-1.5 -translate-y-1/2 rounded bg-amber-500/70"
|
||||
></div>
|
||||
<div
|
||||
class="absolute top-1/2 left-[18%] h-6 w-2.5 -translate-x-1/2 -translate-y-1/2 rounded-sm border border-amber-400 bg-zinc-900"
|
||||
></div>
|
||||
<div
|
||||
class="absolute top-1/2 right-[26%] h-6 w-2.5 translate-x-1/2 -translate-y-1/2 rounded-sm border border-amber-400 bg-zinc-900"
|
||||
></div>
|
||||
</div>
|
||||
<p class="mt-2 text-[10px] text-zinc-500">
|
||||
início 00:43 · fim 02:10 · 1min27s · mínimo 5s · máximo 3min
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<button
|
||||
class="mt-3 h-11 w-full rounded-lg bg-amber-500 text-sm font-medium text-zinc-950"
|
||||
>
|
||||
Compartilhar
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="absolute inset-x-0 bottom-0 rounded-t-2xl border-t border-zinc-700 bg-zinc-900 px-4 pt-3 pb-4"
|
||||
>
|
||||
<div class="mx-auto h-1 w-10 rounded bg-zinc-700"></div>
|
||||
<p class="mt-3 text-sm font-medium text-zinc-100">Compartilhar trecho</p>
|
||||
<p class="mt-1 text-xs text-zinc-500">O link abre o vídeo no ponto escolhido.</p>
|
||||
<div class="mt-2">
|
||||
<div class="flex min-h-11 items-center gap-2 rounded-md px-2 text-sm text-zinc-100">
|
||||
<span class="text-amber-400">✓</span>
|
||||
Link copiado
|
||||
</div>
|
||||
<div class="flex min-h-11 items-center gap-2 rounded-md px-2 text-sm text-zinc-100">
|
||||
<span class="text-zinc-500">→</span>
|
||||
Enviar no WhatsApp
|
||||
</div>
|
||||
</div>
|
||||
<p
|
||||
class="mt-1 border-t border-zinc-800 px-2 pt-2 text-[10px] leading-relaxed text-zinc-500"
|
||||
>
|
||||
Trecho de BREVES COMUNICAÇÕES (11/08/2026): de 00:43 a 02:10<br />
|
||||
youtube.com/watch?v=[id]&t=2634
|
||||
</p>
|
||||
<button
|
||||
class="mt-2 h-11 w-full rounded-lg border border-zinc-700 text-sm text-zinc-300"
|
||||
>
|
||||
Fechar
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
105
docs/plans/c166-compartilhar-trecho-link.md
Normal file
105
docs/plans/c166-compartilhar-trecho-link.md
Normal file
|
|
@ -0,0 +1,105 @@
|
|||
# Acervo: selecionar trecho e compartilhar por link (YouTube no ponto + WhatsApp)
|
||||
|
||||
Status: rascunho
|
||||
Atualizado em: 2026-09-15
|
||||
Issue: #1013
|
||||
Priority: P1
|
||||
Impeccable: B — encaixe no detalhe do acervo (player + compartilhar)
|
||||
Rascunho UI: docs/plans/c166-compartilhar-trecho-link-ui-draft.html
|
||||
Appetite: ~1–1,5 dia eng; um outcome verificável — quem recebe o link abre o YouTube já no ponto do trecho, e o intervalo vai na mensagem
|
||||
Responsável: —
|
||||
|
||||
## Intenção
|
||||
|
||||
O acervo já deixa achar a fala e assistir no ponto (C154/C162), mas transformar um intervalo exato em algo que circula ainda dá trabalho manual: baixar o MP4, cortar fora da ferramenta, subir em algum lugar. Na comunicação da campanha, o que circula de verdade é link no WhatsApp. Esta fatia fecha o gesto: marcar [início, fim] no player (ímã nas frases, limites de 5 s a 180 s, duração visível) e compartilhar o link do YouTube já abrindo no ponto escolhido — copiando ou mandando no WhatsApp com o intervalo escrito na mensagem. Sem cortar arquivo e sem publicar página: isso é C167/C168.
|
||||
|
||||
## Persona e fluxo
|
||||
|
||||
- **Persona / contexto:** assessoria de comunicação (communicator; coordenação e candidatura também), no escritório ou em campo, com peça no prazo curto, muitas vezes no celular.
|
||||
- **Job principal:** transformar um trecho exato da fala num link que abre no ponto e mandá-lo no WhatsApp em segundos, sem baixar nem editar vídeo.
|
||||
- **Fluxo desejado:** abre a fala → ativa "Selecionar trecho" → marca início/fim clicando nas frases (ímã) e ajusta fino nas alças (5 s–180 s; a duração aparece enquanto seleciona) → "Compartilhar" → escolhe "Copiar link" (feedback "Link copiado") ou "Enviar no WhatsApp" (abre o WhatsApp do remetente com o texto pronto) → quem recebe abre o YouTube já no trecho e lê o intervalo na mensagem.
|
||||
- **Anti-goals de produto:** não é editor de vídeo nem corte/export (C167); não é página pública do trecho (C167) nem biblioteca de cortes (C168); não é segundo player; sem telemetria de compartilhamento; nunca expor o acervo autenticado para fora; sem escrita no servidor, sem `Consent`/collection novos.
|
||||
|
||||
### Esboço de fluxo (B/C/D)
|
||||
|
||||
```text
|
||||
[fala com YouTube] → "Selecionar trecho" → clique nas frases (ímã) + alças (5s…3min, duração visível)
|
||||
→ "Compartilhar" → [Copiar link | Enviar no WhatsApp] → [recebe abre o YouTube no ponto; mensagem traz o intervalo]
|
||||
[fala sem YouTube] → seleção continua disponível (porta do corte no C167); sem opção de link + aviso honesto; MP4/fonte seguem
|
||||
```
|
||||
|
||||
### Rascunho UI (B/C/D)
|
||||
|
||||
- Rascunho UI (gate): `docs/plans/c166-compartilhar-trecho-link-ui-draft.html` — cenas: detalhe com barra de seleção (alças/duração/mm:ss) + Compartilhar; popover com "Copiar link" (estado "Copiado") e "Enviar no WhatsApp"; fala sem YouTube (link indisponível + aviso honesto, seleção preservada); mobile com seleção + sheet.
|
||||
|
||||
## Objetivo e aceite
|
||||
|
||||
- Com YouTube: marcar [início, fim] no player com ímã nos limites dos segmentos e ajuste fino; mínimo 5 s, máximo 180 s; duração e `mm:ss` visíveis durante a seleção.
|
||||
- "Compartilhar" oferece exatamente duas opções: "Copiar link" (com feedback "Link copiado") e "Enviar no WhatsApp" (`wa.me` do remetente, sem destinatário).
|
||||
- O link é `https://www.youtube.com/watch?v=<id>&t=<segundos>`, com `t` = offset da sessão + início do trecho; abre já no ponto. O fim não cabe no link — o intervalo vai na mensagem.
|
||||
- Sem YouTube (só VOD ou sem vídeo): a opção de link não é oferecida — aviso honesto de que compartilhar por link exige YouTube; a seleção continua disponível (é a porta do corte de arquivo no C167) e MP4/fonte continuam.
|
||||
- Guardrails: nada de link autenticado do acervo para fora; sem escrita no servidor/`Consent`/collection; `advisor` e `leader` seguem negados; crédito "Fonte: Câmara dos Deputados · CC BY 4.0" e o clique-para-posicionar do C162 ficam intactos.
|
||||
|
||||
## Dados (intenção)
|
||||
|
||||
- **Vou apresentar dados?** Não — a superfície é seleção + compartilhamento; duração/`mm:ss` é feedback de ação, não dado do acervo.
|
||||
- **Decisões desbloqueadas:** a assessoria decide qual intervalo circula e por qual canal (link no ponto ou WhatsApp); quem recebe decide assistir no ponto.
|
||||
- **Forma:** _adiada ao plano de implementação_ — restrição: sem KPI/telemetria de compartilhamento nesta fatia.
|
||||
|
||||
## Dados da decisão (literais)
|
||||
|
||||
- Link compartilhado (fala com YouTube): `https://www.youtube.com/watch?v=<id>&t=<segundos>`; `t=` = offset da sessão + início do trecho em segundos (inteiro), a mesma conta do posicionamento do player; o fim NÃO é codificável no link do YouTube.
|
||||
- Deep link WhatsApp sem destinatário: `https://wa.me/?text=<texto>` (padrão do repo de `wa.me/?text` + copiar com feedback "copiado").
|
||||
- Texto da mensagem: `Trecho de <tipo do discurso> (<data>): de <mm:ss> a <mm:ss>` + URL; ex.: `Trecho de BREVES COMUNICAÇÕES (11/08/2026): de 00:43 a 02:10 https://www.youtube.com/watch?v=<id>&t=2634`.
|
||||
- Limites do trecho: mínimo 5 s, máximo 180 s; duração visível durante a seleção; alças com ímã nos limites dos segmentos e ajuste fino permitido.
|
||||
- Rótulos das ações: "Compartilhar" (opções "Copiar link" e "Enviar no WhatsApp"); feedback "Link copiado".
|
||||
- Fala sem YouTube: nenhuma opção de link; aviso honesto de que o compartilhamento por link exige YouTube; a seleção permanece (porta do corte do C167); nunca compartilhar link autenticado do acervo.
|
||||
- Sem escrita no servidor; sem `Consent`; sem segunda superfície de player; `advisor`/`leader` permanecem negados.
|
||||
|
||||
## Direção no codebase (hipótese)
|
||||
|
||||
- **Áreas prováveis:** `src/components/campaign/speech/` (controle de seleção + compartilhar no detalhe), `src/utilities/speech/` (rótulos/segmentos já no view model) e `src/lib/` (montagem pura de link/mensagem).
|
||||
- **Precedente a olhar:** `src/lib/contentShare.ts` + `src/components/ContentShareButton.tsx` (popover + copiar com feedback), `src/lib/phone.ts` (`buildWhatsAppTextShareUrl` = `wa.me/?text=`), `docs/plans/compartilhar-pagina.md` ("compartilhar não concede acesso", sem server action), C162 em `speechViewModels.ts` (`youtubeVideoId`/`youtubeOffsetSeconds`, segmentos com início/fim).
|
||||
- **Risco de acoplamento:** o clique na transcrição hoje posiciona o vídeo (contrato C162 pinado em unit/e2e) — a seleção precisa de modo explícito para não regredir; o e2e `campaignSpeechAcervo` e o manifesto de áreas tocadas cobrem `src/components/campaign/speech`/`src/utilities/speech`/`src/lib/speech*`.
|
||||
|
||||
## Dependências
|
||||
|
||||
- Entregues (duras, satisfeitas): C154/C155 (acervo em produção) e C162 (player com YouTube default + offset). Nenhuma dependência aberta.
|
||||
|
||||
## Fora de escopo
|
||||
|
||||
- Cortar/gerar arquivo do trecho (clip/export) e download do clip — C167.
|
||||
- Página pública do trecho com preview/OG e biblioteca de cortes — C167/C168.
|
||||
- Compartilhar a partir da lista (só o detalhe nesta fatia).
|
||||
- Telemetria/UTM, contagem de compartilhamentos e analytics de clique.
|
||||
- Legendas, marca d'água, thumbnail e encurtador/tracker de link.
|
||||
- Outros canais (X, Telegram, e-mail) — só WhatsApp + copiar link.
|
||||
- Escrita no servidor, `Consent`, collection/migration novas; ampliar papéis com acesso.
|
||||
|
||||
## Rabbit holes de produto
|
||||
|
||||
- **Virar editor de vídeo.** Se alguém "só completar": trim, preview renderizado, export, fila de render. **Corte neste item:** só [início,fim] + link; nenhum arquivo novo.
|
||||
- **Página pública do trecho "para o link abrir bonito".** Se alguém "só completar": rota pública, OG, hospedagem, moderação. **Corte neste item:** o link é do YouTube; C167 é outro item.
|
||||
- **Encurtador/tracker para medir circulação.** Se alguém "só completar": serviço externo, redirect, privacidade. **Corte neste item:** URL canônica do YouTube; medição é item futuro explícito.
|
||||
- **Precisão de frame / timeline com zoom.** Se alguém "só completar": snapping complexo e segundo quebrado. **Corte neste item:** segundos inteiros, ímã de frase, alças simples.
|
||||
- **Segundo player para pré-visualizar o corte.** Se alguém "só completar": duas superfícies de vídeo. **Corte neste item:** a seleção vive no player existente.
|
||||
|
||||
## Questões em aberto (produto)
|
||||
|
||||
- **Fala sem YouTube?** **Opções:** A) esconder a opção de link com aviso honesto, mantendo a seleção para o corte | B) copiar link autenticado do acervo. **Recomendação:** A — B nunca funciona para quem recebe (rota autenticada) e vaza uma URL interna. _(assumido — validar no gate)_
|
||||
- **Padrão da seleção?** **Opções:** A) marcar por clique em segmentos inteiros e ajustar com alças | B) só alças livres. **Recomendação:** A com ímã — a frase é a unidade de sentido do discurso; alças livres erram por segundos. _(decidido — A, com ajuste fino permitido)_
|
||||
- **Botão?** **Opções:** A) um "Compartilhar" com as duas opções | B) dois botões separados. **Recomendação:** A (pedido do dono: botão com opções); B duplica CTA numa barra já densa. _(decidido — A)_
|
||||
- **Clique na transcrição durante a seleção?** **Opções:** A) modo explícito "Selecionar trecho" (fora dele o clique segue posicionando) | B) clicar-e-arrastar sempre. **Recomendação:** A — preserva o contrato C162 e não surpreende quem só quer ouvir. _(assumido)_
|
||||
- **YouTube com offset desconhecido?** **Opções:** A) oferecer link sem `t=` com aviso de que abre no início da sessão | B) não oferecer link. **Recomendação:** A — o link é utilizável; nunca inventar `t=` errado. _(assumido)_
|
||||
|
||||
## Referências
|
||||
|
||||
- GitHub Issue: — (após `pnpm agent:register`)
|
||||
- Rascunho UI (gate): `docs/plans/c166-compartilhar-trecho-link-ui-draft.html`
|
||||
- Planos irmãos: [`acervo-vod-sob-demanda.md`](acervo-vod-sob-demanda.md) (C162), [`compartilhar-conteudos-home-whatsapp.md`](compartilhar-conteudos-home-whatsapp.md), [`compartilhar-pagina.md`](compartilhar-pagina.md)
|
||||
- Arquivos-chave (pista, não contrato): `src/components/campaign/speech/SpeechDetailPlayer.tsx`, `src/utilities/speech/speechViewModels.ts`, `src/lib/contentShare.ts`, `src/lib/phone.ts`, `tests/e2e/campaignSpeechAcervo.e2e.spec.ts`
|
||||
- `AGENTS.md` — vertical Comunicação, lockdown de papéis e crédito CC BY.
|
||||
|
||||
## Self-score (shaping)
|
||||
|
||||
5/5 — (1) fatia = um outcome verificável (quem recebe abre o YouTube no ponto; o intervalo vai na mensagem) sem cortar arquivo nem publicar página; (2) appetite de ~1–1,5 dia para seleção + compartilhamento sem schema; (3) persona, job e aceite legíveis sem jargão, com as decisões literais separadas; (4) direção no codebase é hipótese com precedentes abertos e o alerta do contrato C162; (5) zero decisão dura de engenharia — nomes, rotas e schema ficam para a implementação.
|
||||
579
docs/plans/c167-cortar-trecho-publicar-ui-draft.html
Normal file
579
docs/plans/c167-cortar-trecho-publicar-ui-draft.html
Normal file
|
|
@ -0,0 +1,579 @@
|
|||
<!doctype html>
|
||||
<html lang="pt-BR">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>
|
||||
<title>UI draft — C167 · Cortar o trecho e publicar o corte</title>
|
||||
</head>
|
||||
<body class="bg-zinc-950 text-zinc-100 antialiased">
|
||||
<main class="mx-auto max-w-[1400px] p-6 sm:p-8">
|
||||
<h1 class="text-lg font-medium text-zinc-100">
|
||||
UI draft — Acervo: cortar o trecho [início,fim] e publicar o arquivo numa página
|
||||
compartilhável (C167)
|
||||
</h1>
|
||||
<p class="mt-1 max-w-3xl text-sm text-zinc-400">
|
||||
A assessoria seleciona o trecho (C166), confirma o corte com título/descrição sugeridos por
|
||||
IA, o servidor gera o MP4 exato [início,fim] e publica uma página unlisted com player; o
|
||||
compartilhamento é por link (preview no WhatsApp) ou baixando o arquivo.
|
||||
</p>
|
||||
<p class="mt-2 text-sm text-zinc-500">
|
||||
Cinza = estrutura existente · <span class="text-amber-400">acento</span> = novo neste item ·
|
||||
barras cinza = conteúdo não especificado. Cenas estáticas: sem interação, sem dados reais.
|
||||
</p>
|
||||
|
||||
<!-- ============================================================ -->
|
||||
<!-- Cena 1 · desktop (~1280px) — detalhe do acervo + formulário -->
|
||||
<!-- ============================================================ -->
|
||||
<section class="mt-8">
|
||||
<p class="text-xs tracking-wide text-zinc-500 uppercase">
|
||||
Cena 1 · desktop (~1280px) — "Cortar vídeo" a partir do trecho selecionado (C166)
|
||||
</p>
|
||||
<div
|
||||
class="mt-3 w-[1280px] max-w-full overflow-hidden rounded-xl border border-zinc-800 bg-zinc-900"
|
||||
>
|
||||
<div class="relative">
|
||||
<!-- fundo: detalhe da fala como existe hoje, esmaecido pelo overlay -->
|
||||
<div class="p-6 opacity-40">
|
||||
<p class="text-xs text-zinc-500">← Voltar ao acervo</p>
|
||||
<h2 class="mt-2 text-base font-medium text-zinc-100">BREVES COMUNICAÇÕES</h2>
|
||||
<p class="mt-1 text-xs text-zinc-500">
|
||||
11/08/2026 · 18:48 · Breves Comunicações · 4min25s
|
||||
</p>
|
||||
<div class="mt-4 grid grid-cols-[1fr_260px] gap-5">
|
||||
<div>
|
||||
<div
|
||||
class="flex aspect-video items-center justify-center rounded-lg border border-zinc-800 bg-zinc-950"
|
||||
>
|
||||
<svg
|
||||
viewBox="0 0 24 24"
|
||||
fill="currentColor"
|
||||
class="size-10 text-zinc-600"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<path d="M8 5v14l11-7z" />
|
||||
</svg>
|
||||
</div>
|
||||
<div class="mt-3 space-y-1">
|
||||
<div class="flex gap-3 rounded-lg px-2 py-1.5">
|
||||
<span class="w-12 shrink-0 text-xs text-zinc-500">00:00</span>
|
||||
<span class="text-sm text-zinc-500">… agradeço, Presidente. …</span>
|
||||
</div>
|
||||
<div class="flex gap-3 rounded-lg px-2 py-1.5">
|
||||
<span class="w-12 shrink-0 text-xs text-zinc-500">00:43</span>
|
||||
<span class="text-sm text-zinc-500"
|
||||
>… o acesso a medicamentos na Bahia precisa chegar a quem mora no interior
|
||||
…</span
|
||||
>
|
||||
</div>
|
||||
<div class="flex gap-3 rounded-lg px-2 py-1.5">
|
||||
<span class="w-12 shrink-0 text-xs text-zinc-500">02:10</span>
|
||||
<span class="text-sm text-zinc-500">… o financiamento tripartite …</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<aside class="space-y-3">
|
||||
<div class="h-3 w-full rounded bg-zinc-800"></div>
|
||||
<div class="h-3 w-5/6 rounded bg-zinc-800"></div>
|
||||
<div class="h-3 w-4/6 rounded bg-zinc-800"></div>
|
||||
<p class="pt-2 text-xs text-zinc-500">Fonte: Câmara dos Deputados · CC BY 4.0</p>
|
||||
</aside>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- overlay: formulário de corte -->
|
||||
<div class="absolute inset-0 grid place-items-center bg-zinc-950/75 p-6">
|
||||
<div class="w-[560px] rounded-xl border border-zinc-700 bg-zinc-900 p-6">
|
||||
<div class="flex items-start justify-between gap-3">
|
||||
<div>
|
||||
<h2 class="text-base font-medium text-zinc-100">Cortar vídeo</h2>
|
||||
<p class="mt-0.5 text-xs text-zinc-500">
|
||||
O arquivo sai com o trecho exato — nada antes, nada depois.
|
||||
</p>
|
||||
</div>
|
||||
<span
|
||||
class="shrink-0 rounded border border-amber-500/60 px-2 py-0.5 text-[10px] tracking-wide text-amber-400 uppercase"
|
||||
>
|
||||
seleção do C166
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="mt-4 rounded-lg border border-zinc-700 bg-zinc-950 p-3">
|
||||
<div class="flex items-center justify-between gap-3">
|
||||
<span class="font-mono text-sm text-amber-400">00:43 → 01:58</span>
|
||||
<span class="text-xs text-zinc-500">1min15s · dentro da faixa de 5–180 s</span>
|
||||
</div>
|
||||
<p class="mt-2 text-xs text-zinc-400">
|
||||
"…o acesso a medicamentos na Bahia precisa chegar a quem mora no interior…"
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="mt-4">
|
||||
<label class="text-xs tracking-wide text-zinc-500 uppercase">Título</label>
|
||||
<div
|
||||
class="mt-1.5 flex min-h-11 w-full items-center rounded-lg border border-zinc-700 bg-zinc-950 px-3 text-sm text-zinc-100"
|
||||
>
|
||||
Acesso a medicamentos na Bahia precisa chegar a quem mora no interior
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-4">
|
||||
<label class="text-xs tracking-wide text-zinc-500 uppercase">Descrição</label>
|
||||
<div
|
||||
class="mt-1.5 min-h-[88px] w-full rounded-lg border border-zinc-700 bg-zinc-950 px-3 py-2.5 text-sm text-zinc-300"
|
||||
>
|
||||
Em pronunciamento no plenário, o deputado cobra o financiamento tripartite da
|
||||
saúde e reforça a necessidade de abastecer as farmácias populares do interior
|
||||
baiano.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="mt-4 rounded-lg border border-amber-500/40 bg-amber-500/10 p-3 text-xs text-amber-200/90"
|
||||
>
|
||||
Sugerido por IA — revise antes de publicar. Os dois campos são editáveis.
|
||||
</div>
|
||||
|
||||
<div class="mt-5 flex items-center justify-end gap-2">
|
||||
<button
|
||||
type="button"
|
||||
class="min-h-11 rounded-lg border border-zinc-700 px-4 text-sm text-zinc-300"
|
||||
>
|
||||
Cancelar
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="min-h-11 rounded-lg bg-amber-500 px-4 text-sm font-medium text-zinc-950"
|
||||
>
|
||||
Cortar e publicar
|
||||
</button>
|
||||
</div>
|
||||
<p class="mt-3 text-xs text-zinc-500">
|
||||
Nada é publicado antes de confirmar. No fim, o corte ganha o link
|
||||
<span class="font-mono">/corte/123</span> e o arquivo fica na biblioteca de cortes
|
||||
(C168).
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ============================================================ -->
|
||||
<!-- Cena 2 · preparando o corte (progresso honesto) -->
|
||||
<!-- ============================================================ -->
|
||||
<section class="mt-8">
|
||||
<p class="text-xs tracking-wide text-zinc-500 uppercase">
|
||||
Cena 2 · "Preparando o corte…" — espera honesta com o passo atual
|
||||
</p>
|
||||
<div
|
||||
class="mt-3 w-full max-w-[640px] overflow-hidden rounded-xl border border-zinc-800 bg-zinc-900 p-6"
|
||||
>
|
||||
<div class="flex items-center gap-3">
|
||||
<div
|
||||
class="h-6 w-6 shrink-0 rounded-full border-2 border-zinc-700 border-t-amber-500"
|
||||
></div>
|
||||
<div>
|
||||
<p class="text-sm font-medium text-zinc-100">Preparando o corte…</p>
|
||||
<p class="text-xs text-zinc-500">
|
||||
Isso costuma levar menos de um minuto. Não feche esta página.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ul class="mt-5 space-y-2">
|
||||
<li class="flex items-center gap-3 rounded-lg border border-zinc-800 px-3 py-2.5">
|
||||
<svg
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
class="size-4 shrink-0 text-amber-400"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<path d="M20 6 9 17l-5-5" />
|
||||
</svg>
|
||||
<span class="text-sm text-zinc-400">Localizando o trecho na Câmara</span>
|
||||
<span class="ml-auto text-xs text-zinc-500">Concluído</span>
|
||||
</li>
|
||||
<li
|
||||
class="flex items-center gap-3 rounded-lg border border-amber-500/40 bg-amber-500/10 px-3 py-2.5"
|
||||
>
|
||||
<span class="size-2 shrink-0 rounded-full bg-amber-500"></span>
|
||||
<span class="text-sm text-zinc-100">Cortando o trecho 00:43 → 01:58</span>
|
||||
<span class="ml-auto text-xs text-amber-400">Em andamento</span>
|
||||
</li>
|
||||
<li class="flex items-center gap-3 rounded-lg border border-zinc-800 px-3 py-2.5">
|
||||
<span class="size-2 shrink-0 rounded-full bg-zinc-700"></span>
|
||||
<span class="text-sm text-zinc-500">Gerando título e descrição</span>
|
||||
<span class="ml-auto text-xs text-zinc-600">Na fila</span>
|
||||
</li>
|
||||
<li class="flex items-center gap-3 rounded-lg border border-zinc-800 px-3 py-2.5">
|
||||
<span class="size-2 shrink-0 rounded-full bg-zinc-700"></span>
|
||||
<span class="text-sm text-zinc-500">Publicando a página do corte</span>
|
||||
<span class="ml-auto text-xs text-zinc-600">Na fila</span>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p class="mt-4 border-t border-zinc-800 pt-3 text-xs text-zinc-500">
|
||||
Nada foi publicado ainda. Se algo falhar, você volta ao acervo sem corte — nada fica no
|
||||
ar pela metade.
|
||||
</p>
|
||||
</div>
|
||||
<p class="mt-2 text-xs text-zinc-500">
|
||||
Progresso honesto: mostra o passo atual e o que falta; sem porcentagem inventada.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<!-- ============================================================ -->
|
||||
<!-- Cena 3 · erro honesto — nada publicado -->
|
||||
<!-- ============================================================ -->
|
||||
<section class="mt-8">
|
||||
<p class="text-xs tracking-wide text-zinc-500 uppercase">
|
||||
Cena 3 · erro — o corte falhou e nada foi publicado
|
||||
</p>
|
||||
<div
|
||||
class="mt-3 w-full max-w-[640px] overflow-hidden rounded-xl border border-zinc-800 bg-zinc-900 p-6"
|
||||
>
|
||||
<div class="flex items-start gap-3">
|
||||
<div
|
||||
class="flex size-9 shrink-0 items-center justify-center rounded-lg border border-zinc-700"
|
||||
>
|
||||
<svg
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
class="size-4 text-zinc-400"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<path d="M18 6 6 18M6 6l12 12" />
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<p class="text-sm font-medium text-zinc-100">Não foi possível cortar o trecho</p>
|
||||
<p class="mt-1 text-sm text-zinc-400">
|
||||
A Câmara não está entregando o vídeo desta fala agora. Nada foi publicado — o acervo
|
||||
e o trecho selecionado continuam como estavam.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-5 flex flex-wrap items-center gap-2">
|
||||
<button
|
||||
type="button"
|
||||
class="min-h-11 rounded-lg bg-amber-500 px-4 text-sm font-medium text-zinc-950"
|
||||
>
|
||||
Tentar novamente
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="min-h-11 rounded-lg border border-zinc-700 px-4 text-sm text-zinc-300"
|
||||
>
|
||||
Voltar ao acervo
|
||||
</button>
|
||||
</div>
|
||||
<p class="mt-3 text-xs text-zinc-500">
|
||||
O mesmo trecho continua selecionado; tentar de novo não cria corte duplicado.
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ============================================================ -->
|
||||
<!-- Cena 4 · sucesso no acervo — link + Copiar + WhatsApp + Baixar -->
|
||||
<!-- ============================================================ -->
|
||||
<section class="mt-8">
|
||||
<p class="text-xs tracking-wide text-zinc-500 uppercase">
|
||||
Cena 4 · sucesso no detalhe — link público, compartilhar e baixar (+ preview WhatsApp)
|
||||
</p>
|
||||
<div class="mt-3 flex flex-wrap items-start gap-5">
|
||||
<div
|
||||
class="w-full max-w-[640px] overflow-hidden rounded-xl border border-zinc-800 bg-zinc-900 p-6"
|
||||
>
|
||||
<div class="flex items-center gap-3">
|
||||
<svg
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
class="size-5 shrink-0 text-amber-400"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<path d="M20 6 9 17l-5-5" />
|
||||
</svg>
|
||||
<div>
|
||||
<p class="text-sm font-medium text-zinc-100">Corte publicado</p>
|
||||
<p class="text-xs text-zinc-500">
|
||||
O arquivo do trecho está salvo e a página pública já está no ar.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="mt-5 text-xs tracking-wide text-zinc-500 uppercase">
|
||||
Link público (funciona no WhatsApp)
|
||||
</p>
|
||||
<div class="mt-1.5 flex items-stretch gap-2">
|
||||
<div
|
||||
class="flex min-h-11 min-w-0 flex-1 items-center rounded-lg border border-zinc-700 bg-zinc-950 px-3 font-mono text-sm text-zinc-300"
|
||||
>
|
||||
<span class="truncate">https://jorgesolla1313.com.br/corte/123</span>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
class="min-h-11 shrink-0 rounded-lg bg-amber-500 px-4 text-sm font-medium text-zinc-950"
|
||||
>
|
||||
Copiar link
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="mt-3 flex flex-wrap items-center gap-2">
|
||||
<button
|
||||
type="button"
|
||||
class="min-h-11 rounded-lg border border-zinc-700 px-4 text-sm text-zinc-300"
|
||||
>
|
||||
Compartilhar no WhatsApp
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="min-h-11 rounded-lg border border-zinc-700 px-4 text-sm text-zinc-300"
|
||||
>
|
||||
Baixar arquivo (MP4)
|
||||
</button>
|
||||
<span class="text-sm text-zinc-400 underline decoration-zinc-700 underline-offset-4"
|
||||
>Abrir página do corte ↗</span
|
||||
>
|
||||
</div>
|
||||
|
||||
<p class="mt-4 border-t border-zinc-800 pt-3 text-xs text-zinc-500">
|
||||
O arquivo também fica disponível na biblioteca de cortes (C168) — é lá que se
|
||||
despublica o corte.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="w-[300px]">
|
||||
<p class="text-xs tracking-wide text-zinc-500 uppercase">
|
||||
Preview no WhatsApp (Open Graph)
|
||||
</p>
|
||||
<div class="mt-1.5 overflow-hidden rounded-lg border border-zinc-800 bg-zinc-900">
|
||||
<div class="flex h-[140px] items-center justify-center bg-zinc-800">
|
||||
<span class="text-xs text-zinc-500"
|
||||
>capa do YouTube da sessão (quando existir)</span
|
||||
>
|
||||
</div>
|
||||
<div class="p-3">
|
||||
<p class="text-sm font-medium text-zinc-100">
|
||||
Acesso a medicamentos na Bahia precisa chegar a quem mora no interior
|
||||
</p>
|
||||
<p class="mt-1 line-clamp-2 text-xs text-zinc-400">
|
||||
Em pronunciamento no plenário, o deputado cobra o financiamento tripartite da
|
||||
saúde…
|
||||
</p>
|
||||
<p class="mt-2 text-[10px] tracking-wide text-zinc-500 uppercase">
|
||||
jorgesolla1313.com.br
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<p class="mt-2 text-xs text-zinc-500">
|
||||
Título, descrição e imagem vêm do corte; a página segue unlisted.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ============================================================ -->
|
||||
<!-- Cena 5 · página pública /corte/123 — desktop -->
|
||||
<!-- ============================================================ -->
|
||||
<section class="mt-8">
|
||||
<p class="text-xs tracking-wide text-zinc-500 uppercase">
|
||||
Cena 5 · desktop (~1280px) — página pública /corte/123
|
||||
</p>
|
||||
<div
|
||||
class="mt-3 w-[1280px] max-w-full overflow-hidden rounded-xl border border-zinc-800 bg-zinc-900"
|
||||
>
|
||||
<div class="flex items-center justify-between border-b border-zinc-800 px-6 py-4">
|
||||
<div class="h-4 w-28 rounded bg-zinc-800"></div>
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="h-3 w-16 rounded bg-zinc-800"></div>
|
||||
<div class="h-3 w-16 rounded bg-zinc-800"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mx-auto max-w-[720px] px-6 py-10">
|
||||
<div class="relative aspect-video rounded-lg border border-zinc-800 bg-zinc-950">
|
||||
<div class="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2">
|
||||
<svg
|
||||
viewBox="0 0 24 24"
|
||||
fill="currentColor"
|
||||
class="size-12 text-zinc-600"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<path d="M8 5v14l11-7z" />
|
||||
</svg>
|
||||
</div>
|
||||
<span
|
||||
class="absolute top-3 right-3 rounded border border-amber-500/60 px-2 py-0.5 text-[10px] tracking-wide text-amber-400 uppercase"
|
||||
>
|
||||
unlisted · não indexável
|
||||
</span>
|
||||
<p class="absolute bottom-3 left-3 text-xs text-zinc-400">
|
||||
Toca o arquivo MP4 do corte (não o YouTube)
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<h2 class="mt-5 text-2xl font-medium text-zinc-100">
|
||||
Acesso a medicamentos na Bahia precisa chegar a quem mora no interior
|
||||
</h2>
|
||||
<p class="mt-2 text-sm text-zinc-500">
|
||||
Discurso em plenário · 11/08/2026 · 1min15s ·
|
||||
<span class="text-zinc-300 underline decoration-zinc-700 underline-offset-4"
|
||||
>Ver sessão no YouTube ↗</span
|
||||
>
|
||||
</p>
|
||||
<p class="mt-4 text-sm text-zinc-300">
|
||||
Em pronunciamento no plenário, o deputado cobra o financiamento tripartite da saúde e
|
||||
reforça a necessidade de abastecer as farmácias populares do interior baiano.
|
||||
</p>
|
||||
|
||||
<div class="mt-6 flex flex-wrap items-center gap-2">
|
||||
<button
|
||||
type="button"
|
||||
class="min-h-11 rounded-lg bg-amber-500 px-4 text-sm font-medium text-zinc-950"
|
||||
>
|
||||
Compartilhar no WhatsApp
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="min-h-11 rounded-lg border border-zinc-700 px-4 text-sm text-zinc-300"
|
||||
>
|
||||
Baixar arquivo (MP4)
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="min-h-11 rounded-lg border border-zinc-700 px-4 text-sm text-zinc-300"
|
||||
>
|
||||
Copiar link
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<p class="mt-8 border-t border-zinc-800 pt-4 text-xs text-zinc-500">
|
||||
Fonte: Câmara dos Deputados · CC BY 4.0
|
||||
</p>
|
||||
<p class="mt-1 text-xs text-zinc-600">
|
||||
Sem transcrição nem internals nesta página — o contexto mínimo é data, tipo e o link
|
||||
da sessão.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ============================================================ -->
|
||||
<!-- Cena 6 · página pública /corte/123 — mobile (~390px) -->
|
||||
<!-- ============================================================ -->
|
||||
<section class="mt-8">
|
||||
<p class="text-xs tracking-wide text-zinc-500 uppercase">
|
||||
Cena 6 · mobile (~390px) — mesma hierarquia, ações empilhadas
|
||||
</p>
|
||||
<div class="mt-3 w-[390px] overflow-hidden rounded-xl border border-zinc-800 bg-zinc-900">
|
||||
<div class="flex items-center justify-between border-b border-zinc-800 px-4 py-3">
|
||||
<div class="h-4 w-20 rounded bg-zinc-800"></div>
|
||||
<div class="h-5 w-5 rounded bg-zinc-800"></div>
|
||||
</div>
|
||||
<div class="px-4 py-5">
|
||||
<div class="relative aspect-video rounded-lg border border-zinc-800 bg-zinc-950">
|
||||
<div class="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2">
|
||||
<svg
|
||||
viewBox="0 0 24 24"
|
||||
fill="currentColor"
|
||||
class="size-10 text-zinc-600"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<path d="M8 5v14l11-7z" />
|
||||
</svg>
|
||||
</div>
|
||||
<p class="absolute bottom-2 left-2 text-[10px] text-zinc-400">Arquivo MP4 do corte</p>
|
||||
</div>
|
||||
|
||||
<h2 class="mt-4 text-lg font-medium text-zinc-100">
|
||||
Acesso a medicamentos na Bahia precisa chegar a quem mora no interior
|
||||
</h2>
|
||||
<p class="mt-1 text-xs text-zinc-500">
|
||||
Discurso em plenário · 11/08/2026 · 1min15s ·
|
||||
<span class="text-zinc-300 underline decoration-zinc-700 underline-offset-4"
|
||||
>YouTube ↗</span
|
||||
>
|
||||
</p>
|
||||
<p class="mt-3 text-sm text-zinc-300">
|
||||
Em pronunciamento no plenário, o deputado cobra o financiamento tripartite da saúde e
|
||||
reforça a necessidade de abastecer as farmácias populares do interior baiano.
|
||||
</p>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
class="mt-4 h-11 w-full rounded-lg bg-amber-500 text-sm font-medium text-zinc-950"
|
||||
>
|
||||
Compartilhar no WhatsApp
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="mt-2 h-11 w-full rounded-lg border border-zinc-700 text-sm text-zinc-300"
|
||||
>
|
||||
Baixar arquivo (MP4)
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="mt-2 h-11 w-full rounded-lg border border-zinc-700 text-sm text-zinc-300"
|
||||
>
|
||||
Copiar link
|
||||
</button>
|
||||
|
||||
<p class="mt-4 border-t border-zinc-800 pt-3 text-xs text-zinc-500">
|
||||
Fonte: Câmara dos Deputados · CC BY 4.0
|
||||
</p>
|
||||
<p class="mt-1 text-[10px] text-zinc-600">unlisted · não indexável · sem transcrição</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ============================================================ -->
|
||||
<!-- Cena 7 · corte despublicado/indisponível -->
|
||||
<!-- ============================================================ -->
|
||||
<section class="mt-8">
|
||||
<p class="text-xs tracking-wide text-zinc-500 uppercase">
|
||||
Cena 7 · público — corte despublicado (kill switch) ou link inválido
|
||||
</p>
|
||||
<div
|
||||
class="mt-3 flex w-full max-w-[1280px] items-center justify-center rounded-xl border border-zinc-800 bg-zinc-900 px-6 py-14"
|
||||
>
|
||||
<div class="max-w-[480px] text-center">
|
||||
<div
|
||||
class="mx-auto flex size-10 items-center justify-center rounded-lg border border-zinc-700"
|
||||
>
|
||||
<svg
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
class="size-4 text-zinc-500"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<path d="M18 6 6 18M6 6l12 12" />
|
||||
</svg>
|
||||
</div>
|
||||
<p class="mt-3 text-base font-medium text-zinc-100">Este corte não está disponível</p>
|
||||
<p class="mt-1 text-sm text-zinc-400">
|
||||
O link pode ter sido despublicado ou o endereço está incorreto.
|
||||
</p>
|
||||
<button
|
||||
type="button"
|
||||
class="mt-5 min-h-11 rounded-lg border border-zinc-700 px-4 text-sm text-zinc-300"
|
||||
>
|
||||
Ir para jorgesolla1313.com.br
|
||||
</button>
|
||||
<p class="mt-3 text-xs text-zinc-600">
|
||||
Mesma resposta para despublicado e id inexistente — não revela se o corte existiu.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
101
docs/plans/c167-cortar-trecho-publicar.md
Normal file
101
docs/plans/c167-cortar-trecho-publicar.md
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
# Acervo: cortar o trecho [início,fim] e publicar o arquivo numa página compartilhável
|
||||
|
||||
Status: rascunho
|
||||
Atualizado em: 2026-09-15
|
||||
Issue: #1014
|
||||
Priority: P1
|
||||
Impeccable: C — fluxo novo no detalhe do acervo + superfície pública nova
|
||||
Rascunho UI: docs/plans/c167-cortar-trecho-publicar-ui-draft.html
|
||||
Appetite: ~2–3 dias eng; um outcome verificável — o corte [início,fim] exato sai salvo, tocável e baixável numa página pública compartilhável
|
||||
Responsável: —
|
||||
|
||||
## Intenção
|
||||
|
||||
O link do YouTube posiciona no ponto, mas a peça exige o arquivo exato. Quem produz conteúdo escolhe um trecho da fala no acervo (C166) e hoje só consegue mandar o link da sessão com o tempo — para editar ou postar, garimpa o vídeo de novo e o trecho vem com o que vier antes e depois. Este item fecha o ciclo: da mesma seleção [início,fim], "Cortar vídeo" gera o arquivo exato, salva no servidor e publica uma página pública com player; o compartilhamento passa a ser por link (com preview no WhatsApp) ou baixando o arquivo. Título e descrição são gerados por IA no momento do corte — editáveis antes de confirmar — e o arquivo fica disponível para a biblioteca de cortes (C168).
|
||||
|
||||
## Persona e fluxo
|
||||
|
||||
- **Persona / contexto:** assessoria de comunicação (communicator, coordenação e candidatura) na mesa, montando peça com prazo curto e com o acervo aberto.
|
||||
- **Job principal:** transformar o trecho escolhido no arquivo exato [início,fim] e ter um link público para mandar no WhatsApp ou baixar.
|
||||
- **Fluxo desejado:** abre a fala → seleciona o trecho (C166) → "Cortar vídeo" → título e descrição sugeridos pela IA (edita se quiser) → "Cortar e publicar" → "Preparando o corte…" → pronto: link público + Copiar + WhatsApp + Baixar arquivo; quem recebe abre `/corte/<id>` e assiste/baixa o mesmo arquivo.
|
||||
- **Anti-goals de produto:** não é editor de vídeo; não aceita upload externo; não expõe transcrição nem internals no público; não cria segundo cadastro de pessoa nem `Consent`; não vira galeria pública indexável; não abre o acervo para quem não lê.
|
||||
|
||||
### Esboço de fluxo (C)
|
||||
|
||||
```text
|
||||
[detalhe da fala] → seleção [início,fim] (C166) → "Cortar vídeo"
|
||||
→ formulário: título/descrição IA (editáveis) + "Cortar e publicar"
|
||||
→ "Preparando o corte…" (espera honesta; falhou → erro claro, nada publicado)
|
||||
→ corte publicado: link /corte/<id> + Copiar + WhatsApp + Baixar MP4
|
||||
→ quem recebe: player do arquivo exato + compartilhar/baixar (unlisted)
|
||||
```
|
||||
|
||||
### Rascunho UI (C)
|
||||
|
||||
- Rascunho UI (gate): `docs/plans/c167-cortar-trecho-publicar-ui-draft.html` — cenas: formulário de corte com título/descrição IA editáveis; "Preparando o corte…"; erro honesto; sucesso no acervo (link + Copiar + WhatsApp + Baixar + preview); página pública desktop e mobile; corte despublicado/indisponível.
|
||||
|
||||
## Objetivo e aceite
|
||||
|
||||
- Da seleção [início,fim] do C166 (5–180 s), "Cortar vídeo" gera e salva o MP4 do trecho EXATO — começa e termina nos marcos escolhidos, sem aproximar keyframe.
|
||||
- O corte nasce publicado: `/corte/<id>` toca esse mesmo arquivo e o download entrega o mesmo arquivo; o link funciona no WhatsApp com preview (título, descrição e imagem).
|
||||
- Título e descrição vêm da IA em pt-BR (texto/contexto do trecho), pré-preenchidos e editáveis antes de confirmar; IA indisponível → fallback determinístico, sem bloquear a criação.
|
||||
- Compartilhar = copiar link público + deep link WhatsApp + baixar arquivo; o mesmo arquivo é baixável direto para compartilhar fora do link.
|
||||
- Kill switch: despublicar tira o corte do ar na hora (admin; toggle na página interna em C168); o id numérico sobrevive à troca de título.
|
||||
- **Guardrails:** página pública não indexável (unlisted, só por link; `noindex`); sem transcrição/internals no público; crédito "Fonte: Câmara dos Deputados · CC BY 4.0"; corta quem lê o acervo (communicator/coordinator/candidate), advisor/leader negados fail-closed; falhou o corte, nada é publicado; sem upload externo/Consent/segundo cadastro.
|
||||
|
||||
## Dados (intenção)
|
||||
|
||||
- **Vou apresentar dados?** Não — a superfície é formulário, estados de progresso/erro e player público; nenhum KPI/gráfico novo.
|
||||
- **Decisões desbloqueadas:** a assessoria decide qual trecho vira peça publicável e compartilha o arquivo exato sem depender do YouTube; a coordenação decide, em C168, o que continua no ar.
|
||||
- **Forma:** _adiada ao plano de implementação_ — restrição: progresso/erro é feedback de ação, não dado de acervo.
|
||||
|
||||
## Dados da decisão (literais)
|
||||
|
||||
- Rota pública `/corte/<id>` — id numérico sequencial do corte, estável mesmo quando o título muda; enumerável por natureza (trade-off aceito: o conteúdo é fala pública do deputado, e despublicar remove o acesso). Estado do corte: `publicado` (público pelo link) | `despublicado` (link fora do ar) — nasce publicado ao confirmar; despublicar é o kill switch (admin; toggle na página interna em C168).
|
||||
- Faixa da seleção: 5–180 s — a mesma do C166.
|
||||
- Arquivo: MP4 do trecho EXATO [início,fim] — começa e termina nos marcos escolhidos (não aproximação de keyframe); salvo no servidor; o player público toca esse arquivo e o download entrega o mesmo arquivo.
|
||||
- Título/descrição: IA em pt-BR (provider DeepSeek já existente no repo) a partir do texto do trecho/contexto do discurso; pré-preenchidos no formulário de corte e editáveis antes de confirmar; IA indisponível → fallback determinístico `Trecho de <tipo> — <data>` + resumo oficial do discurso, sem bloquear a criação.
|
||||
- Open Graph (WhatsApp): título, descrição e imagem; quando a fala tem YouTube, usar a capa do YouTube da sessão como imagem. Página NÃO indexável (unlisted; só por link) e crédito `Fonte: Câmara dos Deputados · CC BY 4.0`.
|
||||
- Compartilhar o corte: copiar link público + deep link WhatsApp (`wa.me/?text=`); baixar o arquivo. O arquivo também pode ser baixado direto para compartilhar.
|
||||
- Quem corta: quem lê o acervo (communicator/coordinator/candidate); advisor/leader negados (fail-closed). Sem expor transcrição/internals na página pública; sem upload externo de vídeo; sem Consent; sem segundo cadastro de pessoa.
|
||||
|
||||
## Direção no codebase (hipótese)
|
||||
|
||||
- **Áreas prováveis:** detalhe do acervo (`src/app/(campaign)/campanha/(app)/comunicacao/acervo/[id]/`, `src/components/campaign/speech/`), `src/utilities/speech/` (corte e publicação), ações/rotas de `/campanha` do acervo, superfície pública em `src/app/(frontend)/` (metadata/Open Graph).
|
||||
- **Precedente a olhar:** resolução VOD sob demanda (`resolver-vod` + `speechVodResolver.ts`); upload programático por buffer já existente (`media`) com S3/Garage e proxy `/api/media/file/...` com Range; IA de texto (`campaignDemandTitle.ts`, `rerankSpeechExcerpts.ts`); páginas públicas com metadata/OG (`[type]/[category]/[slug]/page.tsx`); allowlist de revalidação em `/api/revalidate`.
|
||||
- **Risco de acoplamento (mecanismo de corte EM ABERTO — decisão do plano de implementação):** `ffmpeg/ffprobe` não existem no repo/Dockerfile (Alpine) e a API da Câmara corta do ponto até o FIM (`trecho=`), então o [início,fim] exato exige corte próprio — servidor, navegador ou serviço externo é trade-off a avaliar; sem infra de fila/job no repo, a criação tende a ser espera com progresso; falha nunca publica; diff em `src/utilities/speech`/`src/components/campaign/speech`/comunicacao acorda o e2e `campaignSpeechAcervo`.
|
||||
|
||||
## Dependências
|
||||
|
||||
- **Dura: C166** — a seleção [início,fim] e o compartilhamento por link do YouTube são a porta de entrada; sem ela não há trecho para cortar.
|
||||
- Suaves: C168 (biblioteca de cortes — guarda o arquivo e hospeda o toggle de despublicar), C162 (resolução VOD sob demanda), C154 (vertical acervo).
|
||||
|
||||
## Fora de escopo
|
||||
|
||||
- Editar além da seleção do C166 (timeline, preview, ajuste fino), legenda/CC, trilha e capa custom; biblioteca/curadoria/listagem de cortes e o toggle de despublicar (C168); upload externo de vídeo; indexação/SEO público do corte e publicação em YouTube/redes via API.
|
||||
|
||||
## Rabbit holes de produto
|
||||
|
||||
- **Editor de vídeo no browser.** Se alguém "só completar": timeline, filtros, preview de render. **Corte neste item:** o corte é [início,fim] da seleção do C166; sem edição.
|
||||
- **Fila assíncrona de render com notificação.** Se alguém "só completar": worker, retry, tela de pendências. **Corte nesta fatia:** espera curta com progresso honesto e erro claro; falhou, nada publicado.
|
||||
- **Legendar/transcrever o arquivo gerado.** Se alguém "só completar": burn-in, `.srt`, tradução. **Corte neste item:** o arquivo vai sem legenda; a transcrição segue só no acervo interno.
|
||||
- **Galeria pública de cortes ("já que estão no ar").** Se alguém "só completar": índice, busca, perfil. **Corte neste item:** unlisted, só por link.
|
||||
|
||||
## Questões em aberto (produto)
|
||||
|
||||
- **Publicar direto ou pré-visualizar?** **Opções:** A) confirmar já publica (título/descrição editáveis no formulário) | B) gerar rascunho e publicar depois. **Recomendação:** A, com kill switch via admin/C168. _(assumido — validar com produto)_
|
||||
- **Indexar no Google?** **Opções:** A) unlisted/`noindex` | B) indexável. **Recomendação:** A — o link funciona no WhatsApp e evita exposição no período eleitoral.
|
||||
- **Demora do corte:** **Opções:** A) espera curta com progresso honesto e erro claro | B) fila assíncrona com notificação. **Recomendação:** A nesta fatia (fila é rabbit hole).
|
||||
- **O que a página pública mostra do discurso?** **Opções:** A) só o corte + crédito | B) contexto (data/tipo) e link para o YouTube. **Recomendação:** B minimalista (data/tipo + link; sem transcrição).
|
||||
|
||||
## Referências
|
||||
|
||||
- GitHub Issue: — (após `pnpm agent:register`)
|
||||
- Rascunho UI (gate): `docs/plans/c167-cortar-trecho-publicar-ui-draft.html`
|
||||
- Planos irmãos: [`c166-compartilhar-trecho-link.md`](c166-compartilhar-trecho-link.md) (C166), [`c168-biblioteca-cortes.md`](c168-biblioteca-cortes.md) (C168), [`acervo-vod-sob-demanda.md`](acervo-vod-sob-demanda.md) (C162), [`acervo-videos-comunicacao.md`](acervo-videos-comunicacao.md) (C154)
|
||||
- Arquivos-chave (pista, não contrato): `src/components/campaign/speech/SpeechDetailPlayer.tsx`, `src/utilities/speech/speechVodResolver.ts`, `src/utilities/ai/`, `src/app/(frontend)/`, `scripts/lib/camaraFetch.mjs`
|
||||
- `AGENTS.md` / `AGENTS-campaign.md` — vertical Comunicação, gate do acervo e crédito CC BY.
|
||||
|
||||
## Self-score (shaping)
|
||||
|
||||
5/5 — (1) fatia = um outcome verificável (o corte [início,fim] exato sai salvo, tocável e baixável numa página pública compartilhável); (2) appetite de ~2–3 dias comporta o fluxo + estados + página pública, com o mecanismo de corte como maior incerteza declarada; (3) persona, job e aceite legíveis sem jargão de stack; (4) direção no codebase é hipótese (áreas, precedentes e o risco ffmpeg/Câmara em aberto); (5) zero decisão dura de engenharia no plano (schema, storage, corte e mecanismo de IA ficam para o plano de implementação).
|
||||
705
docs/plans/c168-biblioteca-cortes-ui-draft.html
Normal file
705
docs/plans/c168-biblioteca-cortes-ui-draft.html
Normal file
|
|
@ -0,0 +1,705 @@
|
|||
<!doctype html>
|
||||
<html lang="pt-BR">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>
|
||||
<title>UI draft — C168 · Acervo: biblioteca de cortes</title>
|
||||
</head>
|
||||
<body class="bg-zinc-950 text-zinc-100 antialiased">
|
||||
<main class="mx-auto max-w-[1400px] p-6 sm:p-8">
|
||||
<h1 class="text-lg font-medium text-zinc-100">
|
||||
UI draft — Acervo: biblioteca de cortes (C168)
|
||||
</h1>
|
||||
<p class="mt-1 max-w-3xl text-sm text-zinc-400">
|
||||
A assessoria reencontra um corte já feito, confere o discurso de origem, ajusta título e
|
||||
descrição, baixa, compartilha e publica/despublica — sem refazer o corte.
|
||||
</p>
|
||||
<p class="mt-2 text-sm text-zinc-500">
|
||||
Cinza = estrutura existente · <span class="text-amber-400">âmbar</span> = ação primária /
|
||||
novo neste item · barras cinza = conteúdo não especificado. Cenas estáticas: sem interação,
|
||||
sem dados reais.
|
||||
</p>
|
||||
|
||||
<!-- ============================================================ -->
|
||||
<!-- Cena 1 · desktop (~1280px) — lista de cortes -->
|
||||
<!-- ============================================================ -->
|
||||
<section class="mt-8">
|
||||
<p class="text-xs tracking-wide text-zinc-500 uppercase">
|
||||
Cena 1 · desktop (~1280px) — /campanha/comunicacao/acervo/cortes
|
||||
</p>
|
||||
<div class="mt-3 overflow-x-auto">
|
||||
<div
|
||||
class="w-[1280px] max-w-full overflow-hidden rounded-xl border border-zinc-800 bg-zinc-900"
|
||||
>
|
||||
<div class="flex min-h-[600px]">
|
||||
<aside class="w-52 shrink-0 border-r border-zinc-800 bg-zinc-950/50 p-4">
|
||||
<p class="px-3 text-xs tracking-wide text-zinc-500 uppercase">Campanha</p>
|
||||
<nav class="mt-3 flex flex-col gap-1 text-sm">
|
||||
<span class="rounded-lg bg-zinc-800 px-3 py-2 font-medium text-zinc-100"
|
||||
>Comunicação</span
|
||||
>
|
||||
</nav>
|
||||
<div class="mt-8 flex flex-col gap-1 text-sm text-zinc-500">
|
||||
<span class="rounded-lg px-3 py-2">Meu perfil</span>
|
||||
<span class="rounded-lg px-3 py-2">Sair</span>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<div class="min-w-0 flex-1 p-6">
|
||||
<div class="flex flex-wrap items-end justify-between gap-3">
|
||||
<div>
|
||||
<p class="text-xs text-zinc-500">← Acervo de falas</p>
|
||||
<h2 class="mt-1 text-base font-medium">Cortes</h2>
|
||||
<p class="mt-0.5 text-sm text-zinc-400">
|
||||
O que já foi cortado — reencontre, ajuste o texto e republique.
|
||||
</p>
|
||||
</div>
|
||||
<span class="text-xs text-zinc-500">12 cortes</span>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="mt-4 flex items-center gap-2 rounded-lg border border-zinc-800 bg-zinc-950 p-2"
|
||||
>
|
||||
<svg
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
class="size-4 shrink-0 text-zinc-500"
|
||||
>
|
||||
<circle cx="11" cy="11" r="7" />
|
||||
<path d="m20 20-3.5-3.5" />
|
||||
</svg>
|
||||
<span class="text-sm text-zinc-500">Buscar por título ou descrição…</span>
|
||||
<span class="ml-auto px-1 text-xs text-zinc-500">Busca</span>
|
||||
</div>
|
||||
|
||||
<div class="mt-4 flex flex-col gap-3">
|
||||
<!-- Item publicado -->
|
||||
<article class="rounded-xl border border-zinc-800 bg-zinc-900 p-4">
|
||||
<div class="flex flex-wrap items-center gap-2">
|
||||
<span
|
||||
class="rounded-md border border-amber-500/40 bg-amber-500/10 px-2 py-0.5 text-xs font-medium text-amber-400"
|
||||
>Publicado</span
|
||||
>
|
||||
<span class="text-xs text-zinc-500">Criado em 12/08/2026</span>
|
||||
</div>
|
||||
<h3 class="mt-2 text-sm font-medium text-zinc-100">
|
||||
Saúde pública no interior da Bahia
|
||||
</h3>
|
||||
<div class="mt-1.5 flex flex-wrap items-center gap-x-2 gap-y-1 text-xs">
|
||||
<span class="text-zinc-400">Fala · Breves Comunicações · 11/08/2026</span>
|
||||
<span aria-hidden="true" class="text-zinc-600">·</span>
|
||||
<span class="underline decoration-zinc-700 underline-offset-4 text-zinc-300"
|
||||
>Ver fala no acervo</span
|
||||
>
|
||||
<span aria-hidden="true" class="text-zinc-600">·</span>
|
||||
<span class="text-zinc-400">1min12s</span>
|
||||
</div>
|
||||
<div class="mt-3 flex flex-wrap items-center gap-2">
|
||||
<button
|
||||
type="button"
|
||||
class="min-h-10 rounded-lg border border-zinc-700 px-3 text-sm text-zinc-200"
|
||||
>
|
||||
Abrir corte
|
||||
</button>
|
||||
<button type="button" class="min-h-10 rounded-lg px-3 text-sm text-zinc-400">
|
||||
Copiar link
|
||||
</button>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<!-- Item publicado 2 -->
|
||||
<article class="rounded-xl border border-zinc-800 bg-zinc-900 p-4">
|
||||
<div class="flex flex-wrap items-center gap-2">
|
||||
<span
|
||||
class="rounded-md border border-amber-500/40 bg-amber-500/10 px-2 py-0.5 text-xs font-medium text-amber-400"
|
||||
>Publicado</span
|
||||
>
|
||||
<span class="text-xs text-zinc-500">Criado em 10/08/2026</span>
|
||||
</div>
|
||||
<h3 class="mt-2 text-sm font-medium text-zinc-100">
|
||||
Financiamento tripartite e medicamentos
|
||||
</h3>
|
||||
<div class="mt-1.5 flex flex-wrap items-center gap-x-2 gap-y-1 text-xs">
|
||||
<span class="text-zinc-400">Fala · Breves Comunicações · 09/08/2026</span>
|
||||
<span aria-hidden="true" class="text-zinc-600">·</span>
|
||||
<span class="underline decoration-zinc-700 underline-offset-4 text-zinc-300"
|
||||
>Ver fala no acervo</span
|
||||
>
|
||||
<span aria-hidden="true" class="text-zinc-600">·</span>
|
||||
<span class="text-zinc-400">2min03s</span>
|
||||
</div>
|
||||
<div class="mt-3 flex flex-wrap items-center gap-2">
|
||||
<button
|
||||
type="button"
|
||||
class="min-h-10 rounded-lg border border-zinc-700 px-3 text-sm text-zinc-200"
|
||||
>
|
||||
Abrir corte
|
||||
</button>
|
||||
<button type="button" class="min-h-10 rounded-lg px-3 text-sm text-zinc-400">
|
||||
Copiar link
|
||||
</button>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<!-- Item despublicado -->
|
||||
<article class="rounded-xl border border-dashed border-zinc-800 bg-zinc-900 p-4">
|
||||
<div class="flex flex-wrap items-center gap-2">
|
||||
<span
|
||||
class="rounded-md border border-dashed border-zinc-600 px-2 py-0.5 text-xs text-zinc-400"
|
||||
>Despublicado</span
|
||||
>
|
||||
<span class="text-xs text-zinc-500">Criado em 08/08/2026</span>
|
||||
</div>
|
||||
<h3 class="mt-2 text-sm font-medium text-zinc-100">Obras e emprego na Bahia</h3>
|
||||
<div class="mt-1.5 flex flex-wrap items-center gap-x-2 gap-y-1 text-xs">
|
||||
<span class="text-zinc-400">Fala · Breves Comunicações · 08/08/2026</span>
|
||||
<span aria-hidden="true" class="text-zinc-600">·</span>
|
||||
<span class="underline decoration-zinc-700 underline-offset-4 text-zinc-300"
|
||||
>Ver fala no acervo</span
|
||||
>
|
||||
<span aria-hidden="true" class="text-zinc-600">·</span>
|
||||
<span class="text-zinc-400">45s</span>
|
||||
</div>
|
||||
<div class="mt-3 flex flex-wrap items-center gap-2">
|
||||
<button
|
||||
type="button"
|
||||
class="min-h-10 rounded-lg border border-zinc-700 px-3 text-sm text-zinc-200"
|
||||
>
|
||||
Abrir corte
|
||||
</button>
|
||||
<button type="button" class="min-h-10 rounded-lg px-3 text-sm text-zinc-400">
|
||||
Copiar link
|
||||
</button>
|
||||
</div>
|
||||
</article>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="mt-4 flex flex-wrap items-center justify-between gap-3 border-t border-zinc-800 pt-3 text-xs text-zinc-500"
|
||||
>
|
||||
<span>1–3 de 12 cortes</span>
|
||||
<span class="flex items-center gap-2">
|
||||
<span class="rounded-lg border border-zinc-800 px-2 py-1">Anterior</span>
|
||||
<span class="rounded-lg border border-zinc-800 px-2 py-1 text-zinc-300"
|
||||
>Página 1 de 4</span
|
||||
>
|
||||
<span class="rounded-lg border border-zinc-800 px-2 py-1">Próxima</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ============================================================ -->
|
||||
<!-- Cena 2 · desktop — lista vazia -->
|
||||
<!-- ============================================================ -->
|
||||
<section class="mt-10">
|
||||
<p class="text-xs tracking-wide text-zinc-500 uppercase">
|
||||
Cena 2 · desktop — lista vazia ("Nenhum corte ainda")
|
||||
</p>
|
||||
<div class="mt-3 overflow-x-auto">
|
||||
<div
|
||||
class="w-[1280px] max-w-full overflow-hidden rounded-xl border border-zinc-800 bg-zinc-900"
|
||||
>
|
||||
<div class="flex min-h-[420px]">
|
||||
<aside class="w-52 shrink-0 border-r border-zinc-800 bg-zinc-950/50 p-4">
|
||||
<p class="px-3 text-xs tracking-wide text-zinc-500 uppercase">Campanha</p>
|
||||
<nav class="mt-3 flex flex-col gap-1 text-sm">
|
||||
<span class="rounded-lg bg-zinc-800 px-3 py-2 font-medium text-zinc-100"
|
||||
>Comunicação</span
|
||||
>
|
||||
</nav>
|
||||
</aside>
|
||||
<div class="flex min-w-0 flex-1 flex-col p-6">
|
||||
<p class="text-xs text-zinc-500">← Acervo de falas</p>
|
||||
<h2 class="mt-1 text-base font-medium">Cortes</h2>
|
||||
<div
|
||||
class="flex flex-1 flex-col items-center justify-center gap-2 py-10 text-center"
|
||||
>
|
||||
<svg
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
class="size-8 text-zinc-600"
|
||||
>
|
||||
<rect x="2" y="3" width="20" height="14" rx="2" />
|
||||
<path d="M8 21h8M12 17v4" />
|
||||
</svg>
|
||||
<p class="text-sm font-medium text-zinc-200">Nenhum corte ainda</p>
|
||||
<p class="max-w-sm text-xs text-zinc-500">
|
||||
Quando você cortar um trecho de uma fala, ele fica guardado aqui para
|
||||
reencontrar, baixar, ajustar o texto e republicar.
|
||||
</p>
|
||||
<button
|
||||
type="button"
|
||||
class="mt-2 min-h-11 rounded-lg bg-amber-500 px-4 text-sm font-medium text-zinc-950"
|
||||
>
|
||||
Ir para o acervo de falas
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ============================================================ -->
|
||||
<!-- Cena 3 · desktop — detalhe do corte -->
|
||||
<!-- ============================================================ -->
|
||||
<section class="mt-10">
|
||||
<p class="text-xs tracking-wide text-zinc-500 uppercase">
|
||||
Cena 3 · desktop — /campanha/comunicacao/acervo/cortes/[id] (player, origem, editar,
|
||||
ações)
|
||||
</p>
|
||||
<div class="mt-3 overflow-x-auto">
|
||||
<div
|
||||
class="w-[1280px] max-w-full overflow-hidden rounded-xl border border-zinc-800 bg-zinc-900"
|
||||
>
|
||||
<div class="flex min-h-[720px]">
|
||||
<aside class="w-52 shrink-0 border-r border-zinc-800 bg-zinc-950/50 p-4">
|
||||
<p class="px-3 text-xs tracking-wide text-zinc-500 uppercase">Campanha</p>
|
||||
<nav class="mt-3 flex flex-col gap-1 text-sm">
|
||||
<span class="rounded-lg bg-zinc-800 px-3 py-2 font-medium text-zinc-100"
|
||||
>Comunicação</span
|
||||
>
|
||||
</nav>
|
||||
</aside>
|
||||
|
||||
<div class="min-w-0 flex-1 p-6">
|
||||
<p class="text-xs text-zinc-500">← Voltar aos cortes</p>
|
||||
|
||||
<div class="mt-3 grid gap-6 lg:grid-cols-[minmax(0,1fr)_300px]">
|
||||
<div class="min-w-0">
|
||||
<h2 class="text-lg font-medium">Saúde pública no interior da Bahia</h2>
|
||||
<p class="mt-1 text-xs text-zinc-400">
|
||||
Corte de 1min12s · criado em 12/08/2026
|
||||
</p>
|
||||
|
||||
<!-- Player -->
|
||||
<div
|
||||
class="relative mt-4 flex aspect-video w-full items-center justify-center rounded-lg border border-zinc-800 bg-zinc-950"
|
||||
>
|
||||
<div
|
||||
class="flex size-12 items-center justify-center rounded-full border border-zinc-700 text-zinc-300"
|
||||
>
|
||||
▶
|
||||
</div>
|
||||
<span class="absolute top-3 left-3 text-xs text-zinc-500">
|
||||
Corte · 1min12s
|
||||
</span>
|
||||
<div class="absolute right-3 bottom-3 left-3 flex items-center gap-2">
|
||||
<span class="h-1 flex-1 rounded-full bg-zinc-800">
|
||||
<span class="block h-1 w-1/3 rounded-full bg-zinc-500"></span>
|
||||
</span>
|
||||
<span class="text-[10px] tabular-nums text-zinc-500">00:24 / 01:12</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-3 flex flex-wrap items-center gap-2">
|
||||
<button
|
||||
type="button"
|
||||
class="min-h-11 rounded-lg bg-amber-500 px-4 text-sm font-medium text-zinc-950"
|
||||
>
|
||||
Baixar vídeo (MP4)
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="min-h-11 rounded-lg border border-zinc-700 px-4 text-sm text-zinc-300"
|
||||
>
|
||||
Abrir página pública
|
||||
</button>
|
||||
<button type="button" class="min-h-11 rounded-lg px-4 text-sm text-zinc-400">
|
||||
Copiar link
|
||||
</button>
|
||||
<button type="button" class="min-h-11 rounded-lg px-4 text-sm text-zinc-400">
|
||||
Compartilhar no WhatsApp
|
||||
</button>
|
||||
</div>
|
||||
<p class="mt-2 text-xs text-zinc-500">
|
||||
O link compartilhado é o mesmo da página pública: /corte/123
|
||||
</p>
|
||||
|
||||
<!-- Editar título e descrição -->
|
||||
<section class="mt-6 rounded-xl border border-zinc-800 p-4">
|
||||
<h3 class="text-sm font-medium">Editar título e descrição</h3>
|
||||
<p class="mt-0.5 text-xs text-zinc-500">
|
||||
O que você salvar aqui aparece na página pública e no preview do link.
|
||||
</p>
|
||||
|
||||
<div class="mt-4 flex flex-col gap-1.5">
|
||||
<span class="text-sm text-zinc-300">Título</span>
|
||||
<div
|
||||
class="flex h-11 items-center rounded-lg border border-zinc-700 px-3 text-sm text-zinc-200"
|
||||
>
|
||||
Saúde pública no interior da Bahia
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-3 flex flex-col gap-1.5">
|
||||
<span class="text-sm text-zinc-300">Descrição</span>
|
||||
<div
|
||||
class="h-24 rounded-lg border border-zinc-700 p-3 text-sm text-zinc-300"
|
||||
>
|
||||
O deputado fala sobre o acesso a medicamentos no interior e defende o
|
||||
financiamento tripartite da saúde.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-3 flex items-center justify-end gap-2">
|
||||
<button
|
||||
type="button"
|
||||
class="h-11 rounded-lg border border-zinc-700 px-4 text-sm text-zinc-300"
|
||||
>
|
||||
Descartar
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="h-11 rounded-lg bg-amber-500 px-4 text-sm font-medium text-zinc-950"
|
||||
>
|
||||
Salvar alterações
|
||||
</button>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<aside class="space-y-4">
|
||||
<section class="rounded-xl border border-zinc-800 p-4">
|
||||
<h3 class="text-xs tracking-wide text-zinc-500 uppercase">
|
||||
Discurso de origem
|
||||
</h3>
|
||||
<p class="mt-1.5 text-sm text-zinc-200">Breves Comunicações · 11/08/2026</p>
|
||||
<p class="mt-1 text-xs text-zinc-500">Trecho 00:43–01:55 da fala</p>
|
||||
<p
|
||||
class="mt-2 text-sm underline decoration-zinc-700 underline-offset-4 text-zinc-300"
|
||||
>
|
||||
Ver fala no acervo
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section class="rounded-xl border border-zinc-800 p-4">
|
||||
<h3 class="text-xs tracking-wide text-zinc-500 uppercase">Publicação</h3>
|
||||
<div class="mt-2 flex items-center gap-2">
|
||||
<span
|
||||
class="rounded-md border border-amber-500/40 bg-amber-500/10 px-2 py-0.5 text-xs font-medium text-amber-400"
|
||||
>Publicado</span
|
||||
>
|
||||
</div>
|
||||
<p class="mt-2 text-xs text-zinc-500">
|
||||
Despublicado, o link público para de funcionar para quem já recebeu.
|
||||
</p>
|
||||
<button
|
||||
type="button"
|
||||
class="mt-3 h-11 w-full rounded-lg border border-zinc-700 px-4 text-sm text-zinc-300"
|
||||
>
|
||||
Despublicar
|
||||
</button>
|
||||
</section>
|
||||
|
||||
<section class="rounded-xl border border-dashed border-zinc-800 p-4">
|
||||
<h3 class="text-xs tracking-wide text-zinc-500 uppercase">
|
||||
Variante · despublicado
|
||||
</h3>
|
||||
<div class="mt-2">
|
||||
<span
|
||||
class="rounded-md border border-dashed border-zinc-600 px-2 py-0.5 text-xs text-zinc-400"
|
||||
>Despublicado</span
|
||||
>
|
||||
</div>
|
||||
<p class="mt-2 text-xs text-zinc-500">
|
||||
Despublicado, o link público não responde.
|
||||
</p>
|
||||
<button
|
||||
type="button"
|
||||
class="mt-3 h-11 w-full rounded-lg bg-amber-500 px-4 text-sm font-medium text-zinc-950"
|
||||
>
|
||||
Publicar corte
|
||||
</button>
|
||||
</section>
|
||||
</aside>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ============================================================ -->
|
||||
<!-- Cena 4 · desktop — confirmação de despublicar -->
|
||||
<!-- ============================================================ -->
|
||||
<section class="mt-10">
|
||||
<p class="text-xs tracking-wide text-zinc-500 uppercase">
|
||||
Cena 4 · desktop — confirmação de despublicar (kill switch)
|
||||
</p>
|
||||
<div
|
||||
class="mt-3 overflow-hidden rounded-xl border border-zinc-800 bg-zinc-950/70 p-6 sm:p-10"
|
||||
>
|
||||
<div class="mx-auto max-w-md rounded-xl border border-zinc-800 bg-zinc-900">
|
||||
<div class="border-b border-zinc-800 p-4">
|
||||
<div class="flex flex-wrap items-center gap-2">
|
||||
<h2 class="text-sm font-medium">Despublicar este corte?</h2>
|
||||
<span
|
||||
class="rounded-md border border-amber-500/40 bg-amber-500/10 px-2 py-0.5 text-xs font-medium text-amber-400"
|
||||
>Publicado</span
|
||||
>
|
||||
</div>
|
||||
<p class="mt-1 text-xs text-zinc-500">Saúde pública no interior da Bahia</p>
|
||||
</div>
|
||||
<div class="p-4">
|
||||
<p class="text-sm text-zinc-300">
|
||||
O link público deixa de funcionar para quem já recebeu. Você pode publicar de novo
|
||||
quando quiser.
|
||||
</p>
|
||||
<p class="mt-2 text-xs text-zinc-500">
|
||||
O corte continua na biblioteca como despublicado.
|
||||
</p>
|
||||
</div>
|
||||
<div class="flex items-center justify-end gap-2 border-t border-zinc-800 p-4">
|
||||
<button
|
||||
type="button"
|
||||
class="h-11 rounded-lg border border-zinc-700 px-4 text-sm text-zinc-300"
|
||||
>
|
||||
Cancelar
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="h-11 rounded-lg bg-amber-500 px-4 text-sm font-medium text-zinc-950"
|
||||
>
|
||||
Despublicar
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ============================================================ -->
|
||||
<!-- Cena 5 · mobile (~390px) — lista e detalhe -->
|
||||
<!-- ============================================================ -->
|
||||
<section class="mt-10">
|
||||
<p class="text-xs tracking-wide text-zinc-500 uppercase">
|
||||
Cena 5 · mobile (~390px) — lista de cortes e detalhe
|
||||
</p>
|
||||
<div class="mt-3 flex flex-wrap items-start gap-6">
|
||||
<!-- Lista mobile -->
|
||||
<div
|
||||
class="w-[390px] max-w-full overflow-hidden rounded-xl border border-zinc-800 bg-zinc-900"
|
||||
>
|
||||
<div
|
||||
class="flex items-center justify-between border-b border-zinc-800 px-4 py-3 text-sm"
|
||||
>
|
||||
<span class="text-xs text-zinc-500">← Acervo</span>
|
||||
<span class="font-medium">Cortes</span>
|
||||
<span class="text-xs text-zinc-500">12</span>
|
||||
</div>
|
||||
<div class="p-4">
|
||||
<div
|
||||
class="flex items-center gap-2 rounded-lg border border-zinc-800 bg-zinc-950 p-2"
|
||||
>
|
||||
<svg
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
class="size-4 shrink-0 text-zinc-500"
|
||||
>
|
||||
<circle cx="11" cy="11" r="7" />
|
||||
<path d="m20 20-3.5-3.5" />
|
||||
</svg>
|
||||
<span class="text-sm text-zinc-500">Buscar por título ou descrição…</span>
|
||||
</div>
|
||||
|
||||
<div class="mt-3 flex flex-col gap-3">
|
||||
<article class="rounded-xl border border-zinc-800 bg-zinc-900 p-3">
|
||||
<div class="flex flex-wrap items-center gap-2">
|
||||
<span
|
||||
class="rounded-md border border-amber-500/40 bg-amber-500/10 px-2 py-0.5 text-[10px] font-medium text-amber-400"
|
||||
>Publicado</span
|
||||
>
|
||||
<span class="text-[11px] text-zinc-500">Criado em 12/08/2026</span>
|
||||
</div>
|
||||
<h3 class="mt-2 text-sm font-medium text-zinc-100">
|
||||
Saúde pública no interior da Bahia
|
||||
</h3>
|
||||
<p class="mt-1 text-[11px] text-zinc-400">
|
||||
Fala · Breves Comunicações · 11/08/2026 · 1min12s
|
||||
</p>
|
||||
<p
|
||||
class="mt-1 text-[11px] underline decoration-zinc-700 underline-offset-4 text-zinc-300"
|
||||
>
|
||||
Ver fala no acervo
|
||||
</p>
|
||||
<div class="mt-2 flex items-center gap-2">
|
||||
<button
|
||||
type="button"
|
||||
class="min-h-10 flex-1 rounded-lg border border-zinc-700 px-3 text-sm text-zinc-200"
|
||||
>
|
||||
Abrir corte
|
||||
</button>
|
||||
<button type="button" class="min-h-10 rounded-lg px-3 text-sm text-zinc-400">
|
||||
Copiar link
|
||||
</button>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<article class="rounded-xl border border-dashed border-zinc-800 bg-zinc-900 p-3">
|
||||
<div class="flex flex-wrap items-center gap-2">
|
||||
<span
|
||||
class="rounded-md border border-dashed border-zinc-600 px-2 py-0.5 text-[10px] text-zinc-400"
|
||||
>Despublicado</span
|
||||
>
|
||||
<span class="text-[11px] text-zinc-500">Criado em 08/08/2026</span>
|
||||
</div>
|
||||
<h3 class="mt-2 text-sm font-medium text-zinc-100">Obras e emprego na Bahia</h3>
|
||||
<p class="mt-1 text-[11px] text-zinc-400">
|
||||
Fala · Breves Comunicações · 08/08/2026 · 45s
|
||||
</p>
|
||||
<p
|
||||
class="mt-1 text-[11px] underline decoration-zinc-700 underline-offset-4 text-zinc-300"
|
||||
>
|
||||
Ver fala no acervo
|
||||
</p>
|
||||
<div class="mt-2 flex items-center gap-2">
|
||||
<button
|
||||
type="button"
|
||||
class="min-h-10 flex-1 rounded-lg border border-zinc-700 px-3 text-sm text-zinc-200"
|
||||
>
|
||||
Abrir corte
|
||||
</button>
|
||||
<button type="button" class="min-h-10 rounded-lg px-3 text-sm text-zinc-400">
|
||||
Copiar link
|
||||
</button>
|
||||
</div>
|
||||
</article>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="mt-3 flex items-center justify-between border-t border-zinc-800 pt-3 text-[11px] text-zinc-500"
|
||||
>
|
||||
<span>1–3 de 12</span>
|
||||
<span>Página 1 de 4</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Detalhe mobile -->
|
||||
<div
|
||||
class="w-[390px] max-w-full overflow-hidden rounded-xl border border-zinc-800 bg-zinc-900"
|
||||
>
|
||||
<div
|
||||
class="flex items-center justify-between border-b border-zinc-800 px-4 py-3 text-sm"
|
||||
>
|
||||
<span class="text-xs text-zinc-500">← Cortes</span>
|
||||
<span class="font-medium">Corte</span>
|
||||
<span class="text-xs text-zinc-500">···</span>
|
||||
</div>
|
||||
<div class="p-4">
|
||||
<h2 class="text-sm font-medium">Saúde pública no interior da Bahia</h2>
|
||||
<p class="mt-1 text-[11px] text-zinc-400">Corte de 1min12s · criado em 12/08/2026</p>
|
||||
|
||||
<div
|
||||
class="relative mt-3 flex aspect-video w-full items-center justify-center rounded-lg border border-zinc-800 bg-zinc-950"
|
||||
>
|
||||
<div
|
||||
class="flex size-10 items-center justify-center rounded-full border border-zinc-700 text-sm text-zinc-300"
|
||||
>
|
||||
▶
|
||||
</div>
|
||||
<span class="absolute bottom-2 left-2 text-[10px] text-zinc-500">01:12</span>
|
||||
</div>
|
||||
|
||||
<div class="mt-3 flex flex-col gap-2">
|
||||
<button
|
||||
type="button"
|
||||
class="min-h-11 w-full rounded-lg bg-amber-500 px-4 text-sm font-medium text-zinc-950"
|
||||
>
|
||||
Baixar vídeo (MP4)
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="min-h-11 w-full rounded-lg border border-zinc-700 px-4 text-sm text-zinc-300"
|
||||
>
|
||||
Abrir página pública
|
||||
</button>
|
||||
<div class="flex gap-2">
|
||||
<button
|
||||
type="button"
|
||||
class="min-h-11 flex-1 rounded-lg px-3 text-sm text-zinc-400"
|
||||
>
|
||||
Copiar link
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="min-h-11 flex-1 rounded-lg px-3 text-sm text-zinc-400"
|
||||
>
|
||||
WhatsApp
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<section class="mt-4 rounded-xl border border-zinc-800 p-3">
|
||||
<h3 class="text-[11px] tracking-wide text-zinc-500 uppercase">
|
||||
Discurso de origem
|
||||
</h3>
|
||||
<p class="mt-1 text-sm text-zinc-200">Breves Comunicações · 11/08/2026</p>
|
||||
<p class="mt-0.5 text-[11px] text-zinc-500">Trecho 00:43–01:55 da fala</p>
|
||||
<p
|
||||
class="mt-1.5 text-sm underline decoration-zinc-700 underline-offset-4 text-zinc-300"
|
||||
>
|
||||
Ver fala no acervo
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section class="mt-3 rounded-xl border border-zinc-800 p-3">
|
||||
<h3 class="text-[11px] tracking-wide text-zinc-500 uppercase">Publicação</h3>
|
||||
<div class="mt-1.5">
|
||||
<span
|
||||
class="rounded-md border border-amber-500/40 bg-amber-500/10 px-2 py-0.5 text-[10px] font-medium text-amber-400"
|
||||
>Publicado</span
|
||||
>
|
||||
</div>
|
||||
<p class="mt-1.5 text-[11px] text-zinc-500">
|
||||
Despublicado, o link público para de funcionar para quem já recebeu.
|
||||
</p>
|
||||
<button
|
||||
type="button"
|
||||
class="mt-2 h-11 w-full rounded-lg border border-zinc-700 px-4 text-sm text-zinc-300"
|
||||
>
|
||||
Despublicar
|
||||
</button>
|
||||
</section>
|
||||
|
||||
<section class="mt-3 rounded-xl border border-zinc-800 p-3">
|
||||
<h3 class="text-sm font-medium">Editar título e descrição</h3>
|
||||
<div class="mt-3 flex flex-col gap-1.5">
|
||||
<span class="text-[11px] text-zinc-400">Título</span>
|
||||
<div
|
||||
class="flex min-h-11 items-center rounded-lg border border-zinc-700 px-3 text-sm text-zinc-200"
|
||||
>
|
||||
Saúde pública no interior da Bahia
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-3 flex flex-col gap-1.5">
|
||||
<span class="text-[11px] text-zinc-400">Descrição</span>
|
||||
<div class="min-h-20 rounded-lg border border-zinc-700 p-3 text-sm text-zinc-300">
|
||||
O deputado fala sobre o acesso a medicamentos no interior.
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
class="mt-3 h-11 w-full rounded-lg bg-amber-500 px-4 text-sm font-medium text-zinc-950"
|
||||
>
|
||||
Salvar alterações
|
||||
</button>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
108
docs/plans/c168-biblioteca-cortes.md
Normal file
108
docs/plans/c168-biblioteca-cortes.md
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
# Acervo: biblioteca de cortes (origem, download, compartilhar, editar título/descrição)
|
||||
|
||||
Status: rascunho
|
||||
Atualizado em: 2026-09-15
|
||||
Issue: #1015
|
||||
Priority: P2
|
||||
Impeccable: C — fluxo novo na vertical Comunicação (lista + detalhe de cortes)
|
||||
Rascunho UI: docs/plans/c168-biblioteca-cortes-ui-draft.html
|
||||
Appetite: ~1–1,5 dia eng; um outcome verificável — a assessoria reencontra um corte antigo, edita o texto e republica sem refazer o corte
|
||||
Responsável: —
|
||||
|
||||
## Intenção
|
||||
|
||||
O corte feito hoje morre no instante em que é enviado: existe para quem recebeu o link e some do radar da assessoria. Reaproveitar um corte antigo — outro formato, outra legenda, o mesmo vídeo — significa refazer o corte do zero (reabrir a fala, achar o trecho, gerar de novo) ou garimpar conversas atrás do link. Este item dá à vertical Comunicação uma biblioteca do que já foi cortado: cada corte guarda o discurso de origem e pode ser reencontrado, ter o texto ajustado, ser baixado, compartilhado e publicado/despublicado sem refazer o vídeo.
|
||||
|
||||
## Persona e fluxo
|
||||
|
||||
- **Persona / contexto:** assessoria de comunicação (`communicator`) e coordenação/candidatura, na mesa ou no celular, sob prazo de peça; quem não é da vertical (`advisor`, `leader`) segue negado.
|
||||
- **Job principal:** "reencontrar um corte que eu já fiz, ajustar o texto e republicar — sem refazer o corte".
|
||||
- **Fluxo desejado:** abre Comunicação → Acervo → Cortes → vê os cortes mais recentes (ou busca por título/descrição) → abre um corte → assiste e confere o discurso de origem → edita título/descrição e salva → baixa, copia o link ou compartilha no WhatsApp → publica/despublica → a página pública reflete o texto e o estado.
|
||||
- **Anti-goals de produto:** não virar editor de vídeo (nada de trocar início/fim ou re-render); não ser um segundo acervo de falas; sem comentários, versionamento, coleções/kits, favoritos ou métricas; sem deletar pela UI.
|
||||
|
||||
### Esboço de fluxo (C)
|
||||
|
||||
```text
|
||||
[lista de cortes: recentes primeiro + busca por título/descrição]
|
||||
→ abre o detalhe do corte → assiste e confere o discurso de origem (link)
|
||||
→ edita título/descrição → salva (a página pública reflete)
|
||||
→ baixa MP4 / copia link / WhatsApp / publica-despublica (kill switch)
|
||||
→ [outcome: reencontrou, reaproveitou e republicou sem refazer o corte]
|
||||
```
|
||||
|
||||
### Rascunho UI (C)
|
||||
|
||||
- Rascunho UI (gate): `docs/plans/c168-biblioteca-cortes-ui-draft.html` — cenas: lista de cortes desktop e vazia; detalhe com player, origem, edição e ações; confirmação de despublicar; mobile.
|
||||
|
||||
## Objetivo e aceite
|
||||
|
||||
- Existe `/campanha/comunicacao/acervo/cortes`: cortes mais recentes primeiro, cada item com título, discurso de origem (tipo + data, com link para a fala), duração, status (publicado/despublicado) e data de criação; busca por título/descrição e paginação padrão da casa.
|
||||
- O detalhe do corte mostra o player, o discurso de origem com link e o título/descrição editáveis; salvar reflete na página pública e no preview, sem passo extra.
|
||||
- No detalhe também se baixa o corte (MP4), copia-se o link e compartilha-se no WhatsApp; o link compartilhado é o mesmo da página pública.
|
||||
- Publicar/despublicar pela página interna com aviso explícito: despublicado, o link público para de funcionar; o estado aparece na lista.
|
||||
- **Guardrails de produto:** leem/editam `communicator`, `coordinator` e `candidate`; `advisor` e `leader` ficam de fora (fail-closed). Deletar corte não existe na UI (admin pode). Editar o texto do corte nunca altera a fala original nem o vídeo.
|
||||
|
||||
## Dados (intenção)
|
||||
|
||||
- **Vou apresentar dados?** Não — recorte operacional de itens existentes (lista paginada); status publicado/despublicado é estado do item, não KPI.
|
||||
- **Decisões desbloqueadas:** a assessoria escolhe qual corte reaproveitar, o que ajustar no texto e o que manter no ar; nenhuma leitura agregada nova.
|
||||
- **Forma:** _adiada ao plano de implementação_ — aqui só a restrição de produto: sem métricas de vaidade (views/downloads) nem contadores de acervo.
|
||||
|
||||
## Dados da decisão (literais)
|
||||
|
||||
- Rotas internas: `/campanha/comunicacao/acervo/cortes` (lista) e `/campanha/comunicacao/acervo/cortes/[id]` (detalhe).
|
||||
- Acesso: `communicator`, `coordinator` e `candidate` leem e editam título/descrição/publicação; `advisor` e `leader` negados (fail-closed).
|
||||
- Lista: mais recentes primeiro; cada item mostra título, discurso de origem (tipo + data, com link para a fala), duração, status (publicado/despublicado) e data de criação; busca por título/descrição; paginação padrão da casa.
|
||||
- Aviso de despublicar (texto de produto): título "Despublicar este corte?" e corpo "O link público deixa de funcionar para quem já recebeu. Você pode publicar de novo quando quiser." — botões "Cancelar" e "Despublicar".
|
||||
- Vazio da lista: "Nenhum corte ainda" + caminho para o acervo de falas.
|
||||
- Publicar/despublicar é kill switch: despublicado, o link público para de funcionar; republicar restaura o mesmo link (o corte continua na biblioteca).
|
||||
- Sem deletar corte pela UI (admin pode); sem comentários, versionamento, coleções/kits ou métricas de vaidade.
|
||||
|
||||
## Direção no codebase (hipótese)
|
||||
|
||||
- **Áreas prováveis:** rotas em `src/app/(campaign)/campanha/(app)/comunicacao/acervo/cortes/` (lista + `[id]`), paths em `src/lib/campaignPaths.ts`, chrome em `src/lib/campaignPageChrome.ts`, componentes na vertical (`src/components/campaign/speech/` ou domínio irmão) e utilitários de leitura/estado ao lado do acervo.
|
||||
- **Precedente a olhar:** acervo de falas — `acervo/page.tsx` (lista paginada + vazio + footer), `SpeechAcervoFilters.tsx`/`speechListUrl.ts` (busca e estado na URL), `SpeechResultCard.tsx`, `SpeechDetailPlayer.tsx` (player, baixar/abrir fonte) e o detalhe `acervo/[id]/page.tsx`; chrome `campaignPageChrome.ts`; nav do communicator em `src/components/campaign/shell/nav.ts`.
|
||||
- **Risco de acoplamento:** o `communicator` lê mas não atualiza a fala (`canUpdateSpeech` é de papéis unrestricted) — o texto editável é o do corte, não o da fala; não misturar com o where/ordenação da lista de falas; leader/advisor lockdown e gate `speechCatalog` intocados; a página pública `/corte/<id>` é do C167 (aqui só se reflete).
|
||||
|
||||
## Dependências
|
||||
|
||||
- **Dura: C167** — sem o corte salvo no servidor e a página pública `/corte/<id>`, não há o que listar, baixar, compartilhar nem publicar/despublicar.
|
||||
- **Indireta: C166** — seleção de trecho [início,fim] e compartilhamento por link do YouTube: é o passo anterior do fluxo; o compartilhar da biblioteca é o link público do corte, não o link do YouTube.
|
||||
- Suaves: C154/C153 (acervo de falas, gate e chrome) e a vertical Comunicação.
|
||||
|
||||
## Fora de escopo
|
||||
|
||||
- Editar o corte (trocar início/fim, re-render, editor de vídeo).
|
||||
- Deletar/arquivar corte pela UI (admin pode), lixeira e desfazer.
|
||||
- Comentários, versionamento/histórico, coleções/kits/playlists, favoritos e métricas (views/downloads).
|
||||
- Qualquer mudança na página pública além de refletir título/descrição/publicação (a superfície é do C167).
|
||||
- Ações em lote (baixar/publicar/editar vários) e exportação.
|
||||
|
||||
## Rabbit holes de produto
|
||||
|
||||
- **"Já que tem a lista, deixa ajustar o corte (início/fim)."** Se alguém "só completar": editor/re-render e fila de processamento. **Corte neste item:** só título/descrição/publicação; o vídeo é imutável.
|
||||
- **"Coleções/kits por tema para organizar."** Se alguém "só completar": segunda taxonomia e curadoria. **Corte neste item:** lista única com busca.
|
||||
- **"Mostrar views/downloads de cada corte."** Se alguém "só completar": dashboard de vaidade sem decisão nomeável. **Corte neste item:** sem métricas.
|
||||
- **"Soft delete/desfazer despublicar."** Se alguém "só completar": versionamento e lixeira. **Corte neste item:** kill switch; republicar resolve.
|
||||
- **"Compartilhar em todas as redes."** Se alguém "só completar": integrações e SDKs. **Corte neste item:** copiar link + WhatsApp (o que o produto pediu).
|
||||
|
||||
## Questões em aberto (produto)
|
||||
|
||||
- **Aba/segmento na lista do acervo (Falas | Cortes) ou rota separada?** **Opções:** A) rota separada `/acervo/cortes` com link no acervo | B) abas na mesma tela. **Recomendação: A** — recortes, filtros e ordenação diferentes; misturar paginação e estado de URL confunde. _(assumido — validar no gate)_
|
||||
- **Busca na biblioteca?** **Opções:** A) busca simples por título/descrição | B) sem busca nesta fatia. **Recomendação: A** — é o job do item (reencontrar); barra padrão da casa. _(assumido — validar)_
|
||||
- **Ordenação?** **Opções:** A) mais recentes primeiro | B) agrupar por discurso de origem. **Recomendação: A** — o corte é a unidade; a origem é contexto do item, com link para a fala.
|
||||
- **Quem pode editar título/descrição?** **Opções:** A) qualquer um com acesso ao acervo (communicator+) | B) só quem criou + coordenação. **Recomendação:** A — equipe pequena; o kill switch cobre abuso. _(assumido — validar)_
|
||||
- **Despublicar apaga ou só desativa o link?** **Opções:** A) desativa; republicar restaura o mesmo link | B) apaga o corte público. **Recomendação:** A — reverter é barato e o corte continua na biblioteca.
|
||||
|
||||
## Referências
|
||||
|
||||
- GitHub Issue: — (após `pnpm agent:register`)
|
||||
- Rascunho UI (gate): `docs/plans/c168-biblioteca-cortes-ui-draft.html`
|
||||
- `src/app/(campaign)/campanha/(app)/comunicacao/acervo/page.tsx` · `acervo/[id]/page.tsx` · `src/components/campaign/speech/` (filtros, card, player) · `src/utilities/speech/speechListUrl.ts`/`speechPageData.ts`
|
||||
- `src/lib/campaignPageChrome.ts` · `src/lib/campaignPaths.ts` · `src/utilities/campaignPageActor.ts` (gate `speechCatalog`) · `src/utilities/access/speeches.ts` · `src/components/campaign/shell/nav.ts`
|
||||
- `tests/int/speechCatalog.int.spec.ts` · e2e `campaignSpeechAcervo`
|
||||
- `AGENTS.md` — vertical Comunicação, leader lockdown, naming/i18n
|
||||
|
||||
## Self-score (shaping)
|
||||
|
||||
5/5 — (1) fatia com um outcome verificável: reencontrar/editar/republicar um corte sem refazer o corte; (2) appetite ~1–1,5 dia declarado e o escopo cabe (reuso do acervo, sem editor nem taxonomia nova); (3) persona, job e aceite em linguagem de usuário; (4) direção no codebase é hipótese com precedente nomeado, sem contrato; (5) zero decisão dura de engenharia (sem schema/collection/migration/signature).
|
||||
Loading…
Reference in a new issue