// JanelaApp: a "gravação": um app de lista nítido (janela 1400 × 940 com barra, lateral e lista) que
// MUDA DE ESTADO por quadros, sempre causado pelo clique do cursor: o botão afunda, o modal abre,
// o texto é digitado com cursor de texto, o Salvar afunda, o modal fecha e a linha nova entra no topo
// com fundo de destaque. Pontos úteis pra câmera e cursor: veja ALVOS (coordenadas da janela).
import React from 'react';
import {useCurrentFrame} from 'remotion';
import {COR, FONTE, JANELA, MONO, e5, lerp, mola, seg} from '../base';
export const ALVOS = {botao: [1230, 124], campo: [850, 440], salvar: [1060, 568], novaLinha: [850, 242]} as const;
export type JanelaAppProps = {
endereco?: string;
lateral?: string[];
titulo: string;
/** "{n} tarefas": {n} vira o número de itens */
subtitulo?: string;
botao: string;
itens: {texto: string; tag?: string}[];
modal: {titulo: string; placeholder: string; texto: string; botao: string; tag?: string};
/** quadros (relativos à gravação): clique no botão, digitação [de, até], clique em salvar */
tempos: {abre: number; digita: [number, number]; salva: number};
};
const Linha: React.FC<{texto: string; tag?: string; y: number; h?: number; destaque?: number; check?: number}> = ({texto, tag, y, h = 84, destaque = 0, check = 0}) =>
0 ? `rgba(255,91,20,${0.14 * destaque})` : undefined, boxShadow: destaque > 0 ? `inset 0 0 0 2px rgba(255,91,20,${0.5 * destaque})` : undefined}}>
0 ? COR.ok : '#C7CCD4'}`, boxSizing: 'border-box', background: check > 0.5 ? COR.ok : undefined, transform: `scale(${check > 0 ? mola(check) : 1})`}} />
{texto}
{tag &&
{tag}
}
;
export const JanelaApp: React.FC
= ({endereco = 'pauta.app', lateral = ['Hoje', 'Próximos', 'Projetos', 'Arquivo'], titulo, subtitulo = '{n} tarefas', botao, itens, modal, tempos}) => {
const f = useCurrentFrame();
const apertaB = f >= tempos.abre && f < tempos.abre + 4 ? 0.94 : 1;
const abre = e5(seg(f, tempos.abre + 1, tempos.abre + 9)), fecha = seg(f, tempos.salva + 2, tempos.salva + 8);
const mod = abre * (1 - fecha);
const [d0, d1] = tempos.digita;
const n = Math.round(lerp(0, modal.texto.length, seg(f, d0, d1)));
const caret = f < d0 + 1 || n < modal.texto.length || Math.floor(f / 8) % 2 === 0;
const apertaS = f >= tempos.salva && f < tempos.salva + 4 ? 0.92 : 1;
const entra = e5(seg(f, tempos.salva + 6, tempos.salva + 16));
const brilho = 1 - seg(f, tempos.salva + 30, tempos.salva + 60);
const total = itens.length + (entra > 0 ? 1 : 0);
const Y0 = 210;
return
{/* barra */}
{['#FF5F57', '#FEBC2E', '#28C840'].map((c, i) =>
)}
{endereco}
{/* lateral */}
{lateral.map((l, i) =>
{l}
)}
{/* cabeçalho */}
{titulo}
{subtitulo.replace('{n}', String(total))}
{botao}
{/* lista */}
{entra > 0 &&
}
{itens.map((it, i) =>
)}
{/* modal */}
{mod > 0.01 && <>
{modal.titulo}
= d0 - 4 ? COR.acento : COR.linha}`, boxSizing: 'border-box',
boxShadow: f >= d0 - 4 ? `0 0 0 6px ${COR.acentoClaro}` : undefined, fontFamily: FONTE, fontWeight: 600, fontSize: 30, lineHeight: '74px', paddingLeft: 22, color: n ? COR.tinta : '#A3A9B3', whiteSpace: 'nowrap'}}>
{n ? modal.texto.slice(0, n) : f >= d0 - 4 ? '' : modal.placeholder}
{f >= d0 - 4 && caret && }
{modal.botao}
>}
;
};