How to Convert a TypeScript into a SilverBullet Plugin

I have a home server and I was looking for an application to take notes. As you know, Obsidian is not the ideal choice, especially since I use Docker on my home server. While discussing with ChatGPT, it suggested I use SilverBullet, which turned out to be a very suitable option, particularly with its feature of saving notes as files on the device, and its simple interface that allows writing immediately without much configuration.

However, the problem I faced when writing was Arabic, as it is written from right to left, unlike English, and similar issues occur with other languages like Persian, Urdu, and Hebrew. I tried to develop a plugin to solve this problem, but my attempts were unsuccessful due to my limited experience.

I would like an explanation or method to convert my code into a SilverBullet plugin, even though the JavaScript code works perfectly in the browser:

// RTL fix with English line detection
(function(): void {
  const id: string = 'rtl-fix';
  if (document.getElementById(id)) return;

  const css: string = `
    @import url('https://fonts.googleapis.com/css2?family=Noto+Naskh+Arabic:[email protected]&family=Readex+Pro:[email protected]&display=swap');
    .cm-editor, .cm-scroller, .cm-content, .cm-line, .rendered-markdown, .page-content {
      direction: rtl !important;
      text-align: right !important;
      font-family: "Noto Naskh Arabic", "Readex Pro", sans-serif !important;
      font-optical-sizing: auto !important;
      font-variation-settings: "HEXP" 0 !important;
    }
    .cm-line::before, .rendered-markdown p::before, .rendered-markdown li::before {
      content: "\\200F"; width: 0; height: 0;
    }
    .cm-line.ltr-line, .rendered-markdown p.ltr-line {
      direction: ltr !important; text-align: left !important;
    }
    .cm-line.ltr-line::before, .rendered-markdown p.ltr-line::before { content: none !important; }
    pre, code, table, .cm-inline-code { direction: ltr !important; text-align: left !important; }
  `;

  const s: HTMLStyleElement = document.createElement('style');
  s.id = id;
  s.textContent = css;
  document.head.appendChild(s);

  document.querySelectorAll('.cm-editor, .sb-editor, .rendered-markdown, .page-content')
    .forEach((el: Element) => el.setAttribute('dir', 'rtl'));

  const isEng = (txt: string): boolean => {
    const clean: string = txt.replace(/[\s\d\p{P}\p{S}]/gu, '');
    return clean && !/[\u0600-\u06FF\u0750-\u077F]/.test(clean);
  };

  const detect = (): void => {
    document.querySelectorAll('.cm-line, .rendered-markdown p').forEach((el: Element) => {
      isEng(el.textContent || '') ? el.classList.add('ltr-line') : el.classList.remove('ltr-line');
    });
  };

  detect();
  new MutationObserver(detect).observe(document.body, { childList: true, subtree: true, characterData: true });
})();

1 Like

Multiple things

  • Welcome, I didn’t know ChatGPT recommended SB, cool you found the project.
  • RTL isn’t supported by SB, it’s theoretically supported by CodeMirror, but the SB CodeMirror is so heavily modified in weird ways, it explodes when you look at it wrong. I don’t want to discourage you, but you are definitely up for a challenge here, especially without modifying SB itself.
  • Plugs are very constrained in the ways they can interact with SB. In practice that means that there is no easy way to insert CSS into SB from a plug. Same goes for JS.
  • Your best bet is using SpaceLua and SpaceStyles. Using SpaceStyles you can insert CSS into the DOM Tree very easily. If you want to insert JS, it gets a little more hacky, you would need to access the undocumented js.window object, which is just the normal window object, from Space Lua. You could use this to create a script tag or directly interact with things.
2 Likes

Thanks, MrMugame.
Actually, after some searching, I found a very simple way to fix the text direction issue: a Firefox extension called Auto RTL/LTR Switcher v2.5.
The only problem is that it changes the direction of the entire page, including the English text

1 Like

After some thinking, I found a very simple solution to the RTL issue.

Instead of trying to force SilverBullet to support RTL through a plug—which turned out to be too restricted—I converted my original JavaScript code into a Firefox browser extension.

I named the extension RTL Silverbulle, and it solved the Arabic text direction problem completely. Now SilverBullet works perfectly with Arabic, and the editor automatically switches between RTL and LTR just like I wanted.

The extension can also work automatically. In the Firefox extension preferences, you can add any website URL where you want the RTL fix to be applied automatically.

The extension is available on the Firefox Add-ons store and also on GitHub.

Thanks again for the guidance!

2 Likes