NABI NOTE
একটি মুক্ত-উৎস WYSIWYG সম্পাদক
NABI NOTE একটি মুক্ত-উৎস WYSIWYG সম্পাদক, যেখানে প্রধান সব কাজ — সাজসজ্জা, সারিবদ্ধতা, সারণি, আপলোড আর বাকি সবকিছু — «wing» নামের আলাদা মডিউল হিসেবে কেন্দ্র থেকে সরিয়ে রাখা, যাতে ডেভেলপার কোনো সীমা ছাড়াই নিজের কাজ যোগ করতে পারেন। এটি খাঁটি Vanilla JS-এ লেখা এবং ফ্রেমওয়ার্কে শূন্য নির্ভরতা লক্ষ্য করে, তাই React-এ, Vue-তে বা যেখানেই হোক একইভাবে বসে যায়, আর বিল্ড-ব্যবস্থা নেই এমন প্রকল্পের জন্য একটি CDN গ্রন্থাগারও আছে। এর নিজস্ব JSON রূপ NABI TREE, তাই HTML আর লেখার মধ্যেকার রূপান্তর সেখানেও আগেভাগে সেরে রাখা যায় যেখানে DOM নেই (Node.js, SSR); আর নথিকে তালি দেওয়ার বদলে অনুমোদিত শব্দভাণ্ডার থেকে নতুন করে গড়ে তোলা হয় বলে আলাদা কোনো পরিশোধন-গ্রন্থাগার ছাড়াই XSS স্ক্রিপ্ট গোড়াতেই আটকে যায়। নকশায় CSS Variable পদ্ধতি নেওয়া হয়েছে, ফলে ব্র্যান্ডের রং সহজে বদলানো যায়, আর rem-ভিত্তিক বিন্যাসে ছোট-বড় করলেও মোবাইলের চেহারা মসৃণ থাকে; অন্ধকার ও উজ্জ্বল দুইয়ের সঙ্গে মেলানো রং, হাইলাইটার আর বহুভাষিক হরফ আগে থেকেই আছে। এর সঙ্গে আছে ধরন চিনে সারণির স্তম্ভ সাজানো, স্থানীয় ইতিহাস এবং ভাইব কোডিং-এর সহায়তা।
হরফ
পা-হীন (স্বাভাবিক), পা-সহ, সমান-প্রস্থ আর হাতের লেখা — প্রতিটি পরিবারে লিপি অনুযায়ী হরফ সাজানো, তাই যে ভাষাই লিখুন, সেই পরিবারের চেহারা বজায় থাকে; যে লিপির জন্য সেই পরিবারে হাতের লেখা নেই, সেটি ব্রাউজারের স্বাভাবিক হরফে ফিরে যায়। স্বাভাবিক হরফ ঠিক করে আশ্রয়দাতা।
নিচে প্রতিটি পরিবার নানা ভাষায় দেখানো হলো।
স্যান্স সেরিফ · سانس سیرف · Tanpa serif · بدون سریف · सॅन्स सेरिफ · Không chân · శాన్స్ సెరిఫ్ · Mara seref · Sans serif · Bila serif · சான்ஸ் செரிஃப் · ไร้เชิง · Senza grazie · 산세리프 · ゴシック体 · 无衬线 · Serifenlos · Sans empattement · Sin serifa · Sem serifa · Без засечек · بلا زخارف · सैन्स सेरिफ़
সেরিফ · سیرف · Berserif · سریف · सेरिफ · Có chân · సెరిఫ్ · Mai seref · Serif · Yenye serif · செரிஃப் · มีเชิง · Con grazie · 세리프 · 明朝体 · 衬线 · Avec empattement · Con serifa · Com serifa · С засечками · بزخارف · सेरिफ़
মনোস্পেস · یکساں چوڑائی · Lebar tetap · تکفاصله · मोनोस्पेस · Đơn cách · మోనోస్పేస్ · Tazara ɗaya · Eş aralıklı · Nafasi moja · ஒற்றையகலம் · ความกว้างคงที่ · Monospaziato · Monospace · 고정폭 · 等幅 · 等宽 · Dicktengleich · Chasse fixe · Monoespaciada · Monoespaçada · Моноширинный · ثابت العرض
হস্তলিপি · رواں خط · Tulisan tangan · دستنویس · हस्ताक्षर · Chữ viết tay · చేతిరాత · Rubutun hannu · El yazısı · Mwandiko · கையெழுத்து · ลายมือ · Corsivo · Cursive · 필기체 · 筆記体 · 手写体 · Schreibschrift · Cursiva · Рукописный · خط اليد · हस्तलिपि
লেখার মাপ
খুব ছোট
ছোট
বড়
খুব বড়
শিরোনাম
খালি লাইনে # লিখে স্পেস চাপুন — সঙ্গে সঙ্গে শিরোনাম হয়ে যায়।
H1
H2
H3
H4
H5
H6
মোটা · হেলানো · নিম্নরেখ · কাটা
মোটা হেলানো নিম্নরেখ কাটা — এই তো উদাহরণ।
একটার উপর আরেকটাও দেওয়া যায়।
উপরের ও নিচের অঙ্ক
ক্ষেত্রফল ৩.৫ মি2, আর পাদটীকা এভাবে বসে।1
জল হলো H2O।
লেখার রং · হাইলাইটার
রংগুলো এমনভাবে বাছা, যাতে উজ্জ্বল আর অন্ধকার দুইয়েই পড়তে আরাম লাগে।
লেখার রং সবুজ · প্রবাল · বেগুনি · অ্যাম্বার · নীল
হাইলাইটার হলুদ · সবুজ · আকাশি · গোলাপি · বেগুনি · কমলা
সংযোগ
ঠিকানা বসালেই তা সংযোগ হয়ে যায়।
ঠিকানায় কেবল http:// আর https:// চলে; javascript:-এর মতো কিছু চলবে না।
যেমন https://nabi.saro.me লিখে স্পেস বা এন্টার চাপুন — নিজে থেকেই বদলে যায়, যেমনটা এখানে দেখা যাচ্ছে।
লিঙ্ক খোলা
স্বাভাবিকভাবে একই উৎসের সংযোগ এই জানালাতেই আর অন্য সাইট নতুন জানালায় খোলে; সম্পাদক ঘোষণার সময় এই নিয়ম ঠিক করে দেওয়া যায়।
সংযুক্তির সংযোগ
ছবি ছাড়া অন্য কিছু তুললে নিচের মতো ফাইল-আকৃতির একটি সংযোগ থেকে যায়।
সংযুক্তি এইটুকুই থেকে যায়।
সারিবদ্ধতা
বাঁয়ে
মাঝে
ডানে
শিরোনামও সারিবদ্ধ করা যায়।
তালিকা
বিন্দু-তালিকা
খালি লাইনে - লিখে স্পেস চাপুন — সঙ্গে সঙ্গে বিন্দু-তালিকা হয়ে যায়।
এটি একটি বিন্দু
Tab / Shift+Tab দিয়ে ভিতরে আর বাইরে নেওয়া যায়।
সংখ্যা-তালিকা
খালি লাইনে 1. লিখে স্পেস চাপুন — সংখ্যা-তালিকা হয়ে যায়।
প্রথম
দ্বিতীয়
তৃতীয়
চেক-তালিকা
খালি লাইনে [ ] বা [x] লিখে স্পেস চাপুন — চেক-তালিকা হয়ে যায়।
এই কাজটি হয়ে গেছে।
এটি এখনো বাকি।
সারণি
টুলবারের সারণি থেকে বানান; সারি আর স্তম্ভ যোগ, বাদ ও জোড়া দেওয়া যায়।
স্তম্ভ সাজানো
ঝলক চাপুন, তারপর মজুত আর দাম-এর শিরোনামে একে একে ক্লিক করুন।
মডেল | মজুত | দাম | ওজন |
|---|---|---|---|
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 | ঠিক হয়নি | 12,999 | 2.4 kg |
দাম-এ সবই সংখ্যা, তাই সংখ্যা হিসেবে সাজে।
মজুত লেখা হিসেবে সাজে, কারণ শেষ ঘরে অক্ষর আছে।
বিভাজক রেখা
--- লিখে এন্টার চাপুন — বিভাজক রেখা হয়ে যায়।
ছবি
প্রস্থ ৩০% থেকে ১০০% পর্যন্ত বদলানো যায় আর সেটি বাঁয়ে, মাঝে বা ডানে বসে।
YouTube
আপলোড
কোনো ছবি বা ফাইল সম্পাদকের উপর টেনে আনুন।
এখানকার আপলোড কেবল নকল; একটি সেটিংয়েই তা আপনার সার্ভারে জুড়ে যায়।
আপলোড বিফল হলে সেই ছবি বা ফাইল সম্পাদক থেকে সরিয়ে দেওয়া হয়।
উদ্ধৃতি
খালি লাইনে > লিখে স্পেস চাপুন — উদ্ধৃতির বাক্স হয়ে যায়।
এটি কয়েক লাইন জুড়েও চলতে পারে।
কোড
খালি লাইনে ``` লিখে স্পেস বা এন্টার চাপুন — কোডের বাক্স হয়ে যায়।
ভাষাটাও সঙ্গে লিখুন, যেমন ```java, তারপর স্পেস বা এন্টার — বাক্সে সেই ভাষা বসে যায়।
import { createNabiWith, defaultWings } from 'nabi-note'
const { nabi } = createNabiWith(defaultWings)
const html = nabi.getHtml()ভাঁজ
ভাঁজ তৈরি হয় শিরোনাম আর ভিতরের লেখা দিয়ে।
এটি বন্ধ অবস্থায় সংরক্ষিত হবে না খোলা অবস্থায়, তা আপনি ঠিক করতে পারেন।
শর্টকাট
Shift দুবার দ্রুত চাপুন — টুলবার প্রতিটি কাজের শর্টকাট দেখিয়ে দেয়।
স্বয়ংক্রিয় সাজ
উদাহরণ | কী | ফল |
|---|---|---|
# | স্পেস | শিরোনাম |
- | স্পেস | বিন্দু-তালিকা |
1. | স্পেস | সংখ্যা-তালিকা |
[ ] · [x] | স্পেস | চেক-তালিকা |
> | স্পেস | উদ্ধৃতি |
``` · ```ts | স্পেস · এন্টার | কোডের বাক্স |
--- | এন্টার | বিভাজক রেখা |
https://… | স্পেস · এন্টার | সংযোগ |
নির্গম ফাংশন
ফাংশন | ফল |
|---|---|
getHtml() | HTML |
getJson() | JSON |
DOM ছাড়াও চলে
JSON থেকে HTML বানাতে DOM লাগে না।
সার্ভার (Node.js) সংরক্ষিত নাবি-গাছ যেমন আছে তেমনই পড়ে, XSS ঠেকিয়ে HTML গড়ে তুলতে পারে।
মোবাইলের বন্ধু
মোবাইল চেহারা — সাড়া-দেওয়া বিন্যাস মোবাইলের চেহারা সামলায়।
কীবোর্ডের সংশোধন — কীবোর্ড উঠলে তার উচ্চতা মিলিয়ে নেওয়া হয়।
নমনীয় মাপ — সব মাপ rem-এ লেখা।
বহুভাষিক — এটি একাধিক ভাষা সমর্থন করে।
নিজের মতো করে
নিজের wing — কোনো কাজ দরকার হলে নিজে বানিয়ে জুড়ে দিন।
নিজের 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: 'bn', name: () => 'note' })
const history = mountLocalHistory({ nabi, storage: browserHistoryStorage(window) })
const diff = mountDiffWing({ nabi, registry, surface: content, locale: 'bn' })
// The locale also sets the direction — Arabic and Urdu run right to left
mountSurface({ nabi, registry, root: content, locale: 'bn', fileSink: upload.take })
const settle = watchSettle(document, { surface: content })
const shared = { nabi, registry, surface: content, settle, locale: 'bn' }
// 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: 'bn', 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()))