Asas
Tipo de letra padrãoAltura


NABI NOTE

Um editor WYSIWYG de código aberto


NABI NOTE é um editor WYSIWYG de código aberto que separa do núcleo funções como formatação, alinhamento, tabelas e envio de arquivos em módulos independentes chamados wings. Você pode escolher apenas os wings necessários para montar o editor e conectar aqueles que criar. Ele é escrito em JavaScript puro, podendo ser usado em frameworks como React ou Vue. Em páginas sem ambiente de compilação, você pode começar diretamente com a biblioteca CDN. Seu formato de documento próprio, NABI TREE, pode ser convertido em HTML até mesmo em Node.js sem o DOM do navegador. Os documentos recebidos são normalizados conforme as regras registradas; ao gerar HTML, textos e atributos são escapados e os endereços dos links são verificados. Wings personalizados e dados recebidos do servidor ainda devem ser revisados separadamente conforme a política de segurança da aplicação. Variáveis CSS e um layout baseado em rem permitem ajustar tema e tamanho, com modo escuro e tipografias para vários idiomas. Ordenação de tabelas, histórico local e trabalho com documentos auxiliado por IA usam o mesmo modelo de documento.


Fonte

As famílias sem serifa (padrão), com serifa, monoespaçada e cursiva incluem fontes alternativas por idioma. Se não houver uma fonte adequada para a família escolhida, será usada a fonte padrão do navegador. A página que incorpora o editor define sua fonte padrão.


Abaixo, cada família mostrada em vários idiomas.


산세리프 · ゴシック体 · 无衬线 · Serifenlos · Sans empattement · Sin serifa · Sem serifa · Без засечек · بلا زخارف · सैन्स सेरिफ़ · স্যান্স সেরিফ · سانس سیرف · Tanpa serif · بدون سریف · सॅन्स सेरिफ · Không chân · శాన్స్ సెరిఫ్ · Mara seref · Sans serif · Bila serif · சான்ஸ் செரிஃப் · ไร้เชิง · Senza grazie


세리프 · 明朝体 · 衬线 · Serif · Avec empattement · Con serifa · Com serifa · С засечками · بزخارف · सेरिफ़ · সেরিফ · سیرف · Berserif · سریف · सेरिफ · Có chân · సెరిఫ్ · Mai seref · Yenye serif · செரிஃப் · มีเชิง · Con grazie


고정폭 · 等幅 · 等宽 · Dicktengleich · Chasse fixe · Monoespaciada · Monoespaçada · Моноширинный · ثابت العرض · मोनोस्पेस · মনোস্পেস · یکساں چوڑائی · Lebar tetap · تک‌فاصله · Đơn cách · మోనోస్పేస్ · Tazara ɗaya · Eş aralıklı · Nafasi moja · ஒற்றையகலம் · ความกว้างคงที่ · Monospaziato · Monospace


필기체 · 筆記体 · 手写体 · Schreibschrift · Cursive · Cursiva · Рукописный · خط اليد · हस्तलिपि · হস্তলিপি · رواں خط · Tulisan tangan · دست‌نویس · हस्ताक्षर · Chữ viết tay · చేతిరాత · Rubutun hannu · El yazısı · Mwandiko · கையெழுத்து · ลายมือ · Corsivo



Tamanho da letra

Muito pequeno

Pequeno

Grande

Muito grande



Título

Numa linha vazia escreva # e aperte espaço: na hora vira um título.

H1

H2

H3

H4

H5
H6



Negrito · Itálico · Sublinhado · Riscado

Negrito itálico sublinhado riscado podem ser aplicados juntos ao mesmo caractere.

Também dá para sobrepor.

Sobrescrito e subscrito

A área é de 3,5 m2, e uma nota fica assim1.

A água é H2O.



Cor do texto · Marcador

A paleta foi escolhida para ler bem tanto no claro quanto no escuro.

Cor do texto Verde · Coral · Violeta · Âmbar · Azul

Marcador Amarelo · Verde · Ciano · Rosa · Roxo · Laranja



Link

Ponha um endereço e vira um link.

Você pode usar URLs http:// e https://, além de caminhos do mesmo site que começam com . ou /. Endereços como javascript: não são permitidos.

Por exemplo, escreva https://nabi.saro.me e aperte espaço ou Enter: converte sozinho, como se vê aqui.

Abertura de links

O documento armazena apenas o endereço do link; a página que exibe o documento decide como os links são abertos.

Link de anexo

Arquivos que não são imagens permanecem como links de anexo, como o exemplo abaixo.

Anexo: o link é salvo no documento.



Alinhamento

À esquerda

Centralizado

À direita

Não é possível aplicar alinhamento aos títulos.



Listas

Lista com marcadores

Numa linha vazia escreva - e aperte espaço: na hora vira uma lista com marcadores.

  • Isto é um item

    • Tab / Shift+Tab recuam e voltam.

Lista numerada

Numa linha vazia escreva 1. e aperte espaço: sai uma lista numerada.

  1. Primeiro

  2. Segundo

  3. Terceiro

Lista de tarefas

