ปีก
แบบอักษรหลักระยะเยื้อง


NABI NOTE

โปรแกรมแก้ไข WYSIWYG แบบโอเพนซอร์ส


NABI NOTE เป็นโปรแกรมแก้ไข WYSIWYG แบบโอเพนซอร์ส ซึ่งแยกการจัดรูปแบบ การจัดแนว ตาราง การอัปโหลด และความสามารถอื่นออกจากแกนหลักเป็นโมดูลอิสระที่เรียกว่าปีก เลือกเฉพาะปีกที่ต้องการเพื่อประกอบโปรแกรมแก้ไข และเชื่อมต่อปีกที่สร้างเองได้ เขียนด้วย JavaScript ล้วน จึงใช้กับ React หรือ Vue ได้ หน้าเว็บที่ไม่ต้องตั้งค่าบิลด์เริ่มได้ทันทีด้วย ไลบรารี CDN รูปแบบเอกสาร NABI TREE แปลงเป็น HTML ได้แม้ใน Node.js ที่ไม่มี DOM ของเบราว์เซอร์ เอกสารที่ป้อนเข้าจะได้รับการซ่อมแซมด้วยกฎที่ลงทะเบียนไว้ และ HTML จะ escape ข้อความกับแอตทริบิวต์พร้อมตรวจสอบที่อยู่ลิงก์ อย่างไรก็ตาม ปีกแบบกำหนดเองและข้อมูลจากเซิร์ฟเวอร์ยังต้องตรวจสอบตามนโยบายความปลอดภัยของแอป ตัวแปร CSS และเลย์เอาต์ rem ช่วยปรับธีมและขนาด พร้อมโหมดมืดและการตั้งค่าแบบอักษรหลายภาษา การเรียงตาราง ประวัติในเครื่อง และงานเอกสารที่ AI ช่วยทำยังอยู่บนโมเดลเอกสารเดียวกัน


แบบอักษร

แบบอักษรไร้เชิง (ค่าเริ่มต้น) มีเชิง ความกว้างคงที่ และลายมือ มีฟอนต์สำรองตามภาษา หากไม่มีฟอนต์ที่เหมาะกับแบบอักษรที่เลือก ระบบจะแสดงด้วยฟอนต์เริ่มต้นของเบราว์เซอร์ หน้าเว็บที่ฝังตัวแก้ไขเป็นผู้กำหนดแบบอักษรเริ่มต้นของตัวแก้ไข


ด้านล่างแสดงแต่ละครอบครัว ในหลายภาษา ให้ดู


산세리프 · ゴシック体 · 无衬线 · 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



ขนาดข้อความ

เล็กมาก

เล็ก

ใหญ่

ใหญ่มาก



หัวเรื่อง

บนบรรทัดว่าง พิมพ์ # แล้วเว้นวรรคเพื่อเปลี่ยนเป็นหัวเรื่อง

H1

H2

H3

H4

H5
H6



ตัวหนา · ตัวเอียง · ขีดเส้นใต้ · ขีดทับ

ตัวหนา ตัวเอียง ขีดเส้นใต้ ขีดทับ สามารถใช้ร่วมกันกับอักขระเดียวได้

ซ้อนรูปแบบกันได้ด้วย

ตัวยกและตัวห้อย

พื้นที่คือ 3.5m2 และเพิ่มเชิงอรรถแบบนี้1

น้ำคือ H2O



สีข้อความ · เน้นข้อความ

จานสียังอ่านง่ายทั้งโหมดสว่างและมืด

สีข้อความ เขียว · คอรัล · ม่วง · อำพัน · น้ำเงิน

เน้น เหลือง · เขียว · ฟ้า · ชมพู · ม่วง · ส้ม



ลิงก์

ใส่ที่อยู่แล้วจะเป็น ลิงก์ ได้

ใช้ URL http:// และ https:// รวมทั้งพาธเว็บไซต์เดียวกันที่ขึ้นต้นด้วย . หรือ / ได้ ไม่อนุญาตที่อยู่อย่าง javascript:

พิมพ์ https://nabi.saro.me แล้วกดเว้นวรรคหรือ Enter — ระบบจะแปลงเอง

การเปิดลิงก์

เอกสารเก็บเฉพาะที่อยู่ลิงก์ หน้าที่แสดงเอกสารเป็นผู้ตัดสินใจว่าลิงก์จะเปิดอย่างไร

ลิงก์ไฟล์แนบ

ไฟล์ที่ไม่ใช่รูปภาพจะคงอยู่ในรูปแบบลิงก์ไฟล์แนบดังตัวอย่างด้านล่าง

ไฟล์แนบ จะบันทึกเป็นลิงก์ในเอกสาร



การจัดแนว

ชิดซ้าย

กึ่งกลาง

ชิดขวา

ไม่สามารถใช้การจัดแนวกับหัวข้อได้



รายการ

รายการหัวข้อย่อย

บนบรรทัดว่าง พิมพ์ - แล้วกด เว้นวรรค เพื่อสร้างรายการหัวข้อย่อย

  • นี่คือรายการหัวข้อย่อย

    • Tab / Shift+Tab ใช้เยื้องและเลิกเยื้อง

