From e14bf3fcc5b02140b95e00be4f87fbac80d0f241 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ula=C5=9F=20F=C4=B1rat=20=C3=96ZDEM=C4=B0R?= Date: Sun, 9 Jun 2024 19:01:30 +0300 Subject: [PATCH] Added two new settings to the plugin: 1) toggle to open new .mw files under current viewed (file's) folder 2) toggle to add different views on context menu 2nd setting semi-adresses the 7th issue. I will be adding commands to command palette as a second smaller update. Added a new command 'markwhen-create-template': Spawns a new file with all supported commands of markwhenview (file is on main folder of plugin markwhen.md, new file is created and populated with its contents, could be edited easily) Fixed a bug where spam/fast clicking open new file on ribbon would cause file creation to throw an error due to name. Bug details: Since the name is being generated on a format with 'DD-MM-YYYY HH.MM.SS', upon clicking new file under the same second would lead the second file throw an error file already exists. This would also mean that you could generate a new file once per second. Basic solution would be to check file existance and append a number at the end of the file. The problem arises when subsequent clicks would also check for subsequent files (think of Nth file under same second, it would need to check base file, 1st extra, 2nd extra... till the N). Since file existance checks are done on disk but not on cache/ram this was a resource hog and possible disk destroyer. I rewrote the file creation system with mutexes so that after file creation it checks for the time with Date.now() and adds a number at the end of the file. Since proper usage of mutexes, the concurrency of async functions are not broken. Since properly handling the time I did not check for file existance at all and it works fine on my machine but feel free to do testing and report any bugs. --- README.md | 2 +- copyAssets.sh | 3 +- manifest.json | 4 +- markwhen.md | 197 ++++++++++++++++++++++++++++ package-lock.json | 18 ++- package.json | 5 +- src/MarkwhenCodemirrorPlugin.ts | 1 + src/MarkwhenView.ts | 98 +++++++++++++- src/main.ts | 225 ++++++++++++++++++++++++++++---- 9 files changed, 512 insertions(+), 41 deletions(-) create mode 100644 markwhen.md diff --git a/README.md b/README.md index df87636..707f31b 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ This plugin integrates [Markwhen](https://github.com/mark-when/markwhen/) into [Obsidian.md](https://obsidian.md/). You can use markwhen syntax to create timelines. > [!Note] -> Latest release: 0.0.2 +> Latest release: 0.0.3 > Document version: 0.0.2 ## Installation diff --git a/copyAssets.sh b/copyAssets.sh index 03d80d1..98431b6 100755 --- a/copyAssets.sh +++ b/copyAssets.sh @@ -2,4 +2,5 @@ cp ./out/* ~/Documents/Obsidian\ Vault/.obsidian/plugins/markwhen cp ./styles.css ~/Documents/Obsidian\ Vault/.obsidian/plugins/markwhen -cp ./manifest.json ~/Documents/Obsidian\ Vault/.obsidian/plugins/markwhen \ No newline at end of file +cp ./manifest.json ~/Documents/Obsidian\ Vault/.obsidian/plugins/markwhen +cp ./markwhen.md ~/Documents/Obsidian\ Vault/.obsidian/plugins/markwhen \ No newline at end of file diff --git a/manifest.json b/manifest.json index 31da89c..81c3293 100644 --- a/manifest.json +++ b/manifest.json @@ -1,10 +1,10 @@ { "id": "markwhen", "name": "Markwhen", - "version": "0.0.2", + "version": "0.0.3", "minAppVersion": "1.0.0", "description": "Create timelines, gantt charts, calendars, and more using markwhen.", "author": "Markwhen", "authorUrl": "https://github.com/mark-when", "isDesktopOnly": true -} \ No newline at end of file +} diff --git a/markwhen.md b/markwhen.md new file mode 100644 index 0000000..4761401 --- /dev/null +++ b/markwhen.md @@ -0,0 +1,197 @@ +--- +title: Welcome to Markwhen! + +edit: + - rob@markwhen.com + +view: \* + +#Project1: #d336b1 +--- +section Welcome #welcome +now: This example timeline showcases some of markwhen's features. + +now: For more information, view the documentation [here](https://docs.markwhen.com) or join the [discord](https://discord.gg/3rTpUD94ac) +#welcome + +now: Note that changes you make here are not saved +If you want to make a new markwhen you should open a tab at the bottom or click open in the sidebar +endSection + +section All Projects +group Project 1 #Project1 +// Supports ISO8601 +2023-01/2023-03: Sub task #John +2023-03/2023-06: Sub task 2 #Michelle +More info about sub task 2 + +- [ ] We need to get this done +- [x] And this +- [ ] This one is extra + +2023-07: Yearly planning +endGroup + group Project 2 #Project2 +2023-04/4 months: Larger sub task #Danielle + +// Supports American date formats +03/2023 - 1 year: Longer ongoing task #Michelle + +- [x] Sub task 1 +- [x] Sub task 2 +- [ ] Sub task 3 +- [ ] Sub task 4 +- [ ] so many checkboxes omg + +10/2023 - 2 months: Holiday season +endGroup + +group Project 3 +01/2024: Project kickoff +02/2024-04/2024: Other stuff +endGroup +endSection + +2023-01-03 every other week for 1 year: Biweekly meeting + +// Events that don't have explicit end dates have inferred ranges - for example, when a year is specified, it lasts from the beginning of that year to the end of it. +2024: A year-long event + +// Inferred ranges are as granular as their definitions. +09/2024: one month + +2025-05-05: one day + +Jan 4 2025 8am: instant + +// You can also be specific with your ranges +2024/2025: An event that lasts two years + +November 8, 2022 9am - November 9, 2023, 10am: one year, one day, and one hour + +now: [More documentation](https://docs.markwhen.com/syntax/events.html) + +// Event descriptions last from the date range definition up to the next event +2029-04-25/2029-05-03: Descriptions can be one line + +2029-04-25/2029-05-03: Or +they can span +multiple lines + +1/27/2025: [] An event can have a checkbox for completion +Put square brackets at the start of the event description + +1/27/2026: [x] To mark an event as completed, put an x in the square brackets + +1/27/2027: Events can have lists + +- [ ] checkbox list item +- [x] a completed checkbox list item +- simple list item +- another simple list item + +1/27/2028 - 1 year: 68% Manually indicate an event's completion with a percentage in the description + +Partially completed events will have their event bar partially filled that amount + +1 year: Links are markdown-style: [This is a link](https://markwhen.com) + +1 year: Images are also markdown-style: +![](https://blog.markwhen.com/images/calendar1.png) + +1 year: Locations (which are more useful for the map view) can be indicated in a similar way: [Hawaii](location) [Alaska](map) + +2024: Refer to other markwhen documents with `@` syntax: @rob + +now: [More documentation](https://docs.markwhen.com/syntax/event-descriptions.html) + +// Events can be grouped together + +group +1/27/2024: Happy birthday +2020-03: Covid started in the US +endGroup + +group Group with title + +Feb 2 2025: Interviewing +Feb 8 2025: Write report +Feb 19 2025: Presentation + +endGroup + +group Groups can contain other groups #big + +group Smaller plan #small #nested + +1 year: Accomplish something + +2 years: Accomplish something else + +endGroup + +1 year: Things are accomplished + +endGroup + +section Sections extend across the screen + +2023: Start year + +section Nested section #nested + +2025: End year + +endSection +endSection + +now: [More documentation](https://docs.markwhen.com/syntax/groups-and-sections.html) + +// Specify tag colors in the header (before any event) +#Timeline: #abf + +now: Events and groups can have tags + +section Tagged events #Timeline +Feb 18 1999: back in the day #Past #The90s +2043: in the future #TheOther90s + +now: [More documentation](https://docs.markwhen.com/syntax/event-descriptions.html#tag) + +2025: Event + +1 year: This event happens immediately after the previous event and lasts for 1 year + +#after + +3 months - 1 month: This event happens 3 months after the previous event and lasts for 1 month +#after + +by 2 weeks - 1 month: This event happens 2 weeks before the previous event and lasts 1 month +#before + + +2023: Event !base + +after !base 1 year - 1 month: This event happens 1 year after the event with with id `base` and lasts for 1 month +#after + +before !base 1 week day - 1 hour: This event happens 1 week day before the event with id `base` and lasts 1 hour +#before + +October 7, 1989 every year for 10 years: ... +2025-03-04 every week for 12 weeks: ... +2022-01/2022-03 every other year x9: ... +Feb 1 2023 every 6 months for 10 times: ... + +// Visually indicate that an event is an era or milestone with the tag #era or #milestone + +2023-06-01/2023-08-20: Summer time #vacation + +2023-08-21/2023-12-17: Back to school + +2023-12-18/2024-01-05: Winter break #vacation #milestone + +2024-01-08/2024-05-31: Back to school + +2024-05-27/2024-05-31: Final project due #milestone diff --git a/package-lock.json b/package-lock.json index 662cd7a..b61b02e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "markwhen", - "version": "0.0.2", + "version": "0.0.3", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "markwhen", - "version": "0.0.2", + "version": "0.0.3", "license": "MIT", "dependencies": { "@codemirror/state": "^6.4.1", @@ -16,7 +16,8 @@ "@markwhen/parser": "^0.10.15", "@markwhen/resume": "^1.1.0", "@markwhen/timeline": "^1.3.3", - "@markwhen/view-client": "^1.4.4" + "@markwhen/view-client": "^1.4.4", + "async-mutex": "^0.5.0" }, "devDependencies": { "@types/node": "^20.12.7", @@ -1527,6 +1528,14 @@ "node": ">=8" } }, + "node_modules/async-mutex": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/async-mutex/-/async-mutex-0.5.0.tgz", + "integrity": "sha512-1A94B18jkJ3DYq284ohPxoXbfTA5HsQ7/Mf4DEhcyLx3Bz27Rh59iScbB6EPiP+B+joue6YCxcMXSbFC1tZKwA==", + "dependencies": { + "tslib": "^2.4.0" + } + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmmirror.com/balanced-match/-/balanced-match-1.0.2.tgz", @@ -2879,8 +2888,7 @@ "node_modules/tslib": { "version": "2.4.0", "resolved": "https://registry.npmmirror.com/tslib/-/tslib-2.4.0.tgz", - "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==", - "dev": true + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" }, "node_modules/tsutils": { "version": "3.21.0", diff --git a/package.json b/package.json index 892d23c..d4b6cee 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "markwhen", - "version": "0.0.2", + "version": "0.0.3", "description": "Markwhen integration for Obsidian.md", "main": "main.js", "type": "module", @@ -33,6 +33,7 @@ "@markwhen/parser": "^0.10.15", "@markwhen/resume": "^1.1.0", "@markwhen/timeline": "^1.3.3", - "@markwhen/view-client": "^1.4.4" + "@markwhen/view-client": "^1.4.4", + "async-mutex": "^0.5.0" } } diff --git a/src/MarkwhenCodemirrorPlugin.ts b/src/MarkwhenCodemirrorPlugin.ts index 8c0f687..05a73ec 100644 --- a/src/MarkwhenCodemirrorPlugin.ts +++ b/src/MarkwhenCodemirrorPlugin.ts @@ -39,6 +39,7 @@ export class MarkwhenCodemirrorPlugin implements PluginValue { view: EditorView; worker = useParserWorker((mw) => { this.markwhen = mw; + this.view.dispatch({ effects: parseResult.of(mw), }); diff --git a/src/MarkwhenView.ts b/src/MarkwhenView.ts index 5b85889..b0b7c50 100644 --- a/src/MarkwhenView.ts +++ b/src/MarkwhenView.ts @@ -1,4 +1,4 @@ -import { WorkspaceLeaf, MarkdownView, TFile, Platform } from 'obsidian'; +import { Menu, WorkspaceLeaf, MarkdownView, TFile, Platform, TAbstractFile } from 'obsidian'; import MarkwhenPlugin from './main'; import { MARKWHEN_ICON } from './icons'; export const VIEW_TYPE_MARKWHEN = 'markwhen-view'; @@ -234,6 +234,102 @@ export class MarkwhenView extends MarkdownView { this.contentEl.addClass('markwhen-view'); }); super.onload(); + + const action= (viewType: ViewType) => async (evt: MouseEvent) => { + if (evt.metaKey || evt.ctrlKey) { + await this.split(viewType); + } else if (this.viewType !== viewType) { + await this.setViewType(viewType); + } + }; + this.registerEvent(this.app.workspace.on('file-menu', (menu, file: TAbstractFile) => { + // Check if the submenu should be displayed + if (this.plugin.settings.actionToContextSettingtoggle) { + /* + let submenuOpen = false; + let submenu: Menu | null = null; + const mainMenuItem = menu.addItem((item) => { + item.setTitle('-Markwhen'); // Main menu item title + item.setIcon(MARKWHEN_ICON); // Main item icon + item.onClick((evt: MouseEvent) => drawmenu()(evt)); + }); + const drawmenu = () => async (evt: MouseEvent) => { + if (!submenuOpen) { + submenuOpen = true; + submenu = new Menu(); + submenu.addItem((item) => { + item.setTitle('Edit Text'); + item.setIcon('pen-line'); + item.onClick((evt: MouseEvent) => handleAction('text')(evt)); + }); + + submenu.addItem((item) => { + item.setTitle('View Calendar'); + item.setIcon('calendar'); + item.onClick((evt: MouseEvent) => handleAction('calendar')(evt)); + }); + + submenu.addItem((item) => { + item.setTitle('View Timeline'); + item.setIcon(MARKWHEN_ICON); // Assuming MARKWHEN_ICON is defined + item.onClick((evt: MouseEvent) => handleAction('timeline')(evt)); + }); + + submenu.addItem((item) => { + item.setTitle('View Vertical Timeline'); + item.setIcon('oneview'); // Assuming MARKWHEN_ICON is defined + item.onClick((evt: MouseEvent) => handleAction('oneview')(evt)); + }); + + submenu.showAtPosition({ x: evt.x, y: evt.y }); + } else { + submenu?.hide(); + submenuOpen = false; + } + };*/ //this draws submenu but closes main menu. Maybe override main menu drawing and custom expose the X and Y coords, or hook contextmenu ?? + + // Add a submenu item for the plugin + const pluginSubMenu = menu.addItem((item) => { + item.setTitle('Markwhen'); // Submenu title + item.setIcon(MARKWHEN_ICON); // Main item icon + }); + + // Add custom actions under the submenu + pluginSubMenu.addItem((item) => { + item.setTitle('Edit Text'); + item.setIcon('pen-line'); + item.onClick((evt: MouseEvent) => handleAction('text')(evt)); + }); + + pluginSubMenu.addItem((item) => { + item.setTitle('View Calendar'); + item.setIcon('calendar'); + item.onClick((evt: MouseEvent) => handleAction('calendar')(evt)); + }); + + pluginSubMenu.addItem((item) => { + item.setTitle('View Timeline'); + item.setIcon(MARKWHEN_ICON); // Assuming MARKWHEN_ICON is defined + item.onClick((evt: MouseEvent) => handleAction('timeline')(evt)); + }); + + pluginSubMenu.addItem((item) => { + item.setTitle('View Vertical Timeline'); + item.setIcon('oneview'); // Assuming MARKWHEN_ICON is defined + item.onClick((evt: MouseEvent) => handleAction('oneview')(evt)); + }); + const handleAction = (viewType: ViewType) => async (evt: MouseEvent) => { + if (file instanceof TFile) { + await this.app.workspace.getLeaf().openFile(file); + await action(viewType)(evt); + } else { + console.error("Selected item is not a file."); + } + }; + + // Add more actions as needed + } + })); } async setViewType(viewType?: ViewType) { diff --git a/src/main.ts b/src/main.ts index 25868b3..38b83e8 100644 --- a/src/main.ts +++ b/src/main.ts @@ -8,38 +8,178 @@ import { normalizePath, TextComponent, ExtraButtonComponent, + ToggleComponent, } from 'obsidian'; +import {Mutex} from 'async-mutex'; + import { MARKWHEN_ICON } from './icons'; import { VIEW_TYPE_MARKWHEN, MarkwhenView } from './MarkwhenView'; +import * as fs from 'fs'; +import * as path from 'path'; + interface MarkwhenPluginSettings { folder: string; + deftoselectedtoggle: boolean; + actionToContextSettingtoggle: boolean; } + const DEFAULT_SETTINGS: MarkwhenPluginSettings = { folder: 'Markwhen', + deftoselectedtoggle: false, + actionToContextSettingtoggle: false, }; + + + export default class MarkwhenPlugin extends Plugin { + public utilities = new class { + constructor(public superThis: MarkwhenPlugin) { + } + public testSetOuterPrivate(target: number) { + } + }(this); + + public fclass = new class { + constructor(public superThis: MarkwhenPlugin) { + + } + private lastCallTime = 0; + private notPassedCount = 1; + private isUpdating = false; + private timeMutex = new Mutex(); + private countMutex = new Mutex(); + + async checkAndCreateFolder(folderPath: string) { + const vault = this.superThis.app.vault; + folderPath = normalizePath(folderPath); + //https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/658 + const folder = vault.getAbstractFileByPathInsensitive(folderPath); + if (folder && folder instanceof TFolder) return; + if (folder && folder instanceof TFile) return; //File name corruption + await vault.createFolder(folderPath); + } + + async createMWFile( + filename: string, + folderPath: string, + initData?: string + ): Promise { + const fname = normalizePath(`${folderPath}/${filename}`); + await this.checkAndCreateFolder(folderPath); + // Acquire the time mutex to ensure exclusive access to the critical section for lastCallTime + const timeRelease = await this.timeMutex.acquire(); + try { + const currentTime = Date.now(); + if (!this.isUpdating && (Math.floor(currentTime / 1000) != Math.floor(this.lastCallTime / 1000))) { + // Set the flag to indicate that the value is being updated + this.isUpdating = true; + + // Release the time mutex to allow other functions to proceed + timeRelease(); + + // Update the value + const file = await this.updateLastCallTime(currentTime, fname, initData); + return file; + } else { + timeRelease(); + // Increment the not passed count + const file = await this.incrementNotPassedCount(fname, initData); + return file; + } + } finally { + // Release the time mutex to allow other functions to proceed + timeRelease(); + } + } + + private async updateLastCallTime( + currentTime: number, + filename: string, + initData?: string): Promise { + // Acquire the time mutex to ensure exclusive access to the critical section for lastCallTime + const timeRelease = await this.timeMutex.acquire(); + let file; + try { + // Update the last call time + this.lastCallTime = currentTime; + this.zeroNotPassedCount(); + file = await this.superThis.app.vault.create(filename+".mw", initData ?? ''); + this.isUpdating = false; + } finally { + // Release the time mutex to allow other functions to proceed + timeRelease(); + } + return file; + } + + private async incrementNotPassedCount( + filename: string, + initData?: string): Promise { + // Acquire the count mutex to ensure exclusive access to the critical section for notPassedCount + const countRelease = await this.countMutex.acquire(); + let file; + try { + // Increment the not passed count + file = await this.superThis.app.vault.create(filename+ " (" + this.notPassedCount + ').mw', initData ?? ''); + this.notPassedCount++; + } finally { + // Release the count mutex to allow other functions to proceed + countRelease(); + } + return file; + } + private async zeroNotPassedCount(): Promise { + // Acquire the count mutex to ensure exclusive access to the critical section for notPassedCount + const countRelease = await this.countMutex.acquire(); + try { + // Increment the not passed count + this.notPassedCount = 1; + } finally { + // Release the count mutex to allow other functions to proceed + countRelease(); + } + } + + }(this); + + settings: MarkwhenPluginSettings; async onload() { await this.loadSettings(); + this.addCommand({ + id: 'markwhen-create-template', + name: 'Create Markwhen Template File', + callback: () => { + const markwhenfile = '/markwhen.mw'; + const obsidianConfigDir = this.app.vault.adapter.basePath; + const pluginFolderPath = path.join(obsidianConfigDir, this.manifest?.dir?.replace(/\//g, "\\") ?? ''); //check if configdir exists and if file does not exist create one + + fs.readFile(pluginFolderPath + markwhenfile, 'utf8', (err, data) => { + if (err) { + console.error('Error reading file:', err); + return; + } + this.createAndOpenMWFile(undefined,undefined,data); + // Do something with the file contents here + }); + // Your command logic goes here + console.log('My Plugin Command executed!'); + } + }); + this.addRibbonIcon( MARKWHEN_ICON, 'Create new Markwhen file', // tooltip () => { //TODO: better UX dealing with ribbon icons - this.createAndOpenMWFile( - `Markwhen ${new Date() - .toLocaleString('en-US', { hour12: false }) - .replace(/\//g, '-') - .replace(/:/g, '.') - .replace(/,/, '')}.mw` // improve this - ); - } + this.createAndOpenMWFile(); + } ); this.registerView( @@ -79,35 +219,25 @@ export default class MarkwhenPlugin extends Plugin { //Credits to https://github.com/yuleicul/obsidian-ketcher on file operations async createAndOpenMWFile( - filename: string, + filename?: string, foldername?: string, initData?: string ) { - const file = await this.createMWFile(filename, foldername, initData); + filename = filename ?? `Markwhen ${new Date() + .toLocaleString('en-US', { hour12: false }) + .replace(/\//g, '-') + .replace(/:/g, '.') + .replace(/,/, '')}`; + if (this.settings.deftoselectedtoggle && this.app.workspace.getActiveFile() instanceof TFile ) {foldername = this.app.workspace.getActiveFile()?.parent?.path ?? this.app.workspace.lastActiveFile.parent.path;} + const folderPath = normalizePath(foldername ?? this.settings.folder) + const file = await this.fclass.createMWFile(filename, folderPath, initData); this.app.workspace.getLeaf('tab').openFile(file); } - async createMWFile( - filename: string, - foldername?: string, - initData?: string - ): Promise { - const folderPath = normalizePath(foldername || this.settings.folder); - await this.checkAndCreateFolder(folderPath); - const fname = normalizePath(`${folderPath}/${filename}`); - const file = await this.app.vault.create(fname, initData ?? ''); - return file; + async fileExists(filePath: string): Promise { + return await this.app.vault.adapter.exists(filePath); } - async checkAndCreateFolder(folderPath: string) { - const vault = this.app.vault; - folderPath = normalizePath(folderPath); - //https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/658 - const folder = vault.getAbstractFileByPathInsensitive(folderPath); - if (folder && folder instanceof TFolder) return; - if (folder && folder instanceof TFile) return; //File name corruption - await vault.createFolder(folderPath); - } } class MarkwhenPluginSettingTab extends PluginSettingTab { @@ -130,6 +260,8 @@ class MarkwhenPluginSettingTab extends PluginSettingTab { button.setIcon('rotate-ccw').onClick(async () => { folderText.setValue(DEFAULT_SETTINGS.folder); this.plugin.settings.folder = DEFAULT_SETTINGS.folder; // Extract to Default Object + deftoselecttoggle.setValue(DEFAULT_SETTINGS.deftoselectedtoggle); + this.plugin.settings.deftoselectedtoggle = DEFAULT_SETTINGS.deftoselectedtoggle; await this.plugin.saveSettings(); }); }); @@ -141,5 +273,40 @@ class MarkwhenPluginSettingTab extends PluginSettingTab { this.plugin.settings.folder = value; await this.plugin.saveSettings(); }); + + if (this.plugin.settings.deftoselectedtoggle) { + folderText.inputEl.classList.add('disabled-text-field'); + } else { + folderText.inputEl.classList.remove('disabled-text-field'); + } + + const defToSelectedSetting = new Setting(containerEl) + .setName('Default To Current Folder') + .setDesc('Create new MW file under current folder'); + + const deftoselecttoggle = new ToggleComponent(defToSelectedSetting.controlEl) + .setValue(this.plugin.settings.deftoselectedtoggle) + .onChange(async (value) => { + this.plugin.settings.deftoselectedtoggle = value; + await this.plugin.saveSettings(); + folderText.setDisabled(value); + // Apply the CSS class to gray out the folder name text field + if (value) { + folderText.inputEl.classList.add('disabled-text-field'); + } else { + folderText.inputEl.classList.remove('disabled-text-field'); + } + }); + + const actionToContextSetting = new Setting(containerEl) + .setName('Actions on Context Menu') + .setDesc('Add Default Actions to Context Menu'); + + const actionToContextSettingtoggle = new ToggleComponent(actionToContextSetting.controlEl) + .setValue(this.plugin.settings.actionToContextSettingtoggle) + .onChange(async (value) => { + this.plugin.settings.actionToContextSettingtoggle = value; + await this.plugin.saveSettings(); + }); } }