NABI NOTE
โปรแกรมแก้ไข WYSIWYG แบบโอเพนซอร์ส
NABI NOTE เป็นโปรแกรมแก้ไข WYSIWYG แบบโอเพนซอร์ส ซึ่งแยกการจัดรูปแบบ การจัดแนว ตาราง การอัปโหลด และความสามารถอื่นออกจากแกนหลักเป็นโมดูลอิสระที่เรียกว่าปีก เลือกเฉพาะปีกที่ต้องการเพื่อประกอบโปรแกรมแก้ไข และเชื่อมต่อปีกที่สร้างเองได้ เขียนด้วย JavaScript ล้วน จึงใช้กับ React หรือ Vue ได้ หน้าเว็บที่ไม่ต้องตั้งค่าบิลด์เริ่มได้ทันทีด้วย ไลบรารี CDN รูปแบบเอกสาร NABI TREE แปลงเป็น HTML ได้แม้ใน Node.js ที่ไม่มี DOM ของเบราว์เซอร์ เอกสารที่ป้อนเข้าจะได้รับการซ่อมแซมด้วยกฎที่ลงทะเบียนไว้ และ HTML จะ escape ข้อความกับแอตทริบิวต์พร้อมตรวจสอบที่อยู่ลิงก์ อย่างไรก็ตาม ปีกแบบกำหนดเองและข้อมูลจากเซิร์ฟเวอร์ยังต้องตรวจสอบตามนโยบายความปลอดภัยของแอป ตัวแปร CSS และเลย์เอาต์ rem ช่วยปรับธีมและขนาด พร้อมโหมดมืดและการตั้งค่าแบบอักษรหลายภาษา การเรียงตาราง ประวัติในเครื่อง และงานเอกสารที่ AI ช่วยทำยังอยู่บนโมเดลเอกสารเดียวกัน
แบบอักษร
Sans serif (ค่าเริ่มต้น), serif, monospace และ cursive — แต่ละครอบครัวเรียงฟอนต์ตามอักษร ดังนั้นภาษาที่เขียนยังคงรูปร่างของครอบครัวนั้น และอักษรที่ไม่มีฟอนต์ลายมือจะใช้ฟอนต์ของเบราว์เซอร์แทน ผู้โฮสต์กำหนดแบบอักษรเริ่มต้น
ด้านล่างแสดงแต่ละครอบครัว ในหลายภาษา ให้ดู
Sans serif · 산세리프 · ゴシック体 · 无衬线 · Serifenlos · Sans empattement · Sin serifa · Sem serifa · Без засечек · بلا زخارف · सैन्स सेरिफ़ · স্যান্স সেরিফ · سانس سیرف · Tanpa serif · بدون سریف · सॅन्स सेरिफ · Không chân · శాన్స్ సెరిఫ్ · Mara seref · Bila serif · சான்ஸ் செரிஃப் · ไร้เชิง · Senza grazie
Serif · 세리프 · 明朝体 · 衬线 · Avec empattement · Con serifa · Com serifa · С засечками · بزخارف · सेरिफ़ · সেরিফ · سیرف · Berserif · سریف · सेरिफ · Có chân · సెరిఫ్ · Mai seref · Yenye serif · செரிஃப் · มีเชิง · Con grazie
Monospace · 고정폭 · 等幅 · 等宽 · Dicktengleich · Chasse fixe · Monoespaciada · Monoespaçada · Моноширинный · ثابت العرض · मोनोस्पेस · মনোস্পেস · یکساں چوڑائی · Lebar tetap · تکفاصله · Đơn cách · మోనోస్పేస్ · Tazara ɗaya · Eş aralıklı · Nafasi moja · ஒற்றையகலம் · ความกว้างคงที่ · Monospaziato
Cursive · 필기체 · 筆記体 · 手写体 · Schreibschrift · Cursiva · Рукописный · خط اليد · हस्तलिपि · হস্তলিপি · رواں خط · Tulisan tangan · دستنویس · हस्ताक्षर · Chữ viết tay · చేతిరాత · Rubutun hannu · El yazısı · Mwandiko · கையெழுத்து · ลายมือ · Corsivo
ขนาดข้อความ
เล็กมาก
เล็ก
ใหญ่
ใหญ่มาก
หัวเรื่อง
บนบรรทัดว่าง พิมพ์ # แล้วเว้นวรรคเพื่อเปลี่ยนเป็นหัวเรื่อง
H1
H2
H3
H4
H5
H6
ตัวหนา · ตัวเอียง · ขีดเส้นใต้ · ขีดทับ
ตัวหนา ตัวเอียง ขีดเส้นใต้ ขีดทับ — ตัวอย่าง
ซ้อนรูปแบบกันได้ด้วย
ตัวยกและตัวห้อย
พื้นที่คือ 3.5m2 และเพิ่มเชิงอรรถแบบนี้1
น้ำคือ H2O
สีข้อความ · เน้นข้อความ
จานสียังอ่านง่ายทั้งโหมดสว่างและมืด
สีข้อความ เขียว · คอรัล · ม่วง · อำพัน · น้ำเงิน
เน้น เหลือง · เขียว · ฟ้า · ชมพู · ม่วง · ส้ม
ลิงก์
ใส่ที่อยู่แล้วจะเป็น ลิงก์ ได้
ใช้ URL http:// และ https:// รวมทั้งพาธเว็บไซต์เดียวกันที่ขึ้นต้นด้วย . หรือ / ได้ ไม่อนุญาตที่อยู่อย่าง javascript:
พิมพ์ https://nabi.saro.me แล้วกดเว้นวรรคหรือ Enter — ระบบจะแปลงเอง
การเปิดลิงก์
เอกสารเก็บเฉพาะที่อยู่ลิงก์ หน้าที่แสดงเอกสารเป็นผู้ตัดสินใจว่าลิงก์จะเปิดอย่างไร
ลิงก์ไฟล์แนบ
การอัปโหลดสิ่งอื่นนอกจากรูปภาพจะเหลือลิงก์รูปไฟล์ดังด้านล่าง
ไฟล์แนบ จะแสดงเช่นนี้
การจัดแนว
ชิดซ้าย
กึ่งกลาง
ชิดขวา
หัวเรื่องก็จัดแนวได้
รายการ
รายการหัวข้อย่อย
บนบรรทัดว่าง พิมพ์ - แล้วกด เว้นวรรค เพื่อสร้างรายการหัวข้อย่อย
นี่คือรายการหัวข้อย่อย
Tab / Shift+Tab ใช้เยื้องและเลิกเยื้อง
รายการลำดับเลข
บนบรรทัดว่าง พิมพ์ 1. แล้วกด เว้นวรรค เพื่อสร้างรายการลำดับเลข
แรก
ที่สอง
ที่สาม
รายการตรวจสอบ
บนบรรทัดว่าง พิมพ์ [ ] หรือ [x] แล้วกด เว้นวรรค เพื่อสร้างรายการตรวจสอบ
รายการนี้ถูกเลือกแล้ว
รายการนี้ยังไม่ถูกเลือก
ตาราง
คลิกปุ่มตารางบนแถบเครื่องมือเพื่อสร้าง แล้วเพิ่ม ลบ และผสานแถวกับคอลัมน์
การเรียงคอลัมน์
แสดงตัวอย่างจะเปิดขึ้นก่อน แล้วคลิกหัวคอลัมน์ สต็อก และ ราคา ตามลำดับ
รุ่น | สต็อก | ราคา | น้ำหนัก |
|---|---|---|---|
NB-7 | 1,200 | 349 | 1.2 กก. |
NB-9 | 20,000 | 99 | 0.9 กก. |
NB-12 | 3,500 | 1,299 | 1.4 กก. |
NB-80 | 900 | 8,900 | 2.1 กก. |
NB-100 | รอระบุ | 12,999 | 2.4 กก. |
ราคา เป็นตัวเลขทั้งหมด จึงเรียงตามตัวเลข
สต็อก เรียงเป็นข้อความเพราะช่องสุดท้ายมีตัวอักษร
เส้นคั่น
พิมพ์ --- แล้วกด Enter เพื่อเปลี่ยนเป็นเส้นคั่น
รูปภาพ
ความกว้างอยู่ระหว่าง 30% ถึง 100% และวางชิดซ้าย กึ่งกลาง หรือชิดขวาได้
YouTube
อัปโหลด
ลองลากรูปภาพหรือไฟล์ลงบนโปรแกรมแก้ไข
การอัปโหลดนี้เป็นแบบจำลอง การตั้งค่าจะเชื่อมต่อไปยังเซิร์ฟเวอร์ของคุณ
หากอัปโหลดไม่สำเร็จ รูปภาพหรือไฟล์จะถูกนำออกจากโปรแกรมแก้ไข
คำพูดอ้างอิง
บนบรรทัดว่าง พิมพ์ > แล้วกด เว้นวรรค เพื่อสร้างกล่องคำพูดอ้างอิง
เขียนได้หลายบรรทัด
โค้ด
บนบรรทัดว่าง พิมพ์ ``` แล้วกด เว้นวรรคหรือ Enter เพื่อสร้างกล่องโค้ด
พิมพ์ภาษา เช่น ```java แล้วกดเว้นวรรคหรือ Enter เพื่อสร้างกล่องโค้ดของภาษานั้น
import { createNabiWith, defaultWings } from 'nabi-note'
const { nabi } = createNabiWith(defaultWings)
const html = nabi.getHtml()รายละเอียด
รายละเอียดประกอบด้วยหัวข้อสรุปและเนื้อหา
เลือกได้ว่าจะบันทึกแบบพับหรือเปิด
แป้นพิมพ์ลัด
กด Shift สองครั้งอย่างรวดเร็ว เพื่อแสดงแป้นพิมพ์ลัดบนแถบเครื่องมือ
จัดรูปแบบอัตโนมัติ
ตัวอย่าง | ปุ่มดำเนินการ | ผลลัพธ์ |
|---|---|---|
# | เว้นวรรค | หัวเรื่อง |
- | เว้นวรรค | รายการหัวข้อย่อย |
1. | เว้นวรรค | รายการลำดับเลข |
[ ] · [x] | เว้นวรรค | รายการตรวจสอบ |
> | เว้นวรรค | คำพูดอ้างอิง |
``` · ```ts | เว้นวรรค · Enter | กล่องโค้ด |
--- | Enter | เส้นคั่น |
https://… | เว้นวรรค · Enter | ลิงก์ |
ฟังก์ชันผลลัพธ์
ฟังก์ชัน | ผลลัพธ์ |
|---|---|
getHtml() | HTML |
getJson() | JSON |
ทำงานได้โดยไม่มี DOM
การแปลง JSON เป็น HTML ไม่ต้องใช้ DOM.
เซิร์ฟเวอร์ (Node.js) อ่าน NABI TREE ที่บันทึกไว้และสร้าง HTML ด้วยกฎเดียวกันได้
เหมาะกับมือถือ
UI มือถือ — เลย์เอาต์ตอบสนองรองรับ UI มือถือ
พื้นที่แป้นพิมพ์มือถือ — เมื่อแป้นพิมพ์เปิด ระบบจะคำนึงถึงความสูง
ขนาดยืดหยุ่น — ทุกขนาดเขียนด้วย rem
หลายภาษา — รองรับหลายภาษา
การปรับแต่ง
ปีกของคุณเอง — หากต้องการความสามารถ ให้สร้างและลงทะเบียนเอง
CSS ของคุณเอง — สี มุม และระยะห่างทั้งหมดกำหนดเป็น --nabi-* จึงตั้งค่ามืด สว่าง และอื่น ๆ ได้เอง
โอเพนซอร์ส — เป็นโอเพนซอร์สบน GitHub
อ่านเอกสาร → nabi.saro.me
npm install nabi-noteimport {
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: 'th', name: () => 'note' })
const history = mountLocalHistory({ nabi, storage: browserHistoryStorage(window) })
const diff = mountDiffWing({ nabi, registry, surface: content, locale: 'th' })
// The locale also sets the direction — Arabic and Urdu run right to left
mountSurface({ nabi, registry, root: content, locale: 'th', fileSink: upload.take })
const settle = watchSettle(document, { surface: content })
const shared = { nabi, registry, surface: content, settle, locale: 'th' }
// 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: 'th', 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()))