diff --git a/README.md b/README.md index 401e9c0..763fc16 100644 --- a/README.md +++ b/README.md @@ -12,10 +12,12 @@ Basic CSS styling provided by the plugin renders characters for whitespace at th ## Look / Feel options -1. Use the **Style settings plugin** to toggle additional CSS styles on and off -2. **Use your own snippet**: - - Set `--show-whitespace-color` to change the color of the filler characters - - Copy style.css (from the release) and fully customize how things are rendered +The plugin provides a few options to customize the look and feel of whitespace characters. + +You can also completely disable the plugin's CSS and use your own. +1. Use the plugin setting to disable registration of style.css (this functions as a style settings plugin would) +2. Copy the plugin `style.css` into your own CSS snippet +3. Update styles as desired. ## Installation diff --git a/src/@types/settings.d.ts b/src/@types/settings.d.ts new file mode 100644 index 0000000..40b1b11 --- /dev/null +++ b/src/@types/settings.d.ts @@ -0,0 +1,14 @@ +export type SWVersion = { + major: number; + minor: number; + patch: number; +}; + +export interface SWSettings { + version: SWVersion; + disablePluginStyles: boolean; + showBlockquoteMarkers: boolean; + showCodeblockWhitespace: boolean; + showAllWhitespace: boolean; + outlineListMarkers: boolean; +} diff --git a/src/styles.scss b/src/styles.scss index cb45319..8d26a36 100644 --- a/src/styles.scss +++ b/src/styles.scss @@ -1,45 +1,3 @@ -/*! @settings - -name: Show Whitespace (CM6) -id: show-whitespace-cm6 -settings: - - - id: show-whitespace-color - title: Fill character color - description: "Set `--show-whitespace-color` in a snippet to change the color of fill characters" - type: info-text - markdown: true - - - id: nix-show-whitespace-styles - title: Suppress/Remove this plugin's style - description: Set this to true to suppress the plugin's style - type: class-toggle - default: false - - - id: highlight-blockquote-markers - title: Always show blockquote markers - description: Show the leading > for blockquotes in Live Preview - type: class-toggle - default: false - - - id: highlight-all-codeblock-whitespace - title: Highlight all whitespace characters in code blocks - description: Add a marker for all whitespace characters in code blocks - type: class-toggle - default: false - - - id: highlight-all-whitespace - title: Highlight all whitespace characters - description: Add a marker for all whitespace characters, even those between words - type: class-toggle - default: false - - - id: highlight-min-width-list-markers - title: Highlight list markers - description: Add a very faint underline to min-width list markers - type: class-toggle - default: false -*/ @mixin whitespace { white-space: pre; font-family: var(--font-monospace); @@ -63,8 +21,14 @@ settings: content: '∙'; } } +.theme-dark { + --swcm6-outline-list-markers-color: rgba(var(--mono-rgb-100), 0.05); +} +.theme-light { + --swcm6-outline-list-markers-color: rgba(var(--mono-rgb-100), 0.03); +} -body:not(.nix-show-whitespace-styles) { +body:not(.swcm6-nix-plugin-styles) { --show-whitespace-color: var(--color-base-40); .markdown-source-view.mod-cm6 { @@ -121,7 +85,7 @@ body:not(.nix-show-whitespace-styles) { } } -body:not(.nix-show-whitespace-styles).highlight-blockquote-markers { +body:not(.swcm6-nix-plugin-styles).swcm6-show-blockquote-markers { .markdown-source-view.mod-cm6 { .HyperMD-quote .cm-transparent { color: var(--show-whitespace-color); @@ -129,7 +93,7 @@ body:not(.nix-show-whitespace-styles).highlight-blockquote-markers { } } -body:not(.nix-show-whitespace-styles):not(.highlight-all-whitespace).highlight-all-codeblock-whitespace { +body:not(.swcm6-nix-plugin-styles):not(.swcm6-show-all-whitespace).swcm6-show-codeblock-whitespace { .markdown-source-view.mod-cm6 .cm-line.HyperMD-codeblock { @include all-whitespace; @@ -139,13 +103,13 @@ body:not(.nix-show-whitespace-styles):not(.highlight-all-whitespace).highlight-a } } -body:not(.nix-show-whitespace-styles).highlight-all-whitespace { +body:not(.swcm6-nix-plugin-styles).swcm6-show-all-whitespace { .markdown-source-view.mod-cm6 .cm-line { @include all-whitespace; } } -body:not(.nix-show-whitespace-styles):not(.highlight-all-whitespace):not(.highlight-all-codeblock-whitespace) { +body:not(.swcm6-nix-plugin-styles):not(.swcm6-show-all-whitespace):not(.swcm6-show-codeblock-whitespace) { .markdown-source-view.mod-cm6 .cm-line { .cm-highlightSpace:not(.cm-indent .cm-highlightSpace):not(.cm-trailingSpace .cm-highlightSpace):before { content: ''; @@ -153,13 +117,13 @@ body:not(.nix-show-whitespace-styles):not(.highlight-all-whitespace):not(.highli } } -body:not(.nix-show-whitespace-styles).highlight-min-width-list-markers { +body:not(.swcm6-nix-plugin-styles).swcm6-outline-list-markers { .markdown-source-view.mod-cm6 { .cm-line { .cm-formatting-list-ul, .cm-formatting-list-ol, .task-list-label { - border-bottom: 1px dotted var(--show-whitespace-color); + background-color: var(--swcm6-outline-list-markers-color); } } } diff --git a/src/whitespace-Plugin.ts b/src/whitespace-Plugin.ts index d462200..f3e7f76 100644 --- a/src/whitespace-Plugin.ts +++ b/src/whitespace-Plugin.ts @@ -4,20 +4,115 @@ import { highlightWhitespace, } from "@codemirror/view"; import { Extension } from "@codemirror/state"; +import { SWSettings, SWVersion } from "./@types/settings"; +import { ShowWhitespaceSettingsTab } from "./whitespace-SettingsTab"; + +export const DEFAULT_SETTINGS: SWSettings = { + version: { + major: 0, + minor: 0, + patch: 0, + }, + disablePluginStyles: false, + showBlockquoteMarkers: false, + showCodeblockWhitespace: false, + showAllWhitespace: false, + outlineListMarkers: false, +}; export class ShowWhitespacePlugin extends Plugin { /** CodeMirror 6 extensions. Tracked via array to allow for dynamic updates. */ private cmExtension: Extension[] = []; + settings: SWSettings; + classList: string[] = []; async onload(): Promise { - console.info("loading Show Whitespace (CM6) v" + this.manifest.version); + console.info( + "loading Show Whitespace (SW-CM6) v" + this.manifest.version, + ); + + await this.loadSettings(); + this.addSettingTab(new ShowWhitespaceSettingsTab(this.app, this)); + + document.body.classList.add(this.manifest.id); + this.initClasses(); this.cmExtension.push(highlightWhitespace()); this.cmExtension.push(highlightTrailingWhitespace()); this.registerEditorExtension(this.cmExtension); } + initClasses(): void { + this.classList = []; + if (this.settings.disablePluginStyles) { + this.classList.push("swcm6-nix-plugin-styles"); + } + if (this.settings.showBlockquoteMarkers) { + this.classList.push("swcm6-show-blockquote-markers"); + } + if (this.settings.showCodeblockWhitespace) { + this.classList.push("swcm6-show-codeblock-whitespace"); + } + if (this.settings.showAllWhitespace) { + this.classList.push("swcm6-show-all-whitespace"); + } + if (this.settings.outlineListMarkers) { + this.classList.push("swcm6-outline-list-markers"); + } + document.body.classList.add(...this.classList); + } + + removeClasses(): void { + document.body.classList.remove(...this.classList); + } + onunload(): void { - console.log("unloading Show Whitespace (CM6)"); + console.log("unloading Show Whitespace (SW-CM6)"); + document.body.classList.add(this.manifest.id); + this.removeClasses(); + } + + async loadSettings(): Promise { + if (!this.settings) { + const options = await this.loadData(); + this.settings = Object.assign({}, DEFAULT_SETTINGS, options); + + // check settings version, adapt if necessary + const version = toVersion(this.manifest.version); + if (compareVersion(version, this.settings.version) != 0) { + this.settings.version = version; + await this.saveSettings(); + } + } + } + + async updateSettings(newSettings: SWSettings): Promise { + this.settings = Object.assign({}, this.settings, newSettings); + await this.saveSettings(); + } + + async saveSettings(): Promise { + console.debug("(SW-CM6): saving settings"); + await this.saveData(this.settings); + this.removeClasses(); + this.initClasses(); } } + +function compareVersion(v1: SWVersion, v2: SWVersion): number { + if (v1.major === v2.major) { + if (v1.minor === v2.minor) { + return v1.patch - v2.patch; + } + return v1.minor - v2.minor; + } + return v1.major - v2.major; +} +function toVersion(version: string): SWVersion { + const v = version.split("."); + return { + major: Number(v[0]), + minor: Number(v[1]), + patch: Number(v[2]), + }; +} diff --git a/src/whitespace-SettingsTab.ts b/src/whitespace-SettingsTab.ts new file mode 100644 index 0000000..7bd995c --- /dev/null +++ b/src/whitespace-SettingsTab.ts @@ -0,0 +1,155 @@ +import { App, PluginSettingTab, Setting } from "obsidian"; +import ShowWhitespacePlugin from "./main"; +import { SWSettings } from "./@types/settings"; + +export class ShowWhitespaceSettingsTab extends PluginSettingTab { + plugin: ShowWhitespacePlugin; + newSettings: SWSettings; + saveButton: HTMLElement; + + constructor(app: App, plugin: ShowWhitespacePlugin) { + super(app, plugin); + this.plugin = plugin; + } + + async save() { + await this.plugin.updateSettings(this.newSettings); + } + + async display(): Promise { + await this.plugin.loadSettings(); + this.reset(); + } + + async reset(): Promise { + this.newSettings = JSON.parse(JSON.stringify(this.plugin.settings)); + this.drawElements(); + } + + drawElements(): void { + const id = this.plugin.manifest.id; + const name = this.plugin.manifest.name; + + this.containerEl.empty(); + this.containerEl.addClass(id); + new Setting(this.containerEl).setHeading().setName(name); + + new Setting(this.containerEl) + .setName("Save settings") + .setClass(id + "-save-reset") + .addButton((button) => + button + .setIcon("reset") + .setTooltip( + "Reset to previously saved (or generated) values", + ) + .onClick(() => { + this.reset(); + console.log("(SW-CM6) Configuration reset"); + }), + ) + .addButton((button) => { + button + .setIcon("save") + .setTooltip("Save current values") + .onClick(async () => { + await this.save(); + }); + this.saveButton = button.buttonEl; + }); + + new Setting(this.containerEl) + .setName("Suppress plugin styles") + .setDesc( + "Enable to remove plugin styles. You will need to define your own snippet to customize the appearance of whitespace", + ) + .addToggle((toggle) => + toggle + .setValue(this.newSettings.disablePluginStyles) + .onChange(async (value) => { + const redraw = + value != this.newSettings.disablePluginStyles; + this.newSettings.disablePluginStyles = value; + if (redraw) { + this.drawElements(); + } + }), + ); + + new Setting(this.containerEl) + .setName("Always show blockquote markers") + .setDesc("Show the leading > for blockquotes in Live Preview") + .addToggle((toggle) => + toggle + .setValue(this.newSettings.showBlockquoteMarkers) + .onChange(async (value) => { + const redraw = + value != this.newSettings.showBlockquoteMarkers; + this.newSettings.showBlockquoteMarkers = value; + if (redraw) { + this.drawElements(); + } + }), + ); + + new Setting(this.containerEl) + .setName("Show all whitespace characters in code blocks") + .setDesc( + "Add a marker for all whitespace characters in code blocks (included in Show all whitespace)", + ) + .addToggle((toggle) => + toggle + .setValue(this.newSettings.showCodeblockWhitespace) + .onChange(async (value) => { + value = value || this.newSettings.showAllWhitespace; + const redraw = + value != this.newSettings.showCodeblockWhitespace; + this.newSettings.showCodeblockWhitespace = value; + if (redraw) { + this.drawElements(); + } + }), + ); + + new Setting(this.containerEl) + .setName("Show all whitespace characters") + .setDesc( + "Add a marker for all whitespace characters, even those between words", + ) + .addToggle((toggle) => + toggle + .setValue(this.newSettings.showAllWhitespace) + .onChange(async (value) => { + const redraw = + value != this.newSettings.showAllWhitespace; + this.newSettings.showAllWhitespace = value; + if (redraw) { + this.drawElements(); + } + }), + ); + + new Setting(this.containerEl) + .setName("Outline list markers") + .setDesc( + "Add a style to space reserved by list markers (e.g. ' -' or ' 1.')", + ) + .addToggle((toggle) => + toggle + .setValue(this.newSettings.outlineListMarkers) + .onChange(async (value) => { + const redraw = + value != this.newSettings.outlineListMarkers; + this.newSettings.outlineListMarkers = value; + if (redraw) { + this.drawElements(); + } + }), + ); + } + + /** Save on exit */ + hide(): void { + this.save(); + } +}