Numa linha vazia escreva [ ] ou [x] e aperte espaço: sai uma lista de tarefas.

  • Esta tarefa está feita.

  • Esta ainda não.



Tabela

As células podem conter vários parágrafos e blocos, com cores de fundo para distinguir o conteúdo. Experimente editar o texto e as imagens da tabela abaixo.

Recursos

Notas de trabalho

Uma imagem e sua descrição na mesma célula.

Parágrafos flexíveis

Pressione Enter para criar um parágrafo ou Shift+Enter para quebrar a linha no mesmo parágrafo.

  • Alterar o fundo das células

  • Recuar uma lista com Tab

  • Selecionar várias células e aplicar a mesma cor

Clique para ver dicas de edição

As células também aceitam blocos recolhíveis, citações, código e vídeos.

Ao mesclar células, o conteúdo de cada uma é mantido na ordem.

Clique em uma célula para mostrar sua cor de fundo e as ferramentas de linhas e colunas. Selecione várias células para alterar a cor e o alinhamento em conjunto. Para posicionar a tabela inteira, escolha “Selecionar tabela” e use as ferramentas de alinhamento.

Tabelas com cores ou vários blocos são preservadas como HTML mesmo ao salvar em Markdown.

Cores de fundo das células

Aqui estão todas as cores de fundo disponíveis. Clique em uma célula para mudar sua cor ou escolha “Padrão” nas propriedades para remover o fundo.

Amarelo

yellow

Verde

green

Ciano

cyan

Rosa

pink

Roxo

purple

Laranja

orange

Ordenar colunas

Aperte Pré-visualizar e depois clique, um depois do outro, nos cabeçalhos Estoque e Preço.

Modelo

Estoque

Preço

Peso

NB-7

1,200

349

1.2 kg

NB-9

20,000

99

0.9 kg

NB-12

3,500

1,299

1.4 kg

NB-80

900

8,900

2.1 kg

NB-100

A definir

12,999

2.4 kg

Preço contém apenas valores numéricos, portanto a coluna é ordenada numericamente.

Estoque contém números e texto, portanto a coluna é ordenada como sequências de caracteres.



Separador

Escreva --- e aperte Enter: vira um separador.




Imagem

A largura vai de 30% a 100% e ela fica à esquerda, no centro ou à direita.



Área flutuante

Visão geral

Uma pequena região de apoio para texto, imagens e tabelas.

Posição

Direita

Largura máxima

40%

Use uma área flutuante para colocar explicações ou pequenos materiais ao lado do texto principal. Em um documento largo, este texto flui ao lado da região. Clique dentro dela para editar texto e inserir imagens ou tabelas no mesmo editor.

Coloque o cursor na região para abrir suas propriedades. Alterne entre esquerda e direita e escolha uma largura máxima de 20, 30, 40 ou 50% adequada ao texto. Tabelas e imagens coladas também ficam dentro da região.

Você também pode agrupar os parágrafos selecionados em uma região. O botão de desfazer a região ao lado da largura deixa o conteúdo no documento. A prévia oculta o contorno pontilhado de edição; em documentos estreitos ou na impressão, tudo segue em uma coluna.


YouTube



Envio

Arraste uma imagem ou um arquivo para cima do editor.

Esta demonstração não envia arquivos a um servidor real. Conecte um carregador à sua aplicação para armazená-los em um servidor.

Depois de abrir o seletor de imagens ou iniciar um envio, mover apenas o cursor mantém a inserção na posição original. Editar o documento durante a espera cancela a inserção e mostra um aviso. O progresso e o resultado de um envio iniciado em uma célula também ficam nela.



Citação

Numa linha vazia escreva > e aperte espaço: sai um bloco de citação.

Pode ocupar várias linhas.



Código

Numa linha vazia escreva ``` e aperte espaço ou Enter: sai um bloco de código.

Escreva também a linguagem, como ```java, e aperte espaço ou Enter: o bloco toma aquela linguagem.

import { createNabiWith, defaultWings } from 'nabi-note'

const { nabi } = createNabiWith(defaultWings)
const html = nabi.getHtml()



Bloco recolhível

Um bloco recolhível é feito de título e conteúdo.

Você decide se ele é salvo fechado ou aberto.



Barra de ferramentas

As ferramentas de títulos, formatação, alinhamento, listas, inserção e documento estão agrupadas. No computador, ficam expandidas; no celular, há ferramentas rápidas e a paleta completa. As propriedades da tabela ou área flutuante selecionada aparecem abaixo.


Atalhos

Pressione Shift duas vezes rapidamente para escolher ferramentas pelo teclado. No computador, navegue pela barra expandida; no celular, pela paleta completa. Use Tab para trocar de grupo, as setas para escolher uma ferramenta e Enter para executá-la.

No fim de um bloco de citação, código ou recolhível, pressione Enter duas vezes rapidamente para sair. O intervalo padrão é de 180ms.



Formato automático

Exemplo

Tecla

Resultado

#

Espaço

Título

-

Espaço

Lista com marcadores

1.

Espaço

Lista numerada

[ ] · [x]

Espaço

Lista de tarefas

>

Espaço

Citação

``` · ```ts

Espaço · Enter

Bloco de código

