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
Des polices de remplacement adaptées aux langues sont prévues pour les familles sans empattement (par défaut), avec empattement, à chasse fixe et cursive. Si aucune police ne correspond à la famille choisie, la police par défaut du navigateur est utilisée. La page hôte définit la police par défaut de l’éditeur.
Ci-dessous, chaque famille est affichée dans de nombreuses langues.
산세리프 · ゴシック体 · 无衬线 · 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
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é peuvent s’appliquer ensemble au même caractère.
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
Les fichiers autres que les images restent sous forme de liens de pièce jointe, comme ci-dessous.
Pièce jointe : le lien est enregistré dans le document.
Alignement
Aligné à gauche
Centré
Aligné à droite
L’alignement ne peut pas être appliqué aux titres.
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.
Premier
Deuxième
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
Une cellule peut contenir plusieurs paragraphes et blocs, avec des couleurs de fond pour distinguer les contenus. Essayez de modifier directement le texte et les images du tableau ci-dessous.
Ressources | Notes de travail |
|---|---|
Une image et sa description dans la même cellule. | Des paragraphes libresAppuyez sur Entrée pour créer un paragraphe, ou sur Maj+Entrée pour revenir à la ligne dans le même paragraphe. |
| Cliquer pour afficher les conseilsLes cellules acceptent aussi des blocs repliables, citations, blocs de code et vidéos. La fusion des cellules conserve leur contenu dans l’ordre. |
Cliquez dans une cellule pour afficher sa couleur de fond et les outils de lignes et colonnes. Sélectionnez plusieurs cellules pour changer ensemble leur couleur et leur alignement. Pour déplacer le tableau entier, choisissez « Sélectionner le tableau », puis utilisez les outils d’alignement.
Les tableaux colorés ou contenant plusieurs blocs sont conservés en HTML, même lors d’un enregistrement en Markdown.
Couleurs de fond des cellules
Voici toutes les couleurs de fond disponibles. Cliquez dans une cellule pour changer sa couleur, ou choisissez « Par défaut » dans les propriétés pour effacer son fond.
Jaune yellow | Vert green | Cyan cyan |
Rose pink | Violet purple | Orange orange |
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 valeurs numériques ; cette colonne est donc triée numériquement.
Stock contient des nombres et du texte ; cette colonne est donc triée comme des chaînes de caractères.
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.
Zone flottante
En un coup d’œil
Une petite zone complémentaire pour du texte, des images et des tableaux.
Position | Droite |
Largeur maximale | 40% |
Utilisez une zone flottante pour placer des explications ou de petits documents à côté du texte principal. Dans une page large, ce texte s’écoule le long de la zone. Cliquez à l’intérieur pour modifier le texte et insérer des images ou des tableaux dans le même éditeur.
Placez le curseur dans la zone pour ouvrir ses propriétés. Passez de gauche à droite et choisissez une largeur maximale de 20, 30, 40 ou 50% adaptée au texte. Les tableaux et images collés restent aussi dans la zone.
Vous pouvez également regrouper les paragraphes sélectionnés dans une zone. Le bouton de retrait à côté de la largeur laisse son contenu dans le texte principal. L’aperçu masque les pointillés d’édition ; dans une page étroite ou à l’impression, tout se suit sur une seule colonne.
YouTube
Upload
Essayez de glisser une image ou un fichier sur l’éditeur.
Cette démo n’envoie pas les fichiers vers un véritable serveur. Reliez un gestionnaire d’envoi à votre application pour les enregistrer sur un serveur.
Après l’ouverture du sélecteur d’image ou le début d’un envoi, déplacer seulement le curseur conserve la position d’insertion initiale. Modifier le document pendant l’attente annule l’insertion et affiche un message. La progression et le résultat d’un envoi lancé dans une cellule restent dans cette cellule.
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.
Barre d’outils
Les outils de titres, mise en forme, alignement, listes, insertion et document sont regroupés. Sur ordinateur, ils sont déployés ; sur mobile, les outils rapides et la palette complète sont disponibles. Les propriétés du tableau ou de la zone flottante sélectionnés apparaissent sous la barre.
Raccourcis
Appuyez rapidement deux fois sur Maj pour choisir les outils au clavier. Sur ordinateur, parcourez la barre déployée ; sur mobile, la palette complète. Changez de groupe avec Tab, choisissez un outil avec les flèches, puis exécutez-le avec Entrée.
À la fin d’un bloc de citation, de code ou repliable, appuyez rapidement deux fois sur Entrée pour en sortir. L’intervalle par défaut est de 180ms.
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 NABI TREE en HTML ne nécessite aucun DOM.
Un serveur (Node.js) peut également lire le NABI TREE enregistré et produire du HTML selon les mêmes règles.
Adapté au mobile
Interface mobile — Dispose les outils d’édition selon la largeur de l’écran.
Adaptation au clavier mobile — Ajuste la hauteur de la vue d’édition lorsque le clavier s’ouvre.
Tailles flexibles — Utilise des unités rem pour la disposition principale afin de s’adapter au zoom avant et arrière.
Multilingue — Vous pouvez régler la locale et la police selon la langue et le sens du texte.
Personnalisation
Votre propre wing — si une fonction vous manque, vous pouvez la créer et la connecter vous-même.
Votre propre CSS — ajustez les couleurs principales, les coins et les espacements avec les variables --nabi-* pour les modes clair et sombre.
Open source — le code source est publié sur GitHub et développé en collaboration.
Lire la documentation → nabi.saro.me
npm install nabi-noteimport {
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('fr')
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')