diff --git a/plugs/editor/editor.plug.yaml b/plugs/editor/editor.plug.yaml index 7571b82d..1db9bb78 100644 --- a/plugs/editor/editor.plug.yaml +++ b/plugs/editor/editor.plug.yaml @@ -10,6 +10,10 @@ functions: path: "./editor.ts:toggleDarkMode" command: name: "Editor: Toggle Dark Mode" + toggleMarkdownSyntaxRendering: + path: "./editor.ts:toggleMarkdownSyntaxRendering" + command: + name: "Editor: Toggle Markdown Syntax Rendering" newWindow: path: editor.ts:newWindowCommand command: diff --git a/plugs/editor/editor.ts b/plugs/editor/editor.ts index b7a47a26..e79ad6e9 100644 --- a/plugs/editor/editor.ts +++ b/plugs/editor/editor.ts @@ -12,6 +12,16 @@ export async function setEditorMode() { if (await clientStore.get("darkMode")) { await editor.setUiOption("darkMode", true); } + const markdownSyntaxRendering = await clientStore.get( + "markdownSyntaxRendering", + ); + if (markdownSyntaxRendering != null) { + await editor.setUiOption( + "markdownSyntaxRendering", + markdownSyntaxRendering, + ); + await editor.rebuildEditorState(); + } } export function openCommandPalette() { @@ -41,6 +51,16 @@ export async function toggleDarkMode() { await editor.reloadUI(); } +export async function toggleMarkdownSyntaxRendering() { + let renderingSyntax = await editor.getUiOption( + "markdownSyntaxRendering", + ); + renderingSyntax = !renderingSyntax; + await clientStore.set("markdownSyntaxRendering", renderingSyntax); + await editor.setUiOption("markdownSyntaxRendering", renderingSyntax); + await editor.rebuildEditorState(); +} + export async function centerCursorCommand() { const pos = await editor.getCursor(); await editor.moveCursor(pos, true); diff --git a/web/PAGE_TEMPLATES.ts b/web/PAGE_TEMPLATES.ts index b9de561a..7a69f975 100644 --- a/web/PAGE_TEMPLATES.ts +++ b/web/PAGE_TEMPLATES.ts @@ -18,7 +18,7 @@ _Ah, so that explains the name!_ * Start typing \`:party\` to trigger the emoji picker 🎉 * Type \`/\` somewhere in the text to invoke a **slash command**. * If this matches your personality type, there is also an \`Editor: Toggle Vim Mode\` command to switch to Vim mode. If you cannot figure out how to exit it (classic vim issue), just run that same command again. _Phew!_ -* As you may have noticed, while SilverBullet uses [markdown](https://www.markdownguide.org/) underneath, it also “live previews” it to give a bit more of a WYSIWYG feel. You can always move your cursor “into” the underlying code by \`Alt-clicking\` it (even links and widgets, which we’ll get to later). +* As you may have noticed, while SilverBullet uses [markdown](https://www.markdownguide.org/) underneath, it also “live previews” it to give a bit more of a WYSIWYG feel. You can always move your cursor “into” the underlying code by \`Alt-clicking\` it (even links and widgets, which we’ll get to later), or reveal it permanently with the \`Toggle Markdown Syntax Rendering\` command. While SilverBullet implements (most) of [CommonMark](https://commonmark.org/), it also adds a few extensions that are SilverBullet-specific. Most notably, it adds the \`\${Lua expression}\` syntax to render Lua expressions inline. diff --git a/web/cm_plugins/clean.ts b/web/cm_plugins/clean.ts index eebd7c5c..ca0ac42a 100644 --- a/web/cm_plugins/clean.ts +++ b/web/cm_plugins/clean.ts @@ -17,7 +17,17 @@ import { hashtagPlugin } from "./hashtag.ts"; import type { ClickEvent } from "@silverbulletmd/silverbullet/type/client"; export function cleanModePlugins(client: Client) { + const pluginsNeededEvenWhenRenderingSyntax = [ + luaDirectivePlugin(client), + cleanWikiLinkPlugin(client), + ]; + + if (client.ui.viewState.uiOptions.markdownSyntaxRendering) { + return pluginsNeededEvenWhenRenderingSyntax; + } + return [ + ...pluginsNeededEvenWhenRenderingSyntax, linkPlugin(client), blockquotePlugin(), admonitionPlugin(), @@ -42,9 +52,7 @@ export function cleanModePlugins(client: Client) { }), listBulletPlugin(), tablePlugin(client), - cleanWikiLinkPlugin(client), cleanEscapePlugin(), - luaDirectivePlugin(client), hashtagPlugin(), ] as Extension[]; } diff --git a/web/cm_plugins/inline_content.ts b/web/cm_plugins/inline_content.ts index 9c22772c..21ec26ae 100644 --- a/web/cm_plugins/inline_content.ts +++ b/web/cm_plugins/inline_content.ts @@ -32,7 +32,10 @@ export function inlineContentPlugin(client: Client) { return; } - if (!isCursorInRange(state, [from, to])) { + const renderingSyntax = client.ui.viewState.uiOptions + .markdownSyntaxRendering; + const cursorIsInRange = isCursorInRange(state, [from, to]); + if (!renderingSyntax && !cursorIsInRange) { widgets.push(invisibleDecoration.range(from, to)); } diff --git a/web/cm_plugins/lua_directive.ts b/web/cm_plugins/lua_directive.ts index 9dd91797..364d955b 100644 --- a/web/cm_plugins/lua_directive.ts +++ b/web/cm_plugins/lua_directive.ts @@ -143,7 +143,10 @@ export function luaDirectivePlugin(client: Client) { ), }).range(node.to), ); - widgets.push(invisibleDecoration.range(node.from, node.to)); + + if (!client.ui.viewState.uiOptions.markdownSyntaxRendering) { + widgets.push(invisibleDecoration.range(node.from, node.to)); + } }, }); diff --git a/web/cm_plugins/wiki_link.ts b/web/cm_plugins/wiki_link.ts index 2e36de1d..0f754cda 100644 --- a/web/cm_plugins/wiki_link.ts +++ b/web/cm_plugins/wiki_link.ts @@ -62,7 +62,9 @@ export function cleanWikiLinkPlugin(client: Client) { "default": "", }[linkStatus]; - if (isCursorInRange(state, [from, to])) { + const renderingSyntax = + client.ui.viewState.uiOptions.markdownSyntaxRendering; + if (isCursorInRange(state, [from, to]) || renderingSyntax) { // Only attach a CSS class, then get out if (linkStatus !== "default") { widgets.push( diff --git a/web/editor_ui.tsx b/web/editor_ui.tsx index 1fdcef27..e98c6198 100644 --- a/web/editor_ui.tsx +++ b/web/editor_ui.tsx @@ -127,6 +127,11 @@ export class MainUI { }); }, [viewState.uiOptions.darkMode]); + useEffect(() => { + document.documentElement.dataset.markdownSyntaxRendering = + viewState.uiOptions.markdownSyntaxRendering ? "on" : "off"; + }, [viewState.uiOptions.markdownSyntaxRendering]); + useEffect(() => { // Need to dispatch a resize event so that the top_bar can pick it up globalThis.dispatchEvent(new Event("resize")); diff --git a/web/styles/theme.scss b/web/styles/theme.scss index 1f4fcfec..3f3b3831 100644 --- a/web/styles/theme.scss +++ b/web/styles/theme.scss @@ -279,6 +279,15 @@ html[data-theme="dark"] { --editor-directive-background-color: #4c4c4c7d; } +html[data-markdown-syntax-rendering="on"] { + --editor-meta-color: unset; + --editor-directive-mark-color: unset; + + #sb-main .cm-editor .sb-lua-directive-block { + margin-top: 0.5em; + } +} + .sb-admonition[admonition="note" i] { .sb-admonition-type { &::before { diff --git a/web/ui_types.ts b/web/ui_types.ts index db3ce722..0466ca35 100644 --- a/web/ui_types.ts +++ b/web/ui_types.ts @@ -39,6 +39,7 @@ export type AppViewState = { uiOptions: { vimMode: boolean; darkMode?: boolean; + markdownSyntaxRendering: boolean; forcedROMode: boolean; customStyles?: string; }; @@ -76,6 +77,7 @@ export const initialViewState: AppViewState = { uiOptions: { vimMode: false, darkMode: undefined, + markdownSyntaxRendering: false, forcedROMode: false, }, isMobile: false, diff --git a/website/Live Preview.md b/website/Live Preview.md index 7ef13825..e11b3e66 100644 --- a/website/Live Preview.md +++ b/website/Live Preview.md @@ -2,4 +2,4 @@ SilverBullet uses a “live preview” markdown editor. This mechanism is heavil It reduces visual noise by not constantly showing [[Markdown]] codes such as `[SilverBullet website](https://silverbullet.md)`, only showing the underlying Markdown formatting code when the cursor is placed inside. -In SilverBullet, you can always see the underlying format by moving your cursor “inside.” **Alt-clicking** on any piece of formatted text will move your cursor there and reveal the underlying (markdown) code. +In SilverBullet, you can always see the underlying format by moving your cursor “inside.” **Alt-clicking** on any piece of formatted text will move your cursor there and reveal the underlying (markdown) code, or you can reveal it permanently with the `Toggle Markdown Syntax Rendering` command.