mirror of
https://github.com/kotaindah55/extended-markdown-syntax.git
synced 2026-07-22 12:00:23 +00:00
feat: add ability to change the tag display behavior and the highlight colors
This commit is contained in:
parent
cd9ac9d6cf
commit
784532b1d2
18 changed files with 634 additions and 103 deletions
5
src/enums/DisplayBehaviour.ts
Normal file
5
src/enums/DisplayBehaviour.ts
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
export enum DisplayBehaviour {
|
||||
ALWAYS,
|
||||
TAG_TOUCHED,
|
||||
SYNTAX_TOUCHED
|
||||
}
|
||||
9
src/enums/Field.ts
Normal file
9
src/enums/Field.ts
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
export enum Field {
|
||||
TOGGLE,
|
||||
MULTI_TOGGLE,
|
||||
DROPDOWN,
|
||||
COLOR,
|
||||
TEXT,
|
||||
TEXT_AREA,
|
||||
SLIDER
|
||||
}
|
||||
4
src/enums/Theme.ts
Normal file
4
src/enums/Theme.ts
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
export enum Theme {
|
||||
LIGHT,
|
||||
DARK
|
||||
}
|
||||
|
|
@ -1,5 +1,9 @@
|
|||
export * from "./LineCtx";
|
||||
export * from "./TokenRole";
|
||||
export * from "./Delimiter";
|
||||
export * from "./TokenStatus";
|
||||
export * from "./Format";
|
||||
export * from "./SettingOpt1";
|
||||
export * from "./MarkdownViewMode";
|
||||
export * from "./TokenLevel";
|
||||
export * from "./Field";
|
||||
export * from "./DisplayBehaviour";
|
||||
export * from "./Theme";
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
import { SettingOpt1 } from "src/enums";
|
||||
import { PluginSettings } from "src/types";
|
||||
|
||||
export const DEFAULT_SETTINGS: PluginSettings = {
|
||||
insertion: SettingOpt1.ALL,
|
||||
spoiler: SettingOpt1.ALL,
|
||||
superscript: SettingOpt1.ALL,
|
||||
subscript: SettingOpt1.ALL,
|
||||
customHighlight: SettingOpt1.ALL,
|
||||
customAlign: SettingOpt1.ALL,
|
||||
editorEscape: false,
|
||||
colorButton: true
|
||||
};
|
||||
8
src/settings/configs/ALWAYS_SHOW_DROPDOWN.ts
Normal file
8
src/settings/configs/ALWAYS_SHOW_DROPDOWN.ts
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
import { MarkdownViewMode } from "src/enums";
|
||||
|
||||
export const ALWAYS_SHOW_DROPDOWN: Record<MarkdownViewMode, string> = {
|
||||
[MarkdownViewMode.NONE]: "Default",
|
||||
[MarkdownViewMode.EDITOR_MODE]: "Editor only",
|
||||
[MarkdownViewMode.PREVIEW_MODE]: "Preview only",
|
||||
[MarkdownViewMode.ALL]: "Both editor and preview"
|
||||
};
|
||||
24
src/settings/configs/DEFAULT_SETTINGS.ts
Normal file
24
src/settings/configs/DEFAULT_SETTINGS.ts
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
import { getDefaultColorConfigs } from "src/color-management";
|
||||
import { DisplayBehaviour, MarkdownViewMode } from "src/enums";
|
||||
import { PluginSettings } from "src/types";
|
||||
|
||||
export const DEFAULT_SETTINGS: PluginSettings = {
|
||||
insertion: MarkdownViewMode.ALL,
|
||||
spoiler: MarkdownViewMode.ALL,
|
||||
superscript: MarkdownViewMode.ALL,
|
||||
subscript: MarkdownViewMode.ALL,
|
||||
customHighlight: MarkdownViewMode.ALL,
|
||||
customSpan: MarkdownViewMode.ALL,
|
||||
fencedDiv: MarkdownViewMode.ALL,
|
||||
editorEscape: false,
|
||||
colorButton: true,
|
||||
decoratePDF: true,
|
||||
colorConfigs: getDefaultColorConfigs(),
|
||||
lightModeHlOpacity: 0.4,
|
||||
darkModeHlOpacity: 0.5,
|
||||
hlTagDisplayBehaviour: DisplayBehaviour.SYNTAX_TOUCHED,
|
||||
spanTagDisplayBehaviour: DisplayBehaviour.SYNTAX_TOUCHED,
|
||||
showHlTagInPreviewMode: false,
|
||||
showSpanTagInPreviewMode: false,
|
||||
alwaysShowFencedDivTag: MarkdownViewMode.NONE
|
||||
};
|
||||
7
src/settings/configs/DISPLAY_BEHAVIOUR_DROPDOWN.ts
Normal file
7
src/settings/configs/DISPLAY_BEHAVIOUR_DROPDOWN.ts
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
import { DisplayBehaviour } from "src/enums";
|
||||
|
||||
export const DISPLAY_BEHAVIOUR_DROPDOWN: Record<DisplayBehaviour, string> = {
|
||||
[DisplayBehaviour.ALWAYS]: "Always visible",
|
||||
[DisplayBehaviour.TAG_TOUCHED]: "When touching the tag itself",
|
||||
[DisplayBehaviour.SYNTAX_TOUCHED]: "When touching its syntax"
|
||||
}
|
||||
8
src/settings/configs/MARKDOWN_VIEW_MODE_DROPDOWN.ts
Normal file
8
src/settings/configs/MARKDOWN_VIEW_MODE_DROPDOWN.ts
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
import { MarkdownViewMode } from "src/enums";
|
||||
|
||||
export const MARKDOWN_VIEW_MODE_DROPDOWN: Record<MarkdownViewMode, string> = {
|
||||
[MarkdownViewMode.NONE]: "Disable all",
|
||||
[MarkdownViewMode.EDITOR_MODE]: "Editor only",
|
||||
[MarkdownViewMode.PREVIEW_MODE]: "Preview only",
|
||||
[MarkdownViewMode.ALL]: "Enable all"
|
||||
};
|
||||
5
src/settings/configs/index.ts
Normal file
5
src/settings/configs/index.ts
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
export * from "./MARKDOWN_VIEW_MODE_DROPDOWN";
|
||||
export * from "./DEFAULT_SETTINGS";
|
||||
export * from "./retrieveSettingUIConfigs";
|
||||
export * from "./DISPLAY_BEHAVIOUR_DROPDOWN";
|
||||
export * from "./ALWAYS_SHOW_DROPDOWN";
|
||||
236
src/settings/configs/retrieveSettingUIConfigs.ts
Normal file
236
src/settings/configs/retrieveSettingUIConfigs.ts
Normal file
|
|
@ -0,0 +1,236 @@
|
|||
import { Field, Theme } from "src/enums";
|
||||
import { PluginSettings, SettingRoot } from "src/types";
|
||||
import { ALWAYS_SHOW_DROPDOWN, DISPLAY_BEHAVIOUR_DROPDOWN, MARKDOWN_VIEW_MODE_DROPDOWN } from "src/settings/configs";
|
||||
|
||||
/**
|
||||
* Main configuration of the setting interface.
|
||||
*/
|
||||
export function retrieveSettingUIConfigs(settings: PluginSettings): SettingRoot<PluginSettings> {
|
||||
return [{
|
||||
items: [{
|
||||
name: "Insertion (underline)",
|
||||
desc: "Use double plus (\"++\") as a delimiter.",
|
||||
fields: [{
|
||||
type: Field.DROPDOWN,
|
||||
record: settings,
|
||||
key: "insertion",
|
||||
spec: {
|
||||
options: MARKDOWN_VIEW_MODE_DROPDOWN
|
||||
},
|
||||
update: { internal: true }
|
||||
}]
|
||||
}, {
|
||||
name: "Discord-flavored spoiler",
|
||||
desc: "Use double bars (\"||\") as a delimiter.",
|
||||
fields: [{
|
||||
type: Field.DROPDOWN,
|
||||
record: settings,
|
||||
key: "spoiler",
|
||||
spec: {
|
||||
options: MARKDOWN_VIEW_MODE_DROPDOWN
|
||||
},
|
||||
update: { internal: true }
|
||||
}]
|
||||
}, {
|
||||
name: "Pandoc-style superscript",
|
||||
desc: "Use a single caret (\"^\") as a delimiter.",
|
||||
fields: [{
|
||||
type: Field.DROPDOWN,
|
||||
record: settings,
|
||||
key: "superscript",
|
||||
spec: {
|
||||
options: MARKDOWN_VIEW_MODE_DROPDOWN
|
||||
},
|
||||
update: { internal: true }
|
||||
}]
|
||||
}, {
|
||||
name: "Pandoc-style subscript",
|
||||
desc: "Use a single tilde (\"~\") as a delimiter.",
|
||||
fields: [{
|
||||
type: Field.DROPDOWN,
|
||||
record: settings,
|
||||
key: "subscript",
|
||||
spec: {
|
||||
options: MARKDOWN_VIEW_MODE_DROPDOWN
|
||||
},
|
||||
update: { internal: true }
|
||||
}]
|
||||
}, {
|
||||
name: "Highlight color tag",
|
||||
desc: "Use alphanumeric and hyphen characters (\"A-Za-z0-9-\") after the opening delimiter covered by curly brackets (\"{}\").",
|
||||
fields: [{
|
||||
type: Field.DROPDOWN,
|
||||
record: settings,
|
||||
key: "customHighlight",
|
||||
spec: {
|
||||
options: MARKDOWN_VIEW_MODE_DROPDOWN
|
||||
},
|
||||
update: { internal: true }
|
||||
}]
|
||||
}, {
|
||||
name: "Custom span",
|
||||
desc: "Use double exclamation marks (\"!!\") as a delimiter. Can be inserted after the " +
|
||||
"opening delimiter by a tag with the same way as highlight tag. " +
|
||||
"Additionally, you can use multiple classes inside it, separated by space(s).",
|
||||
fields: [{
|
||||
type: Field.DROPDOWN,
|
||||
record: settings,
|
||||
key: "customSpan",
|
||||
spec: {
|
||||
options: MARKDOWN_VIEW_MODE_DROPDOWN
|
||||
},
|
||||
update: { internal: true }
|
||||
}]
|
||||
}, {
|
||||
name: "Pandoc-style fenced div (custom block)",
|
||||
desc: "Use three colons (\":::\") or more at the beginning of a paragraph, " +
|
||||
"followed by alphanumeric and hyphen character (\"A-Za-z0-9\") after them. Use space to separate each class.",
|
||||
fields: [{
|
||||
type: Field.DROPDOWN,
|
||||
record: settings,
|
||||
key: "fencedDiv",
|
||||
spec: {
|
||||
options: MARKDOWN_VIEW_MODE_DROPDOWN
|
||||
},
|
||||
update: { internal: true }
|
||||
}]
|
||||
}]
|
||||
}, {
|
||||
heading: "Tag display behaviour",
|
||||
collapsible: true,
|
||||
items: [{
|
||||
name: "Highlight tag in live-preview mode",
|
||||
desc: "Tags can either always be visible, or when they meet particular condition.",
|
||||
fields: [{
|
||||
type: Field.DROPDOWN,
|
||||
record: settings,
|
||||
key: "hlTagDisplayBehaviour",
|
||||
spec: {
|
||||
options: DISPLAY_BEHAVIOUR_DROPDOWN
|
||||
},
|
||||
update: { internal: true }
|
||||
}]
|
||||
}, {
|
||||
name: "Custom span tag in live-preview mode",
|
||||
desc: "Tags can either always be visible, or when they meet particular condition.",
|
||||
fields: [{
|
||||
type: Field.DROPDOWN,
|
||||
record: settings,
|
||||
key: "spanTagDisplayBehaviour",
|
||||
spec: {
|
||||
options: DISPLAY_BEHAVIOUR_DROPDOWN
|
||||
},
|
||||
update: { internal: true }
|
||||
}]
|
||||
}, {
|
||||
name: "Highlight tag in preview mode",
|
||||
desc: "Show or hide highlight color tag in the preview mode.",
|
||||
fields: [{
|
||||
type: Field.TOGGLE,
|
||||
record: settings,
|
||||
key: "showHlTagInPreviewMode",
|
||||
spec: null,
|
||||
update: { internal: true }
|
||||
}]
|
||||
}, {
|
||||
name: "Custom span tag in preview mode",
|
||||
desc: "Show or hide custom span tag in the preview mode.",
|
||||
fields: [{
|
||||
type: Field.TOGGLE,
|
||||
record: settings,
|
||||
key: "showSpanTagInPreviewMode",
|
||||
spec: null,
|
||||
update: { internal: true }
|
||||
}]
|
||||
}, {
|
||||
name: "Always show fenced div tag",
|
||||
desc: "By default, the tag is always hidden in the preview mode, " +
|
||||
"and only displayed when touching the cursor or selection in the live preview mode.",
|
||||
fields: [{
|
||||
type: Field.DROPDOWN,
|
||||
record: settings,
|
||||
key: "alwaysShowFencedDivTag",
|
||||
spec: {
|
||||
options: ALWAYS_SHOW_DROPDOWN
|
||||
},
|
||||
update: { internal: true }
|
||||
}]
|
||||
}]
|
||||
}, {
|
||||
heading: "Customize highlight",
|
||||
collapsible: true,
|
||||
items: [{
|
||||
name: "Color button",
|
||||
desc: "Display a button after highlight opening delimiter, used to open the color menu.",
|
||||
fields: [{
|
||||
type: Field.TOGGLE,
|
||||
record: settings,
|
||||
key: "colorButton",
|
||||
spec: null,
|
||||
update: { internal: true }
|
||||
}]
|
||||
}, {
|
||||
name: "Color opacity in light mode",
|
||||
desc: "Adjust highlight opacity in light mode. Zero means that will be fully transparent.",
|
||||
fields: [{
|
||||
type: Field.SLIDER,
|
||||
record: settings,
|
||||
key: "lightModeHlOpacity",
|
||||
spec: {
|
||||
min: 0,
|
||||
max: 1,
|
||||
step: 0.01
|
||||
},
|
||||
callback: (slider, plugin) => {
|
||||
plugin.setHlOpacity(slider.getValue(), Theme.LIGHT);
|
||||
},
|
||||
update: { stylesheet: true }
|
||||
}]
|
||||
}, {
|
||||
name: "Color opacity in dark mode",
|
||||
desc: "Adjust highlight opacity in dark mode. Zero means that will be fully transparent.",
|
||||
fields: [{
|
||||
type: Field.SLIDER,
|
||||
record: settings,
|
||||
key: "darkModeHlOpacity",
|
||||
spec: {
|
||||
min: 0,
|
||||
max: 1,
|
||||
step: 0.01
|
||||
},
|
||||
callback: (slider, plugin) => {
|
||||
plugin.setHlOpacity(slider.getValue(), Theme.DARK);
|
||||
},
|
||||
update: { stylesheet: true }
|
||||
}]
|
||||
}, {
|
||||
name: "Customize the colors",
|
||||
desc: "The first text field gives the name of the item in the color menu, " +
|
||||
"and the second one sets the tag string to be used in highlight syntax.",
|
||||
preservedForColorSettings: true
|
||||
}]
|
||||
}, {
|
||||
heading: "Others",
|
||||
collapsible: true,
|
||||
items: [{
|
||||
name: "Delimiter escaping",
|
||||
desc: "Use backslash as a delimiter escaper. Works only in the editor mode.",
|
||||
fields: [{
|
||||
type: Field.TOGGLE,
|
||||
record: settings,
|
||||
key: "editorEscape",
|
||||
spec: null,
|
||||
update: { internal: true }
|
||||
}]
|
||||
}, {
|
||||
name: "Parse exported PDF",
|
||||
desc: "Parse syntax on an exported PDF.",
|
||||
fields: [{
|
||||
type: Field.TOGGLE,
|
||||
record: settings,
|
||||
key: "decoratePDF",
|
||||
spec: null
|
||||
}]
|
||||
}]
|
||||
}];
|
||||
};
|
||||
|
|
@ -1 +1 @@
|
|||
export * from "./DEFAULT_SETTINGS";
|
||||
export * from "./configs/DEFAULT_SETTINGS";
|
||||
299
src/settings/interface/ExtendedSettingTab.ts
Normal file
299
src/settings/interface/ExtendedSettingTab.ts
Normal file
|
|
@ -0,0 +1,299 @@
|
|||
import * as Plugin from 'main'
|
||||
import { App, IconName, PluginSettingTab, Setting } from 'obsidian';
|
||||
import { Field, MarkdownViewMode, DisplayBehaviour } from 'src/enums';
|
||||
import { retrieveSettingUIConfigs } from 'src/settings/configs';
|
||||
import { ColorConfig, DropdownFieldDesc, MultiToggleFieldDesc, PluginSettings, SettingGroup, SettingItem, SettingRoot, SliderFieldDesc, ToggleFieldDesc } from 'src/types';
|
||||
import { collapseElsBelow, insertButton } from 'src/settings/interface/utils';
|
||||
import { createCSSRuleFromColorConfig } from 'src/color-management';
|
||||
import { moveElement } from 'src/utils';
|
||||
|
||||
export class ExtendedSettingTab extends PluginSettingTab {
|
||||
plugin: Plugin.default;
|
||||
colorSettingItems: Setting[] = [];
|
||||
refreshInternal = false;
|
||||
rebuildStyleSheet = false;
|
||||
constructor(app: App, plugin: Plugin.default) {
|
||||
super(app, plugin);
|
||||
this.plugin = plugin;
|
||||
}
|
||||
saveSettings(spec?: { internal?: boolean, stylesheet?: boolean }) {
|
||||
this.plugin.saveSettings();
|
||||
if (spec?.internal) {
|
||||
this.refreshInternal = true;
|
||||
}
|
||||
if (spec?.stylesheet) {
|
||||
this.rebuildStyleSheet = true;
|
||||
}
|
||||
}
|
||||
display(): void {
|
||||
let { containerEl } = this,
|
||||
{ settings } = this.plugin;
|
||||
containerEl.empty();
|
||||
let settingsUIConfig = retrieveSettingUIConfigs(settings);
|
||||
this.drawFromConfig(settingsUIConfig, containerEl);
|
||||
}
|
||||
hide(): void {
|
||||
if (this.refreshInternal) {
|
||||
this.plugin.refreshMarkdownView();
|
||||
}
|
||||
if (this.rebuildStyleSheet) {
|
||||
this.plugin.rebuildColorsStyleSheet();
|
||||
}
|
||||
this.refreshInternal = this.rebuildStyleSheet = false;
|
||||
this.colorSettingItems.splice(0);
|
||||
super.hide();
|
||||
}
|
||||
removeSetting(setting: Setting) {
|
||||
setting.clear();
|
||||
setting.settingEl.remove();
|
||||
}
|
||||
drawFromConfig(config: SettingRoot<PluginSettings>, containerEl: HTMLElement) {
|
||||
for (let group of config) {
|
||||
if (group.heading) { this.drawHeading(group, containerEl) }
|
||||
for (let item of group.items) {
|
||||
this.drawSettingItem(item, containerEl, group.collapsible);
|
||||
if (item.preservedForColorSettings) { this.drawColorSettings(containerEl, group.collapsible) }
|
||||
}
|
||||
}
|
||||
}
|
||||
drawHeading(group: SettingGroup<PluginSettings>, containerEl: HTMLElement) {
|
||||
if (!group.heading) { return }
|
||||
let heading = new Setting(containerEl)
|
||||
.setHeading()
|
||||
.setName(group.heading);
|
||||
if (group.desc) {
|
||||
heading.setDesc(group.desc);
|
||||
}
|
||||
if (group.collapsible) {
|
||||
heading.addExtraButton(btn => {
|
||||
let btnEl = btn.extraSettingsEl;
|
||||
btn
|
||||
.setIcon("chevron-down")
|
||||
.setTooltip("Collapse", { placement: "bottom" })
|
||||
.onClick(() => {
|
||||
let btnEl = btn.extraSettingsEl;
|
||||
collapseElsBelow(heading.settingEl);
|
||||
if (btnEl.hasClass("collapsing")) {
|
||||
btn.setTooltip("Collapse", { placement: "bottom" });
|
||||
btnEl.removeClass("collapsing");
|
||||
} else {
|
||||
btn.setTooltip("Expand", { placement: "bottom" });
|
||||
btnEl.addClass("collapsing");
|
||||
}
|
||||
});
|
||||
btnEl.addClass("collapse-button", "ems-button");
|
||||
});
|
||||
heading.controlEl.addClass("collapse-control");
|
||||
}
|
||||
}
|
||||
drawSettingItem(item: SettingItem<PluginSettings>, containerEl: HTMLElement, collapsible?: boolean) {
|
||||
let setting = new Setting(containerEl).setName(item.name);
|
||||
if (item.desc) {
|
||||
setting.setDesc(item.desc);
|
||||
}
|
||||
if (collapsible) {
|
||||
setting.setClass("is-collapsible")
|
||||
}
|
||||
if (item.fields) {
|
||||
for (let field of item.fields) {
|
||||
if (field.type == Field.TOGGLE) { this.setToggleField(field, setting) }
|
||||
else if (field.type == Field.DROPDOWN) { this.setDropdownField(field, setting) }
|
||||
else if (field.type == Field.MULTI_TOGGLE) { this.setMultiToggleField(field, setting) }
|
||||
else if (field.type == Field.SLIDER) { this.setSliderField(field, setting) }
|
||||
}
|
||||
}
|
||||
}
|
||||
drawColorSettings(containerEl: HTMLElement, collapsible?: boolean) {
|
||||
let colorConfigs = this.plugin.settings.colorConfigs,
|
||||
groupEl = containerEl.createDiv({ cls: ["setting-item", "setting-group", "ems-setting-group"] });
|
||||
if (collapsible) { groupEl.addClass("is-collapsible") }
|
||||
colorConfigs.forEach(config => {
|
||||
this.setColorItem(config, colorConfigs, groupEl);
|
||||
});
|
||||
let controlSetting = new Setting(containerEl);
|
||||
insertButton(controlSetting, "Add color", false, () => {
|
||||
this.plugin.addNewColor();
|
||||
let newSetting = this.setColorItem(colorConfigs.at(-1)!, colorConfigs, groupEl);
|
||||
newSetting.controlEl.querySelector<HTMLElement>(".ems-field-tag")?.focus();
|
||||
this.saveSettings({ internal: false, stylesheet: false });
|
||||
});
|
||||
insertButton(controlSetting, "Reset to default", true, () => {
|
||||
this.colorSettingItems.forEach(setting => {
|
||||
this.removeSetting(setting);
|
||||
});
|
||||
this.colorSettingItems.splice(0);
|
||||
this.plugin.revertColorConfigs((config, configs) => {
|
||||
this.setColorItem(config, configs, groupEl);
|
||||
});
|
||||
this.saveSettings({ internal: false, stylesheet: true });
|
||||
});
|
||||
if (collapsible) {
|
||||
controlSetting.setClass("is-collapsible");
|
||||
}
|
||||
}
|
||||
setColorItem(config: ColorConfig, configArr: ColorConfig[], containerEl: HTMLElement) {
|
||||
if (/[^a-z0-9-]/i.test(config.tag)) { config.tag = config.tag.replaceAll(/[^a-z0-9-]/ig, "") }
|
||||
let colorSetting = new Setting(containerEl)
|
||||
.setClass("ems-setting-item")
|
||||
.setClass("ems-highlight-color-config")
|
||||
.addText(text => {
|
||||
text.setPlaceholder("Color name");
|
||||
text.setValue(config.name);
|
||||
text.inputEl.addClasses(["ems-field", "ems-field-name"]);
|
||||
text.onChange(name => {
|
||||
config.name = name;
|
||||
this.saveSettings({ internal: false, stylesheet: false });
|
||||
});
|
||||
})
|
||||
.addExtraButton(btn => {
|
||||
let btnEl = btn.extraSettingsEl;
|
||||
btnEl.addClasses(["ems-button", "ems-button-delete"]);
|
||||
btn.setIcon("trash");
|
||||
btn.setTooltip("Delete");
|
||||
btn.onClick(() => {
|
||||
let index = configArr.findIndex(target => target == config);
|
||||
configArr.splice(index, 1);
|
||||
this.colorSettingItems.splice(index, 1);
|
||||
this.plugin.colorsHandler.removeSingle(index);
|
||||
this.removeSetting(colorSetting);
|
||||
this.saveSettings({ internal: false, stylesheet: true });
|
||||
});
|
||||
})
|
||||
.addExtraButton(btn => {
|
||||
btn.extraSettingsEl.addClasses(["ems-button", "ems-button-shift-up"]);
|
||||
btn.setIcon("arrow-up");
|
||||
btn.setTooltip("Shift up");
|
||||
btn.onClick(() => {
|
||||
let index = configArr.findIndex(target => target == config);
|
||||
if (index) {
|
||||
moveElement(colorSetting.settingEl, -1)
|
||||
configArr.splice(index - 1, 0, configArr.splice(index, 1)[0]);
|
||||
this.plugin.colorsHandler.moveSingleRule(index, -1);
|
||||
this.saveSettings({ internal: false, stylesheet: true });
|
||||
}
|
||||
});
|
||||
})
|
||||
.addExtraButton(btn => {
|
||||
btn.extraSettingsEl.addClasses(["ems-button", "ems-button-shift-down"]);
|
||||
btn.setIcon("arrow-down");
|
||||
btn.setTooltip("Shift down");
|
||||
btn.onClick(() => {
|
||||
let index = configArr.findIndex(target => target == config);
|
||||
if (index < configArr.length - 1) {
|
||||
moveElement(colorSetting.settingEl, 1)
|
||||
configArr.splice(index, 0, configArr.splice(index + 1, 1)[0]);
|
||||
this.plugin.colorsHandler.moveSingleRule(index, 1);
|
||||
this.saveSettings({ internal: false, stylesheet: true });
|
||||
}
|
||||
});
|
||||
})
|
||||
.addExtraButton(btn => {
|
||||
btn.extraSettingsEl.addClasses(["ems-button", "ems-button-toggle-show-hide"]);
|
||||
btn.setIcon(config.showInMenu ? "eye" : "eye-off");
|
||||
btn.setTooltip("Show/hide menu item");
|
||||
btn.onClick(() => {
|
||||
config.showInMenu = !config.showInMenu;
|
||||
btn.setIcon(config.showInMenu ? "eye" : "eye-off");
|
||||
this.saveSettings({ internal: false, stylesheet: false })
|
||||
});
|
||||
})
|
||||
.addText(text => {
|
||||
text.setPlaceholder("Tag string");
|
||||
text.inputEl.addClasses(["ems-field", "ems-field-tag"]);
|
||||
text.setValue(config.tag);
|
||||
text.onChange(tag => {
|
||||
config.tag = tag.replaceAll(/[^a-z0-9-]/gi, "");
|
||||
text.setValue(config.tag);
|
||||
let index = configArr.findIndex(target => target == config),
|
||||
ruleStr = createCSSRuleFromColorConfig(config);
|
||||
this.plugin.colorsHandler.replace(ruleStr, index);
|
||||
this.saveSettings({ internal: false, stylesheet: true });
|
||||
});
|
||||
})
|
||||
.addColorPicker(picker => {
|
||||
picker.setValue(config.color);
|
||||
picker.colorPickerEl.addClasses(["ems-field", "ems-field-color-picker"]);
|
||||
picker.onChange(color => {
|
||||
config.color = color;
|
||||
let index = configArr.findIndex(target => target == config),
|
||||
ruleStr = createCSSRuleFromColorConfig(config);
|
||||
this.plugin.colorsHandler.replace(ruleStr, index);
|
||||
this.saveSettings({ internal: false, stylesheet: true });
|
||||
});
|
||||
});
|
||||
this.colorSettingItems.push(colorSetting);
|
||||
return colorSetting;
|
||||
}
|
||||
setToggleField(field: ToggleFieldDesc<PluginSettings>, setting: Setting) {
|
||||
setting.addToggle(toggle => {
|
||||
let { record, key } = field;
|
||||
toggle.setValue(record[key]);
|
||||
toggle.onChange(val => {
|
||||
record[key] = val;
|
||||
this.saveSettings(field.update);
|
||||
if (field.callback) {
|
||||
field.callback(toggle, this.plugin);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
setDropdownField(field: DropdownFieldDesc<PluginSettings>, setting: Setting) {
|
||||
setting.addDropdown(dropdown => {
|
||||
let { record, key } = field;
|
||||
dropdown.addOptions(field.spec.options);
|
||||
dropdown.setValue(record[key].toString());
|
||||
dropdown.onChange(val => {
|
||||
(record[key] as MarkdownViewMode | DisplayBehaviour) = parseInt(val);
|
||||
this.saveSettings(field.update);
|
||||
if (field.callback) {
|
||||
field.callback(dropdown, this.plugin);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
setMultiToggleField(field: MultiToggleFieldDesc<PluginSettings>, setting: Setting) {
|
||||
let { record, key } = field,
|
||||
value = record[key],
|
||||
options = field.spec.options as Record<typeof value, { icon: IconName, tooltip?: string }>,
|
||||
optionMap: string[] = (() => {
|
||||
let optionMap = [];
|
||||
for (let opt in options) { optionMap.push(opt) };
|
||||
return optionMap;
|
||||
})(),
|
||||
index = optionMap.findIndex(val => val === value.toString());
|
||||
setting.addExtraButton(btn => {
|
||||
let { icon, tooltip } = options[value];
|
||||
btn.setIcon(icon);
|
||||
btn.setTooltip(tooltip ?? "");
|
||||
btn.onClick(() => {
|
||||
if (index + 1 >= optionMap.length) { index = 0 }
|
||||
else { index++ }
|
||||
let changedVal = parseInt(optionMap[index]) as typeof value,
|
||||
{ icon, tooltip } = options[changedVal];
|
||||
btn.setIcon(icon);
|
||||
btn.setTooltip(tooltip ?? "");
|
||||
(record[key] as MarkdownViewMode | DisplayBehaviour) = changedVal;
|
||||
this.saveSettings(field.update);
|
||||
if (field.callback) {
|
||||
field.callback(btn, this.plugin);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
setSliderField(field: SliderFieldDesc<PluginSettings>, setting: Setting) {
|
||||
setting.addSlider(slider => {
|
||||
let { record, key, spec } = field;
|
||||
slider.setInstant(false);
|
||||
slider.setDynamicTooltip();
|
||||
slider.setLimits(spec.min, spec.max, spec.step);
|
||||
slider.setValue(record[key]);
|
||||
slider.onChange(val => {
|
||||
(record[key] as number) = val;
|
||||
this.saveSettings(field.update);
|
||||
if (field.callback) {
|
||||
field.callback(slider, this.plugin);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -1,86 +0,0 @@
|
|||
import * as Plugin from 'main'
|
||||
import { App, PluginSettingTab, Setting } from 'obsidian';
|
||||
import { SettingOpt1 } from 'src/enums';
|
||||
|
||||
const DROPDOWN_OPTIONS_1: Record<SettingOpt1, string> = {
|
||||
[SettingOpt1.DISABLED]: "Disable all",
|
||||
[SettingOpt1.EDITOR_MODE]: "Editor only",
|
||||
[SettingOpt1.PREVIEW_MODE]: "Preview only",
|
||||
[SettingOpt1.ALL]: "Enable all"
|
||||
};
|
||||
|
||||
export class SettingTab extends PluginSettingTab {
|
||||
plugin: Plugin.default;
|
||||
constructor(app: App, plugin: Plugin.default) {
|
||||
super(app, plugin);
|
||||
this.plugin = plugin;
|
||||
}
|
||||
display(): void {
|
||||
let { containerEl } = this,
|
||||
{ settings } = this.plugin;
|
||||
this.plugin.areSettingsChanged = false;
|
||||
containerEl.empty();
|
||||
new Setting(containerEl)
|
||||
.setName("Insertion (underline)")
|
||||
.setDesc("Use double plus (\"++\") as a delimiter.")
|
||||
.addDropdown((dropdown) => {
|
||||
dropdown.addOptions(DROPDOWN_OPTIONS_1);
|
||||
dropdown.setValue(settings.insertion.toString());
|
||||
dropdown.onChange((val) => { settings.insertion = parseInt(val); this.plugin.saveSettings() });
|
||||
});
|
||||
new Setting(containerEl)
|
||||
.setName("Discord flavoured spoiler")
|
||||
.setDesc("Use double bars (\"||\") as a delimiter.")
|
||||
.addDropdown((dropdown) => {
|
||||
dropdown.addOptions(DROPDOWN_OPTIONS_1);
|
||||
dropdown.setValue(settings.spoiler.toString());
|
||||
dropdown.onChange((val) => { settings.spoiler = parseInt(val); this.plugin.saveSettings() });
|
||||
});
|
||||
new Setting(containerEl)
|
||||
.setName("Pandoc-style superscript")
|
||||
.setDesc("Use single caret (\"^\") as a delimiter.")
|
||||
.addDropdown((dropdown) => {
|
||||
dropdown.addOptions(DROPDOWN_OPTIONS_1);
|
||||
dropdown.setValue(settings.superscript.toString());
|
||||
dropdown.onChange((val) => { settings.superscript = parseInt(val); this.plugin.saveSettings() });
|
||||
});
|
||||
new Setting(containerEl)
|
||||
.setName("Pandoc-style subscript")
|
||||
.setDesc("Use single tilde (\"~\") as a delimiter.")
|
||||
.addDropdown((dropdown) => {
|
||||
dropdown.addOptions(DROPDOWN_OPTIONS_1);
|
||||
dropdown.setValue(settings.subscript.toString());
|
||||
dropdown.onChange((val) => { settings.subscript = parseInt(val); this.plugin.saveSettings() });
|
||||
});
|
||||
new Setting(containerEl)
|
||||
.setName("Custom highlight color")
|
||||
.setDesc("Type at least one, and only, alphanumeric character (\"A-Za-z0-9-_\") after highlight opening covered by curly brackets (\"{}\").")
|
||||
.addDropdown((dropdown) => {
|
||||
dropdown.addOptions(DROPDOWN_OPTIONS_1);
|
||||
dropdown.setValue(settings.customHighlight.toString());
|
||||
dropdown.onChange((val) => { settings.customHighlight = parseInt(val); this.plugin.saveSettings() });
|
||||
});
|
||||
new Setting(containerEl)
|
||||
.setName("Paragraph alignment")
|
||||
.setDesc("Type \"left\", \"right\", \"center\", or \"justify\", covered by two exclamation marks (\"!!\"), and place it in the beginning of line.")
|
||||
.addDropdown((dropdown) => {
|
||||
dropdown.addOptions(DROPDOWN_OPTIONS_1);
|
||||
dropdown.setValue(settings.customAlign.toString());
|
||||
dropdown.onChange((val) => { settings.customAlign = parseInt(val); this.plugin.saveSettings() });
|
||||
});
|
||||
new Setting(containerEl)
|
||||
.setName("Escape delimiter")
|
||||
.setDesc("Use backslash as a delimiter escaper. Works only in editor.")
|
||||
.addToggle((toggle) => {
|
||||
toggle.setValue(settings.editorEscape);
|
||||
toggle.onChange((val) => { settings.editorEscape = val; this.plugin.saveSettings() });
|
||||
});
|
||||
new Setting(containerEl)
|
||||
.setName("Highlight color button")
|
||||
.setDesc("Display button after highlight opening delimiter, used to open a color menu for quick customizing by clicking on it.")
|
||||
.addToggle((toggle) => {
|
||||
toggle.setValue(settings.colorButton);
|
||||
toggle.onChange((val) => { settings.colorButton = val; this.plugin.saveSettings() });
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -1 +1 @@
|
|||
export * from "./SettingTab";
|
||||
export * from "./ExtendedSettingTab";
|
||||
9
src/settings/interface/utils/collapseElsBelow.ts
Normal file
9
src/settings/interface/utils/collapseElsBelow.ts
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
export function collapseElsBelow(rootEl: HTMLElement) {
|
||||
for (let el = rootEl.nextElementSibling; el?.hasClass("is-collapsible"); el = el.nextElementSibling) {
|
||||
if (el.hasClass("collapsed")) {
|
||||
el.removeClass("collapsed");
|
||||
} else {
|
||||
el.addClass("collapsed");
|
||||
}
|
||||
}
|
||||
}
|
||||
2
src/settings/interface/utils/index.ts
Normal file
2
src/settings/interface/utils/index.ts
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
export * from "./insertButton";
|
||||
export * from "./collapseElsBelow";
|
||||
10
src/settings/interface/utils/insertButton.ts
Normal file
10
src/settings/interface/utils/insertButton.ts
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
import { Setting } from "obsidian";
|
||||
|
||||
export function insertButton(setting: Setting, text: string, cta: boolean, onClick: (evt: MouseEvent) => unknown) {
|
||||
setting.addButton(btn => {
|
||||
btn.setButtonText(text);
|
||||
btn.onClick(onClick);
|
||||
if (cta) { btn.setCta() }
|
||||
});
|
||||
return setting;
|
||||
}
|
||||
Loading…
Reference in a new issue