---

Enter

Separador

https://…

Espaço · Enter

Link



Funções de saída

Função

Resultado

getHtml()

HTML

getJson()

JSON



Funciona sem DOM

Converter NABI TREE em HTML não precisa de DOM.

Um servidor (Node.js) também pode ler o NABI TREE salvo e gerar HTML com as mesmas regras.


Amigo do celular

  • Interface móvel — Organiza as ferramentas de edição conforme a largura da tela.

  • Ajuste do teclado móvel — Ajusta a altura da área de edição quando o teclado é aberto.

  • Tamanhos flexíveis — Usa unidades rem no layout principal para se adaptar à ampliação e à redução.

  • Vários idiomas — Você pode definir a localidade e a tipografia conforme o idioma e a direção do texto.


Personalização

  • Seus próprios módulos wing — se precisar de uma função, você pode criá-la e conectá-la.

  • Seu próprio CSS — ajuste as cores principais, os cantos e os espaçamentos com os tokens --nabi-* para os modos claro e escuro.

  • Código aberto — publicamos o código-fonte no GitHub e o desenvolvemos em colaboração.


Ver a documentação → nabi.saro.me

HTMLCarregando o editor…
JSONnabi-treeCarregando o editor…
Instalação
npm install nabi-note
Código
import {
  createLocale, createNabiWith, mountSurface, mountToolbar,
  mountContextToolbar, mountHints, watchSettle, makeTranslator,
  defaultWings, mountUpload, mountUploadView, browserFileStore,
  mountFile, mountViewTools, browserHistoryStorage, mountLocalHistory,
  openHistoryPanel,
} from 'nabi-note'
import { mountDiffWing } from 'nabi-note/diff'
import { mountOutline } from 'nabi-note/viewer'

// The box that asks — without it the core answers "no" to everything (plug in your own)
const ask = { message: (t: string) => alert(t), confirm: (t: string) => confirm(t) }

const selected = [
  ...defaultWings,
]
const locale = createLocale('pt')
const { nabi, registry } = createNabiWith(selected, { ask, locale })

// Bring your own highlighter (Prism, highlight.js, Shiki, …) — the wing stays as it is
// and only the attach is swapped (`makeCodeAttach` ships from the same door)
// { ...codeWing, attach: makeCodeAttach({ highlight: (source, lang) => [{ text: source }] }) }

const root = document.querySelector('.nabi')!
const content = document.querySelector('.nabi-content')!

const view = mountUploadView({ nabi, surface: content, locale })
const upload = mountUpload({
  nabi, root: content, locale,
  // your upload goes here — report progress with task.onProgress(0–100)
  uploader: async (task) => ({ uri: 'https://cdn.example/uploaded' }),
  extensions: ['png', 'jpg', 'pdf'], maxFileSize: 10 * 1024 * 1024,
  onStart: (tasks) => view.start(tasks),
  onProgress: (id, percent) => view.progress(id, percent),
  onSettle: () => view.settle(),
  onDone: () => view.done(),
})
const file = mountFile({ nabi, registry, store: browserFileStore(document), locale, name: () => 'note' })
const history = mountLocalHistory({ nabi, storage: browserHistoryStorage(window) })
const diff = mountDiffWing({ nabi, registry, surface: content, locale })

// The locale also sets the direction — Arabic and Urdu run right to left
mountSurface({ nabi, registry, root: content, locale, fileSink: upload.take })

const trigger = document.createElement('button')
trigger.type = 'button'
trigger.textContent = makeTranslator(locale).t('outline')
trigger.style.cssText = 'position:fixed;right:1rem;bottom:1rem;z-index:1000'
root.append(trigger)
const outline = mountOutline(content, {
  trigger, locale,
  scrollContainer: () => root.classList.contains('is-fullscreen') ? root : window,
  onChange: ({ items, activeIndex, available, open }) => {
    trigger.hidden = !available
    trigger.setAttribute("aria-expanded", String(open))
  },
})
trigger.onclick = () => outline.toggle()
// Call outline.unmount() when removing the editor

const settle = watchSettle(document, { surface: content })
const shared = { nabi, registry, surface: content, settle, locale }
// A tool that needs a panel comes back to the host — without this the button is dead
const toolbar = mountToolbar({
  ...shared, root: document.querySelector('#toolbar')!,
  file,
  onFiles: upload.take,
  onHost: (w) => {
    if (w === 'diff') { diff.open(); return }
    if (w !== 'localHistory') return
    openHistoryPanel({
      history, surface: content, locale, sessionId: history.sessionId,
      render: (record) => createNabiWith(selected, { doc: JSON.parse(record.body) }).nabi.getHtml(),
    })
  },
})
const context = mountContextToolbar({ ...shared, root: document.querySelector('#context')! })
mountHints({ toolbar, context, root, surface: content })
// The preview and fullscreen buttons — they stand their own box at the end of the row
mountViewTools({ ...shared, root, container: document.querySelector('#toolbar')! })

// on every change — hook up your own code here
// nabi.onChange(() => user_callback(nabi.getHtml()))

// Call from your language selector. Content and editing history stay intact.
// locale.setLocale('ko')