Ailes
Police par défautDécalage


NABI NOTE

Un éditeur WYSIWYG open source


NABI NOTE est un éditeur WYSIWYG open source dont la mise en forme, l’alignement, les tableaux, l’upload et les autres fonctionnalités sont séparés du noyau sous forme de modules indépendants appelés wings. Vous pouvez choisir seulement les wings nécessaires pour assembler un éditeur, et connecter les wings que vous construisez vous-même. Il est écrit en JavaScript pur, donc utilisable depuis des frameworks comme React ou Vue. Sur les pages sans configuration de build, vous pouvez démarrer immédiatement avec la bibliothèque CDN. Son propre format de document, NABI TREE, peut être converti en HTML même dans des environnements Node.js sans DOM de navigateur. Les documents entrants sont réparés par les règles enregistrées ; lors de la création du HTML, le texte et les attributs sont échappés et les adresses de liens sont vérifiées. Les wings personnalisés et les données reçues du serveur doivent toutefois rester examinés séparément selon la politique de sécurité de l’application. Les variables CSS et une mise en page basée sur rem permettent d’ajuster le thème et la taille ; le mode sombre et les réglages de polices multilingues sont aussi fournis. Le tri des tableaux, l’historique local et le travail documentaire assisté par IA continuent tous sur le même modèle de document.


Police

Sans empattement (par défaut), serif, monospace et cursive — chaque famille empile des polices par système d’écriture, si bien que la langue utilisée garde la forme de cette famille ; une écriture sans police manuscrite dans cette famille retombe sur la police du navigateur. L’hôte choisit la police par défaut.


Ci-dessous, chaque famille est affichée dans de nombreuses langues.


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


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


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


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



Taille du texte

Très petit

Petit

Grand

Très grand



Titre

Sur une ligne vide, tapez # puis une espace pour la transformer aussitôt en titre.

H1

H2

H3

H4

H5
H6



Gras · Italique · Souligné · Barré

Gras italique souligné barré — un exemple.

Ils peuvent aussi être empilés.

Exposant et indice

La surface est de 3,5 m2, et une note se place ainsi.1

L’eau est H2O.



Couleur du texte · Surlignage

La palette est choisie pour rester lisible en mode clair comme en mode sombre.

Couleur du texte Vert · Corail · Violet · Ambre · Bleu

Surlignage Jaune · Vert · Cyan · Rose · Violet · Orange



Lien

Insérez une adresse et elle devient un lien.

Vous pouvez utiliser les URL http:// et https://, ainsi que les chemins du même site commençant par . ou /. Les adresses comme javascript: ne sont pas autorisées.

Par exemple, tapez https://nabi.saro.me puis appuyez sur espace ou Entrée — la conversion se fait d’elle-même, comme ici.

Ouverture des liens

Le document ne stocke que l’adresse du lien ; la page qui affiche le document décide comment les liens s’ouvrent.

Lien de pièce jointe

Uploader autre chose qu’une image laisse un lien de fichier comme celui ci-dessous.

Pièce jointe reste ainsi.



Alignement

Aligné à gauche

Centré

Aligné à droite

Les titres peuvent aussi être alignés.



Listes

Liste à puces

Sur une ligne vide, tapez - et appuyez sur espace — cela devient aussitôt une liste à puces.

  • Ceci est un élément de liste

    • Tab / Maj+Tab indente et désindente.

Liste numérotée

Sur une ligne vide, tapez 1. et appuyez sur espace pour obtenir une liste numérotée.

  1. Premier

  2. Deuxième

  3. Troisième

Liste de tâches

Sur une ligne vide, tapez [ ] ou [x] et appuyez sur espace pour obtenir une liste de tâches.

  • Cet élément est coché.

  • Celui-ci n’est pas encore coché.



Tableau

Cliquez sur le bouton tableau dans la barre d’outils pour en créer un, puis ajoutez, supprimez et fusionnez lignes et colonnes.

Tri des colonnes