รายการลำดับเลข

บนบรรทัดว่าง พิมพ์ 1. แล้วกด เว้นวรรค เพื่อสร้างรายการลำดับเลข

  1. แรก

  2. ที่สอง

  3. ที่สาม

รายการตรวจสอบ

บนบรรทัดว่าง พิมพ์ [ ] หรือ [x] แล้วกด เว้นวรรค เพื่อสร้างรายการตรวจสอบ

  • รายการนี้ถูกเลือกแล้ว

  • รายการนี้ยังไม่ถูกเลือก



ตาราง

เซลล์สามารถมีหลายย่อหน้าและหลายบล็อก โดยใช้สีพื้นหลังแยกเนื้อหาได้ ลองแก้ไขข้อความและรูปภาพในตารางด้านล่างโดยตรง

เอกสารประกอบ

บันทึกงาน

รูปภาพและคำอธิบายอยู่ในเซลล์เดียวกัน

จัดย่อหน้าได้อย่างอิสระ

กด Enter เพื่อขึ้นย่อหน้าใหม่ หรือ Shift+Enter เพื่อขึ้นบรรทัดใหม่ในย่อหน้าเดิม

  • เปลี่ยนสีพื้นหลังเซลล์

  • กด Tab เพื่อเยื้องรายการ

  • เลือกหลายเซลล์แล้วใช้สีเดียวกัน

คลิกเพื่อดูเคล็ดลับการแก้ไข

ในเซลล์ยังใส่บล็อกพับเก็บ ข้อความอ้างอิง โค้ด และวิดีโอได้

เมื่อผสานเซลล์ เนื้อหาของแต่ละเซลล์ยังคงอยู่ตามลำดับ

คลิกในเซลล์เพื่อแสดงสีพื้นหลังและเครื่องมือแถวกับคอลัมน์ เลือกหลายเซลล์เพื่อเปลี่ยนสีและการจัดแนวพร้อมกัน หากต้องการเปลี่ยนตำแหน่งทั้งตาราง ให้เลือก “เลือกทั้งตาราง” แล้วใช้เครื่องมือจัดแนว

ตารางที่มีสีหรือหลายบล็อกจะยังคงเป็น HTML แม้บันทึกเป็น Markdown

สีพื้นหลังเซลล์

รวมสีพื้นหลังเซลล์ที่รองรับทั้งหมดไว้ที่นี่ คลิกแต่ละเซลล์เพื่อเปลี่ยนสี หรือเลือก “ค่าเริ่มต้น” ในเครื่องมือคุณสมบัติเพื่อล้างสีพื้นหลัง

สีเหลือง

yellow

สีเขียว

green

สีฟ้าอมเขียว

cyan

สีชมพู

pink

สีม่วง

purple

สีส้ม

orange

การเรียงคอลัมน์

คลิก แสดงตัวอย่าง แล้วคลิกเซลล์หัวคอลัมน์ สต็อก และ ราคา ตามลำดับ

รุ่น

สต็อก

ราคา

น้ำหนัก

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% และวางชิดซ้าย กึ่งกลาง หรือชิดขวาได้



พื้นที่ลอย

ดูอย่างรวดเร็ว

พื้นที่เสริมขนาดเล็กสำหรับข้อความ รูปภาพ และตาราง

ตำแหน่ง

ขวา

ความกว้างสูงสุด

40%

ใช้พื้นที่ลอยเมื่อต้องการวางคำอธิบายเสริมหรือข้อมูลเล็ก ๆ ข้างเนื้อหาหลัก เมื่อเอกสารกว้าง ข้อความนี้จะไหลอยู่ข้างพื้นที่ คลิกด้านในเพื่อแก้ไขข้อความและแทรกรูปภาพหรือตารางในตัวแก้ไขเดียวกัน

วางเคอร์เซอร์ในพื้นที่เพื่อเปิดเครื่องมือคุณสมบัติ สลับตำแหน่งซ้ายหรือขวา และเลือกความกว้างสูงสุด 20, 30, 40 หรือ 50% ให้เหมาะกับเนื้อหา ตารางและรูปภาพที่วางก็จะอยู่ภายในพื้นที่เช่นกัน

คุณยังสามารถรวมย่อหน้าที่เลือกไว้ในพื้นที่ได้ ปุ่มยกเลิกพื้นที่ข้างค่าความกว้างจะคงเนื้อหาไว้ในเอกสารหลัก การแสดงตัวอย่างจะซ่อนเส้นประสำหรับแก้ไข ส่วนเอกสารแคบหรือการพิมพ์จะเรียงต่อกันในคอลัมน์เดียว


YouTube



อัปโหลด

ลองลากรูปภาพหรือไฟล์ลงบนโปรแกรมแก้ไข

เดโมนี้ไม่ส่งไฟล์ไปยังเซิร์ฟเวอร์จริง เชื่อมต่อตัวอัปโหลดในแอปพลิเคชันเพื่อบันทึกไฟล์ลงเซิร์ฟเวอร์

