feat: menus mobile corrigidos, sincronia multi-dispositivo e editor WYSIWYG
- Menus: dropdowns agora com position:fixed posicionado via JS — no celular
o overflow-x:auto da menubar cortava os itens (bug relatado)
- Sincronia celular/desktop: PUT aceita base_hash opcional; divergência →
409 {server_hash} e diálogo "Conflito de edição" (recarregar | salvar por
cima); abas limpas recarregam sozinhas no focus/visibilitychange (debounce)
- WYSIWYG (Ctrl+M): contenteditable com render md→html no servidor e
serialização html→md própria (títulos, negrito/itálico/tachado, listas
com task, citação, código, blocos, links, tabelas, entidades); HTML edita
preservando tags/atributos, sanitizando script/on* na entrada; toolbar
usa execCommand no modo rico; colar é sempre texto puro; txt não aplica
- store/api: ErrConflict + teste de conflito na store e na API
- README: WYSIWYG, sincronia, base_hash, nota do fix de menu
This commit is contained in:
1 parent
8b355e8edb
commit
3b91c1a509
8 files changed
+456
-57
No files matched your search
@@ -41,8 +41,12 @@ ocupa a tela inteira; menus e toolbar rolam horizontalmente com botões só de
|
||||
- **Barra de ferramentas de formatação**: negrito, itálico, tachado, títulos H1/H2, listas,
|
||||
citação, link, código inline e bloco de código — inserindo sintaxe Markdown **ou** HTML conforme
|
||||
o formato ativo (desabilitada em texto puro).
|
||||
- **Modo Edição ↔ Preview**: Markdown é renderizado no servidor (goldmark, GFM, HTML cru escapado);
|
||||
HTML é pré-visualizado em `<iframe sandbox>`; texto puro é exibido como está.
|
||||
- **Modo Edição ↔ WYSIWYG ↔ Preview** (`Ctrl+E/M/R`): o WYSIWYG (`Ctrl+M`) renderiza a nota num
|
||||
`contenteditable` e sincroniza com o fonte a cada tecla — Markdown vira HTML editável (negrito,
|
||||
títulos, listas, citação, código, links, tabelas) e volta a Markdown ao editar/alternar; HTML é
|
||||
editado visualmente com tags/atributos preservados (scripts e `on*` são removidos ao abrir).
|
||||
O Preview renderiza Markdown no servidor (goldmark, GFM, HTML cru escapado); HTML em
|
||||
`<iframe sandbox>`; texto puro como está. Em texto puro o WYSIWYG não se aplica.
|
||||
- **Categorias como árvore de pastas**: o painel lateral traz um explorador de arquivos —
|
||||
categorias aninhadas (subpastas), expansão/colapso, contagem de notas por pasta e menu de
|
||||
contexto (Nova subpasta / Renomear / Excluir, sem ciclos). Uma nota pode pertencer a
|
||||
@@ -78,18 +82,27 @@ ocupa a tela inteira; menus e toolbar rolam horizontalmente com botões só de
|
||||
(autor, data, mensagem, hash SHA-256 e parent). O painel de histórico mostra o **diff unificado**
|
||||
de cada revisão e permite **restaurar** qualquer versão anterior (a restauração vira uma nova
|
||||
revisão — nada se perde). Conteúdo idêntico é deduplicado (content-addressed).
|
||||
- **Sincronia entre dispositivos** (celular + desktop no mesmo servidor):
|
||||
- Cada aba lembra o hash em que se baseia (`base_hash`). Ao salvar, se o servidor mudou desde
|
||||
então, a API responde **409** e a UI abre o diálogo **Conflito de edição** com as duas saídas:
|
||||
*Recarregar do servidor* (descarta o texto local) ou *Salvar por cima* (a versão remota fica
|
||||
no histórico e é restaurável).
|
||||
- Abas **sem edição pendente** são recarregadas automaticamente quando a janela volta ao foco
|
||||
(`visibilitychange`/`focus`, com debounce), com aviso discreto.
|
||||
- **Autenticação por token**: sem token, a interface exibe um diálogo pedindo o token; ele é
|
||||
guardado em **cookie HttpOnly/SameSite=Lax** (30 dias). A API também aceita
|
||||
`Authorization: Bearer <token>` para scripts.
|
||||
- **Responsivo para celular** (≤760px): barra lateral vira gaveta com backdrop (☰ fecha ao
|
||||
tocar uma nota), painel de versões ocupa a tela toda, toolbar e menus rolam horizontalmente
|
||||
sem rótulos, alvos de toque ampliados, diálogos em largura total, fonte do editor com mínimo
|
||||
de 16px (evita zoom automático do iOS), altura em `dvh` e `safe-area-inset` para notch.
|
||||
sem rótulos, **dropdowns dos menus posicionados como `fixed`** (o `overflow-x` da menubar não
|
||||
os corta mais em telas pequenas), alvos de toque ampliados, diálogos em largura total, fonte
|
||||
do editor com mínimo de 16px (evita zoom automático do iOS), altura em `dvh` e
|
||||
`safe-area-inset` para notch.
|
||||
- **Estilo Mousepad**: tema claro Greybird-like, menus nativos (Arquivo/Editar/Exibir/Ajuda),
|
||||
atalhos `Ctrl+S`, `Ctrl+N`, `Ctrl+E/R` (editar/preview), `Ctrl+H` (histórico), `F9` (barra
|
||||
lateral), `Ctrl+B/I/K` (formatação), `Ctrl+,` (preferências), `Alt+W`/`Alt+←/→`/`Alt+1..9`
|
||||
(abas), barra de status com arquivo, formato, linha/coluna, contagem de palavras e estado de
|
||||
salvamento.
|
||||
atalhos `Ctrl+S`, `Ctrl+N`, `Ctrl+E/M/R` (edição/wysiwyg/preview), `Ctrl+H` (histórico), `F9`
|
||||
(barra lateral), `Ctrl+B/I/K` (formatação), `Ctrl+,` (preferências), `Alt+W`/`Alt+←/→`/
|
||||
`Alt+1..9` (abas), barra de status com arquivo, formato, linha/coluna, contagem de palavras e
|
||||
estado de salvamento.
|
||||
|
||||
## Estrutura do projeto
|
||||
|
||||
@@ -160,8 +173,10 @@ curl -H "Authorization: Bearer $T" $B/api/notes/<id> # nota + conteú
|
||||
curl -s -X POST -H "Authorization: Bearer $T" -H 'Content-Type: application/json' \
|
||||
-d '{"title":"Olá","format":"md","categories":["<id>"],"content":"# Oi #linux"}' $B/api/notes
|
||||
curl -X PUT -H "Authorization: Bearer $T" -H 'Content-Type: application/json' \
|
||||
-d '{"title":"Olá","format":"md","categories":["<id>"],"content":"editado","author":"lg","message":"revisão 2"}' \
|
||||
-d '{"title":"Olá","format":"md","categories":["<id>"],"content":"editado","author":"lg","message":"revisão 2","base_hash":"<hash carregado>"}' \
|
||||
$B/api/notes/<id>
|
||||
# base_hash é opcional: se enviado e diferente do atual → 409 {error, server_hash, updated_at}
|
||||
# (omitir/enviar vazio = força o salvamento)
|
||||
curl -H "Authorization: Bearer $T" $B/api/notes/<id>/revisions # histórico
|
||||
curl -H "Authorization: Bearer $T" $B/api/notes/<id>/revisions/<hash>/diff # diff unificado
|
||||
curl -X POST -H "Authorization: Bearer $T" $B/api/notes/<id>/revisions/<hash>/restore \
|
||||
|
||||
Reference in new issue
Block a user