Ouvrez d’abord l’Aperçu, puis cliquez tour à tour sur les cellules d’en-tête Stock et Prix.

Modèle

Stock

Prix

Poids

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

À définir

12,999

2.4 kg

Prix ne contient que des nombres, donc il est trié numériquement.

Stock est trié comme du texte à cause des lettres dans la dernière cellule.



Séparateur

Tapez --- et appuyez sur Entrée pour le transformer en séparateur.




Image

La largeur va de 30 % à 100 %, et l’image peut être à gauche, au centre ou à droite.



YouTube



Upload

Essayez de glisser une image ou un fichier sur l’éditeur.

L’upload utilisé ici est une maquette ; un réglage le connecte à votre serveur.

Si un upload échoue, l’image ou le fichier est retiré de l’éditeur.



Citation

Sur une ligne vide, tapez > et appuyez sur espace pour obtenir un bloc de citation.

Il peut s’étendre sur plusieurs lignes.



Code

Sur une ligne vide, tapez ``` et appuyez sur espace ou Entrée pour obtenir un bloc de code.

Écrivez aussi le langage, comme ```java, puis appuyez sur espace ou Entrée pour obtenir un bloc de code avec ce langage appliqué.

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

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



Details

Details est composé d’un résumé et d’un corps.

Vous pouvez choisir s’il est enregistré replié ou ouvert.



Raccourcis

Appuyez rapidement deux fois sur Maj pour afficher le raccourci de chaque fonction dans la barre d’outils.



Format automatique

Exemple

Touche d’action

Résultat

#

Espace

Titre

-

Espace

Liste à puces

1.

Espace

Liste numérotée

[ ] · [x]

Espace

Liste de tâches

>

Espace

Citation

``` · ```ts

Espace · Entrée

Bloc de code

---

Entrée

Séparateur

https://…

Espace · Entrée

Lien



Fonctions de sortie

Fonction

Résultat

getHtml()

HTML

getJson()

JSON



Fonctionne sans DOM

Convertir du JSON en HTML ne nécessite aucun DOM.

Un serveur (Node.js) peut lire le NABI TREE stocké et créer du HTML avec les mêmes règles.


Adapté au mobile

  • Interface mobile — une mise en page responsive porte l’interface mobile.

  • Inset du clavier mobile — lorsque le clavier s’ouvre, sa hauteur est prise en compte.

  • Tailles fluides — chaque taille est écrite en rem.

  • Nombreuses langues — plusieurs langues sont prises en charge.


Personnalisation

  • Votre propre wing — si vous avez besoin d’une fonction, construisez-la vous-même et enregistrez-la.

  • Votre propre CSS — couleurs, coins et espacements sont tous définis en --nabi-* ; le sombre, le clair et le reste vous appartiennent.

  • Open source — le projet est open source sur GitHub.


Lire la documentation → nabi.saro.me

HTMLChargement de l'éditeur…
JSONnabi-treeChargement de l'éditeur…
Installation
npm install nabi-note
Code
import {
  createNabiWith, mountSurface, mountToolbar, mountContextToolbar,
  mountHints, watchSettle, defaultWings, mountUpload, mountUploadView,
  browserFileStore, mountFile, parseNodes, mountViewTools,
  browserHistoryStorage, mountLocalHistory, openHistoryPanel,
} from 'nabi-note'
import { mountDiffWing } from 'nabi-note/diff'

// 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 { nabi, registry } = createNabiWith(selected, { ask })

// 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 })
const upload = mountUpload({
  nabi, root: content,
  // 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), parse: parseNodes, locale: 'fr', name: () => 'note' })
const history = mountLocalHistory({ nabi, storage: browserHistoryStorage(window) })
const diff = mountDiffWing({ nabi, registry, surface: content, locale: 'fr' })

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

const settle = watchSettle(document, { surface: content })
const shared = { nabi, registry, surface: content, settle, locale: 'fr' }
// 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: 'fr', 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()))