หลังเปิดตัวเลือกรูปภาพหรือเริ่มอัปโหลด หากย้ายเพียงเคอร์เซอร์จะยังแทรกที่ตำแหน่งเดิม หากแก้ไขเอกสารระหว่างรอ จะยกเลิกการแทรกและแสดงข้อความแจ้ง ความคืบหน้าและผลลัพธ์ของการอัปโหลดที่เริ่มในเซลล์จะยังอยู่ในเซลล์นั้น



คำพูดอ้างอิง

บนบรรทัดว่าง พิมพ์ > แล้วกด เว้นวรรค เพื่อสร้างกล่องคำพูดอ้างอิง

เขียนได้หลายบรรทัด



โค้ด

บนบรรทัดว่าง พิมพ์ ``` แล้วกด เว้นวรรคหรือ Enter เพื่อสร้างกล่องโค้ด

พิมพ์ภาษา เช่น ```java แล้วกดเว้นวรรคหรือ Enter เพื่อสร้างกล่องโค้ดของภาษานั้น

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

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



รายละเอียด

รายละเอียดประกอบด้วยหัวข้อสรุปและเนื้อหา

เลือกได้ว่าจะบันทึกแบบพับหรือเปิด



แถบเครื่องมือ

เครื่องมือหัวเรื่อง รูปแบบข้อความ การจัดแนว รายการ การแทรก และเอกสารถูกจัดเป็นกลุ่ม บนคอมพิวเตอร์จะแสดงเครื่องมือทั้งหมด ส่วนมือถือมีเครื่องมือด่วนและแผงเครื่องมือครบชุด คุณสมบัติของตารางหรือพื้นที่ลอยที่เลือกจะแสดงใต้แถบเครื่องมือ


แป้นพิมพ์ลัด

กด Shift สองครั้งอย่างรวดเร็ว เพื่อเลือกเครื่องมือด้วยแป้นพิมพ์ บนคอมพิวเตอร์ให้เลื่อนไปตามแถบเครื่องมือที่ขยายแล้ว ส่วนมือถือใช้แผงเครื่องมือครบชุด กด Tab เพื่อเปลี่ยนกลุ่ม ใช้ปุ่มลูกศรเลือกเครื่องมือ แล้วกด Enter เพื่อใช้งาน

เมื่ออยู่ท้ายบล็อก เช่น ข้อความอ้างอิง โค้ด หรือบล็อกพับเก็บ ให้กด Enter สองครั้งอย่างรวดเร็วเพื่อออกจากบล็อก ช่วงเวลาการกดซ้ำเริ่มต้นคือ 180ms



จัดรูปแบบอัตโนมัติ

ตัวอย่าง

ปุ่มดำเนินการ

ผลลัพธ์

#

เว้นวรรค

หัวเรื่อง

-

เว้นวรรค

รายการหัวข้อย่อย

1.

เว้นวรรค

รายการลำดับเลข

[ ] · [x]

เว้นวรรค

รายการตรวจสอบ

>

เว้นวรรค

คำพูดอ้างอิง

``` · ```ts

เว้นวรรค · Enter

กล่องโค้ด

---

Enter

เส้นคั่น

https://…

เว้นวรรค · Enter

ลิงก์



ฟังก์ชันผลลัพธ์

ฟังก์ชัน

ผลลัพธ์

getHtml()

HTML

getJson()

JSON



ทำงานได้โดยไม่มี DOM

การแปลง NABI TREE เป็น HTML ไม่ต้องใช้ DOM.

เซิร์ฟเวอร์ (Node.js) ก็สามารถอ่าน NABI TREE ที่บันทึกไว้แล้วสร้าง HTML ตามกฎเดียวกันได้


เหมาะกับมือถือ

  • UI บนมือถือ — จัดวางเครื่องมือแก้ไขตามความกว้างหน้าจอ

  • การปรับตามแป้นพิมพ์มือถือ — ปรับความสูงของพื้นที่แก้ไขเมื่อแป้นพิมพ์เปิดขึ้น

  • ขนาดที่ยืดหยุ่น — ใช้หน่วย rem ในเค้าโครงหลักเพื่อรองรับการขยายและย่อ

  • หลายภาษา — ตั้งค่าโลแคลและแบบอักษรให้เหมาะกับภาษาและทิศทางข้อความได้


การปรับแต่ง

  • ปีกของคุณเอง — หากต้องการความสามารถใด คุณสามารถสร้างและเชื่อมต่อเองได้

  • CSS ของคุณเอง — ปรับสีหลัก มุม และระยะห่างด้วยโทเคน --nabi-* ให้เหมาะกับโหมดสว่างและมืดได้

  • โอเพนซอร์ส — เผยแพร่ซอร์สโค้ดบน GitHub และร่วมกันพัฒนา


อ่านเอกสาร → nabi.saro.me

HTMLกำลังโหลดโปรแกรมแก้ไข…
JSONnabi-treeกำลังโหลดโปรแกรมแก้ไข…
ติดตั้ง
npm install nabi-note
โค้ด
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('th')
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')