diff --git a/README.md b/README.md index c773152..bb0348e 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,10 @@ This is a sample plugin for Obsidian (https://obsidian.md). -This project uses TypeScript to provide type checking and documentation. -The repo depends on the latest plugin API (obsidian.d.ts) in TypeScript Definition format, which contains TSDoc comments describing what it does. +This project uses Typescript to provide type checking and documentation. +The repo depends on the latest plugin API (obsidian.d.ts) in Typescript Definition format, which contains TSDoc comments describing what it does. + +**Note:** The Obsidian API is still in early alpha and is subject to change at any time! This sample plugin demonstrates some of the basic functionality the plugin API can do. - Adds a ribbon icon, which shows a Notice when clicked. @@ -39,7 +41,7 @@ Quick starting guide for new plugin devs: ## Adding your plugin to the community plugin list -- Check the [plugin guidelines](https://docs.obsidian.md/Plugins/Releasing/Plugin+guidelines). +- Check https://github.com/obsidianmd/obsidian-releases/blob/master/plugin-review.md - Publish an initial version. - Make sure you have a `README.md` file in the root of your repo. - Make a pull request at https://github.com/obsidianmd/obsidian-releases to add your plugin. diff --git a/esbuild.config.mjs b/esbuild.config.mjs index a5de8b8..b13282b 100644 --- a/esbuild.config.mjs +++ b/esbuild.config.mjs @@ -38,7 +38,6 @@ const context = await esbuild.context({ sourcemap: prod ? false : "inline", treeShaking: true, outfile: "main.js", - minify: prod, }); if (prod) { @@ -46,4 +45,4 @@ if (prod) { process.exit(0); } else { await context.watch(); -} +} \ No newline at end of file diff --git a/main.ts b/main.ts index 0261989..2d07212 100644 --- a/main.ts +++ b/main.ts @@ -1,13 +1,134 @@ -import { Plugin } from 'obsidian'; +import { App, Editor, MarkdownView, Modal, Notice, Plugin, PluginSettingTab, Setting } from 'obsidian'; -const UNSAFE_CHAR_REGEX = /[*?<>"]/g; +// Remember to rename these classes and interfaces! -export default class SafeFilenames extends Plugin { - async onload() { - this.registerEvent(this.app.vault.on('rename', (file, oldPath) => { - if (UNSAFE_CHAR_REGEX.test(file.path)) { - this.app.fileManager.renameFile(file, file.path.replaceAll(UNSAFE_CHAR_REGEX, '')); - } - })); - } +interface MyPluginSettings { + mySetting: string; +} + +const DEFAULT_SETTINGS: MyPluginSettings = { + mySetting: 'default' +} + +export default class MyPlugin extends Plugin { + settings: MyPluginSettings; + + async onload() { + await this.loadSettings(); + + // This creates an icon in the left ribbon. + const ribbonIconEl = this.addRibbonIcon('dice', 'Sample Plugin', (evt: MouseEvent) => { + // Called when the user clicks the icon. + new Notice('This is a notice!'); + }); + // Perform additional things with the ribbon + ribbonIconEl.addClass('my-plugin-ribbon-class'); + + // This adds a status bar item to the bottom of the app. Does not work on mobile apps. + const statusBarItemEl = this.addStatusBarItem(); + statusBarItemEl.setText('Status Bar Text'); + + // This adds a simple command that can be triggered anywhere + this.addCommand({ + id: 'open-sample-modal-simple', + name: 'Open sample modal (simple)', + callback: () => { + new SampleModal(this.app).open(); + } + }); + // This adds an editor command that can perform some operation on the current editor instance + this.addCommand({ + id: 'sample-editor-command', + name: 'Sample editor command', + editorCallback: (editor: Editor, view: MarkdownView) => { + console.log(editor.getSelection()); + editor.replaceSelection('Sample Editor Command'); + } + }); + // This adds a complex command that can check whether the current state of the app allows execution of the command + this.addCommand({ + id: 'open-sample-modal-complex', + name: 'Open sample modal (complex)', + checkCallback: (checking: boolean) => { + // Conditions to check + const markdownView = this.app.workspace.getActiveViewOfType(MarkdownView); + if (markdownView) { + // If checking is true, we're simply "checking" if the command can be run. + // If checking is false, then we want to actually perform the operation. + if (!checking) { + new SampleModal(this.app).open(); + } + + // This command will only show up in Command Palette when the check function returns true + return true; + } + } + }); + + // This adds a settings tab so the user can configure various aspects of the plugin + this.addSettingTab(new SampleSettingTab(this.app, this)); + + // If the plugin hooks up any global DOM events (on parts of the app that doesn't belong to this plugin) + // Using this function will automatically remove the event listener when this plugin is disabled. + this.registerDomEvent(document, 'click', (evt: MouseEvent) => { + console.log('click', evt); + }); + + // When registering intervals, this function will automatically clear the interval when the plugin is disabled. + this.registerInterval(window.setInterval(() => console.log('setInterval'), 5 * 60 * 1000)); + } + + onunload() { + + } + + async loadSettings() { + this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData()); + } + + async saveSettings() { + await this.saveData(this.settings); + } +} + +class SampleModal extends Modal { + constructor(app: App) { + super(app); + } + + onOpen() { + const {contentEl} = this; + contentEl.setText('Woah!'); + } + + onClose() { + const {contentEl} = this; + contentEl.empty(); + } +} + +class SampleSettingTab extends PluginSettingTab { + plugin: MyPlugin; + + constructor(app: App, plugin: MyPlugin) { + super(app, plugin); + this.plugin = plugin; + } + + display(): void { + const {containerEl} = this; + + containerEl.empty(); + + new Setting(containerEl) + .setName('Setting #1') + .setDesc('It\'s a secret') + .addText(text => text + .setPlaceholder('Enter your secret') + .setValue(this.plugin.settings.mySetting) + .onChange(async (value) => { + this.plugin.settings.mySetting = value; + await this.plugin.saveSettings(); + })); + } } diff --git a/manifest.json b/manifest.json index 1c80431..dfa940e 100644 --- a/manifest.json +++ b/manifest.json @@ -1,10 +1,11 @@ { - "id": "safe-filenames", - "name": "Safe Filenames", + "id": "sample-plugin", + "name": "Sample Plugin", "version": "1.0.0", "minAppVersion": "0.15.0", - "description": "Prevents renaming files with characters that can't be synced cross-platform.", - "author": "xenofem", - "authorUrl": "https://xeno.science", + "description": "Demonstrates some of the capabilities of the Obsidian API.", + "author": "Obsidian", + "authorUrl": "https://obsidian.md", + "fundingUrl": "https://obsidian.md/pricing", "isDesktopOnly": false } diff --git a/package.json b/package.json index 0319f4e..6a00766 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { - "name": "obsidian-safe-filenames", + "name": "obsidian-sample-plugin", "version": "1.0.0", - "description": "Obsidian plugin to prevent renaming files with unsafe characters", + "description": "This is a sample plugin for Obsidian (https://obsidian.md)", "main": "main.js", "scripts": { "dev": "node esbuild.config.mjs", @@ -9,7 +9,7 @@ "version": "node version-bump.mjs && git add manifest.json versions.json" }, "keywords": [], - "author": "xenofem", + "author": "", "license": "MIT", "devDependencies": { "@types/node": "^16.11.6", diff --git a/styles.css b/styles.css new file mode 100644 index 0000000..71cc60f --- /dev/null +++ b/styles.css @@ -0,0 +1,8 @@ +/* + +This CSS file will be included with your plugin, and +available in the app when your plugin is enabled. + +If your plugin does not need CSS, delete this file. + +*/ diff --git a/tsconfig.json b/tsconfig.json index c44b729..2d6fbdf 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -10,7 +10,7 @@ "moduleResolution": "node", "importHelpers": true, "isolatedModules": true, - "strictNullChecks": true, + "strictNullChecks": true, "lib": [ "DOM", "ES5",