├── .github ├── FUNDING.yml └── workflows │ └── release.yml ├── .gitignore ├── LICENSE ├── README.md ├── manifest.json ├── package.json ├── rollup.config.js ├── src ├── main.ts ├── types.ts ├── ui │ ├── commandSuggester.ts │ ├── iconPicker.ts │ ├── icons.ts │ ├── macroModal.ts │ └── settingsTab.ts └── util.ts ├── styles.css ├── tsconfig.json └── versions.json /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: ['phibr0'] 2 | custom: ['https://www.buymeacoffee.com/phibr0'] 3 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release Obsidian Plugin 2 | on: 3 | push: 4 | # Sequence of patterns matched against refs/tags 5 | tags: 6 | - '*' # Push events to matching any tag format, i.e. 1.0, 20.15.10 7 | jobs: 8 | build: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@v2 12 | with: 13 | fetch-depth: 0 # otherwise, you will failed to push refs to dest repo 14 | - name: Use Node.js 15 | uses: actions/setup-node@v1 16 | with: 17 | node-version: '14.x' # You might need to adjust this value to your own version 18 | # Get the version number and put it in a variable 19 | - name: Get Version 20 | id: version 21 | run: | 22 | echo "::set-output name=tag::$(git describe --abbrev=0)" 23 | # Build the plugin 24 | - name: Build 25 | id: build 26 | run: | 27 | npm install 28 | npm run build --if-present 29 | # Package the required files into a zip 30 | - name: Package 31 | run: | 32 | mkdir ${{ github.event.repository.name }} 33 | cp main.js manifest.json styles.css README.md ${{ github.event.repository.name }} 34 | zip -r ${{ github.event.repository.name }}.zip ${{ github.event.repository.name }} 35 | # Create the release on github 36 | - name: Create Release 37 | id: create_release 38 | uses: actions/create-release@v1 39 | env: 40 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 41 | VERSION: ${{ github.ref }} 42 | with: 43 | tag_name: ${{ github.ref }} 44 | release_name: ${{ github.ref }} 45 | draft: false 46 | prerelease: false 47 | # Upload the packaged release file 48 | - name: Upload zip file 49 | id: upload-zip 50 | uses: actions/upload-release-asset@v1 51 | env: 52 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 53 | with: 54 | upload_url: ${{ steps.create_release.outputs.upload_url }} 55 | asset_path: ./${{ github.event.repository.name }}.zip 56 | asset_name: ${{ github.event.repository.name }}.zip 57 | asset_content_type: application/zip 58 | # Upload the main.js 59 | - name: Upload main.js 60 | id: upload-main 61 | uses: actions/upload-release-asset@v1 62 | env: 63 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 64 | with: 65 | upload_url: ${{ steps.create_release.outputs.upload_url }} 66 | asset_path: ./main.js 67 | asset_name: main.js 68 | asset_content_type: text/javascript 69 | # Upload the manifest.json 70 | - name: Upload manifest.json 71 | id: upload-manifest 72 | uses: actions/upload-release-asset@v1 73 | env: 74 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 75 | with: 76 | upload_url: ${{ steps.create_release.outputs.upload_url }} 77 | asset_path: ./manifest.json 78 | asset_name: manifest.json 79 | asset_content_type: application/json 80 | # Upload the style.css 81 | - name: Upload styles.css 82 | id: upload-css 83 | uses: actions/upload-release-asset@v1 84 | env: 85 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 86 | with: 87 | upload_url: ${{ steps.create_release.outputs.upload_url }} 88 | asset_path: ./styles.css 89 | asset_name: styles.css 90 | asset_content_type: text/css 91 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Intellij 2 | *.iml 3 | .idea 4 | 5 | # npm 6 | node_modules 7 | package-lock.json 8 | 9 | # build 10 | main.js 11 | *.js.map 12 | 13 | # obsidian 14 | data.json 15 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Phillip 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # This Plugin is now archived. [Commander](https://github.com/phibr0/obsidian-commander) is a work-in-progress successor! 2 | 3 | # Obsidian Macros [![GitHub tag (Latest by date)](https://img.shields.io/github/v/tag/phibr0/obsidian-macros)](https://github.com/phibr0/obsidian-macros/releases) ![GitHub all releases](https://img.shields.io/github/downloads/phibr0/obsidian-macros/total) 4 | 5 | This plugin allows you to group as many commands as you wish together into one command (Macro). You can also specify an icon and set a delay between the commands. 6 | 7 | ## How to install 8 | 9 | 1. Go to **Community Plugins** in your [Obsidian](https://www.obsidian.md) settings and **disable** Safe Mode 10 | 2. Click on **Browse** and search for „Macros“ 11 | 3. Click install 12 | 4. Toggle the plugin **on** in the **Community Plugins** tab 13 | 14 | ## Support me 15 | 16 | If you find this plugin helpful, consider supporting me: 17 | 18 | 19 | -------------------------------------------------------------------------------- /manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "macro-plugin", 3 | "name": "Macros", 4 | "version": "0.1.0", 5 | "minAppVersion": "0.12.11", 6 | "description": "Group multiple Commands into one Macro.", 7 | "author": "phibr0", 8 | "authorUrl": "https://github.com/phibr0/", 9 | "isDesktopOnly": false 10 | } 11 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "obsidian-sample-plugin", 3 | "version": "0.12.0", 4 | "description": "This is a sample plugin for Obsidian (https://obsidian.md)", 5 | "main": "main.js", 6 | "scripts": { 7 | "dev": "esbuild src/main.ts --bundle --external:obsidian --format=cjs --outfile=main.js --watch", 8 | "build": "rollup --config rollup.config.js --environment BUILD:production" 9 | }, 10 | "keywords": [], 11 | "author": "", 12 | "license": "MIT", 13 | "devDependencies": { 14 | "@rollup/plugin-commonjs": "^18.0.0", 15 | "@rollup/plugin-node-resolve": "^11.2.1", 16 | "@rollup/plugin-typescript": "^8.2.1", 17 | "@types/feather-icons": "^4.7.0", 18 | "@types/node": "^14.14.37", 19 | "obsidian": "^0.12.0", 20 | "rollup": "^2.32.1", 21 | "tslib": "^2.2.0", 22 | "typescript": "^4.2.4", 23 | "esbuild": "^0.12.19" 24 | }, 25 | "dependencies": { 26 | "feather-icons": "^4.28.0" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /rollup.config.js: -------------------------------------------------------------------------------- 1 | import typescript from '@rollup/plugin-typescript'; 2 | import {nodeResolve} from '@rollup/plugin-node-resolve'; 3 | import commonjs from '@rollup/plugin-commonjs'; 4 | 5 | const isProd = (process.env.BUILD === 'production'); 6 | 7 | const banner = 8 | `/* 9 | THIS IS A GENERATED/BUNDLED FILE BY ROLLUP 10 | if you want to view the source visit the plugins github repository 11 | */ 12 | `; 13 | 14 | export default { 15 | input: 'src/main.ts', 16 | output: { 17 | dir: '.', 18 | sourcemap: 'inline', 19 | sourcemapExcludeSources: isProd, 20 | format: 'cjs', 21 | exports: 'default', 22 | banner, 23 | }, 24 | external: ['obsidian'], 25 | plugins: [ 26 | typescript(), 27 | nodeResolve({browser: true}), 28 | commonjs(), 29 | ] 30 | }; -------------------------------------------------------------------------------- /src/main.ts: -------------------------------------------------------------------------------- 1 | import { IconPicker } from './ui/iconPicker'; 2 | import { App, ButtonComponent, Command, Modal, Notice, Platform, Plugin, PluginSettingTab, Setting } from 'obsidian'; 3 | import { addFeatherIcons } from './ui/icons'; 4 | import CommandSuggester from './ui/commandSuggester'; 5 | import MacroSettingsTab from './ui/settingsTab'; 6 | import { MacroSettings, DEFAULT_SETTINGS } from './types'; 7 | import { wait } from './util'; 8 | 9 | 10 | export default class MacroPlugin extends Plugin { 11 | settings: MacroSettings; 12 | iconList: string[] = ["any-key", "audio-file", "blocks", "bold-glyph", "bracket-glyph", "broken-link", "bullet-list", "bullet-list-glyph", "calendar-with-checkmark", "check-in-circle", "check-small", "checkbox-glyph", "checkmark", "clock", "cloud", "code-glyph", "create-new", "cross", "cross-in-box", "crossed-star", "csv", "deleteColumn", "deleteRow", "dice", "document", "documents", "dot-network", "double-down-arrow-glyph", "double-up-arrow-glyph", "down-arrow-with-tail", "down-chevron-glyph", "enter", "exit-fullscreen", "expand-vertically", "filled-pin", "folder", "formula", "forward-arrow", "fullscreen", "gear", "go-to-file", "hashtag", "heading-glyph", "help", "highlight-glyph", "horizontal-split", "image-file", "image-glyph", "indent-glyph", "info", "insertColumn", "insertRow", "install", "italic-glyph", "keyboard-glyph", "languages", "left-arrow", "left-arrow-with-tail", "left-chevron-glyph", "lines-of-text", "link", "link-glyph", "logo-crystal", "magnifying-glass", "microphone", "microphone-filled", "minus-with-circle", "moveColumnLeft", "moveColumnRight", "moveRowDown", "moveRowUp", "note-glyph", "number-list-glyph", "open-vault", "pane-layout", "paper-plane", "paused", "pdf-file", "pencil", "percent-sign-glyph", "pin", "plus-with-circle", "popup-open", "presentation", "price-tag-glyph", "quote-glyph", "redo-glyph", "reset", "right-arrow", "right-arrow-with-tail", "right-chevron-glyph", "right-triangle", "run-command", "search", "sheets-in-box", "sortAsc", "sortDesc", "spreadsheet", "stacked-levels", "star", "star-list", "strikethrough-glyph", "switch", "sync", "sync-small", "tag-glyph", "three-horizontal-bars", "trash", "undo-glyph", "unindent-glyph", "up-and-down-arrows", "up-arrow-with-tail", "up-chevron-glyph", "uppercase-lowercase-a", "vault", "vertical-split", "vertical-three-dots", "wrench-screwdriver-glyph"]; 13 | 14 | async onload() { 15 | console.log('loading plugin'); 16 | 17 | await this.loadSettings(); 18 | 19 | addFeatherIcons(this.iconList); 20 | 21 | this.settings.macros.forEach(macro => { 22 | const command: Command = { 23 | id: macro.commandID, 24 | name: macro.name, 25 | callback: async () => { 26 | for (let i = 0; i < macro.commands.length; i++) { 27 | //@ts-ignore 28 | this.app.commands.executeCommandById(macro.commands[i]); 29 | await wait(macro.delay); 30 | } 31 | }, 32 | icon: macro.icon, 33 | } 34 | this.addCommand(command); 35 | }); 36 | 37 | this.addSettingTab(new MacroSettingsTab(this)); 38 | } 39 | 40 | onunload() { 41 | console.log('unloading plugin'); 42 | } 43 | 44 | async loadSettings() { 45 | this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData()); 46 | } 47 | 48 | async saveSettings() { 49 | await this.saveData(this.settings); 50 | } 51 | } -------------------------------------------------------------------------------- /src/types.ts: -------------------------------------------------------------------------------- 1 | import { Command } from "obsidian"; 2 | 3 | export interface Macro { 4 | commandID: string; 5 | name: string; 6 | mobileOnly: boolean; 7 | icon: string; 8 | delay: number; 9 | commands: string[]; 10 | command?: Command; 11 | } 12 | 13 | export interface MacroSettings { 14 | macros: Macro[]; 15 | } 16 | 17 | export const DEFAULT_SETTINGS: MacroSettings = { 18 | macros: [], 19 | } -------------------------------------------------------------------------------- /src/ui/commandSuggester.ts: -------------------------------------------------------------------------------- 1 | import { FuzzySuggestModal, Command } from "obsidian"; 2 | import CustomSidebarPlugin from "src/main"; 3 | 4 | export default class CommandSuggester extends FuzzySuggestModal { 5 | 6 | constructor(private plugin: CustomSidebarPlugin) { 7 | super(plugin.app); 8 | } 9 | 10 | getItems(): Command[] { 11 | //@ts-ignore 12 | return this.app.commands.listCommands(); 13 | } 14 | 15 | getItemText(item: Command): string { 16 | return item.name; 17 | } 18 | 19 | async onChooseItem(item: Command, evt: MouseEvent | KeyboardEvent): Promise { 20 | this.close(); 21 | setTimeout(() => { 22 | dispatchEvent(new CustomEvent("M-commandAdded", {detail: {command: item.id}})); 23 | }, 100); 24 | } 25 | 26 | } -------------------------------------------------------------------------------- /src/ui/iconPicker.ts: -------------------------------------------------------------------------------- 1 | import { Command, FuzzyMatch, FuzzySuggestModal, setIcon } from "obsidian"; 2 | import MacroPlugin from "src/main"; 3 | 4 | export class IconPicker extends FuzzySuggestModal{ 5 | plugin: MacroPlugin; 6 | 7 | constructor(plugin: MacroPlugin) { 8 | super(plugin.app); 9 | this.plugin = plugin; 10 | this.setPlaceholder("Pick an Icon"); 11 | } 12 | 13 | private cap(string: string): string { 14 | const words = string.split(" "); 15 | 16 | return words.map((word) => { 17 | return word[0].toUpperCase() + word.substring(1); 18 | }).join(" "); 19 | } 20 | 21 | getItems(): string[] { 22 | return this.plugin.iconList; 23 | } 24 | 25 | getItemText(item: string): string { 26 | return this.cap(item.replace("feather-", "").replace(/-/ig, " ")); 27 | } 28 | 29 | renderSuggestion(item: FuzzyMatch, el: HTMLElement): void { 30 | el.addClass("M-icon-container"); 31 | const div = createDiv({ cls: "M-icon" }); 32 | el.appendChild(div); 33 | setIcon(div, item.item); 34 | super.renderSuggestion(item, el); 35 | } 36 | 37 | async onChooseItem(item: string): Promise { 38 | this.close(); 39 | setTimeout(() => { 40 | dispatchEvent(new CustomEvent("M-iconPicked", {detail: {icon: item}})); 41 | }, 100); 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /src/ui/icons.ts: -------------------------------------------------------------------------------- 1 | import * as feather from "feather-icons"; 2 | import { addIcon } from "obsidian"; 3 | 4 | export function addFeatherIcons(iconList: string[]) { 5 | Object.values(feather.icons).forEach((i) => { 6 | const svg = i.toSvg({viewBox: "0 0 24 24", width: "100", height: "100"}); 7 | //Remove the svg tag: svg.match(/(?<=>).*(?=<\/svg>)/).first() 8 | addIcon("feather-" + i.name, svg); 9 | iconList.push("feather-" + i.name); 10 | }); 11 | } -------------------------------------------------------------------------------- /src/ui/macroModal.ts: -------------------------------------------------------------------------------- 1 | import { Modal, Command, Setting, Platform } from "obsidian"; 2 | import MacroPlugin from "src/main"; 3 | import { Macro } from "src/types"; 4 | import { wait } from "src/util"; 5 | import CommandSuggester from "./commandSuggester"; 6 | import { IconPicker } from "./iconPicker"; 7 | 8 | export default class MacroCreatorModal extends Modal { 9 | plugin: MacroPlugin; 10 | command: any; 11 | delay: number; //in ms 12 | name: string; 13 | coms: string[] = []; 14 | mobileOnly: boolean; 15 | editing: boolean; 16 | 17 | constructor(plugin: MacroPlugin, macro?: Macro) { 18 | super(plugin.app); 19 | this.plugin = plugin; 20 | this.command = macro?.command ?? {}; 21 | this.delay = macro?.delay ?? 10; 22 | this.name = macro?.name; 23 | this.coms = macro?.commands ?? []; 24 | this.mobileOnly = macro?.mobileOnly ?? false; 25 | if (macro) { 26 | this.editing = true; 27 | } else { 28 | this.editing = false; 29 | } 30 | addEventListener("M-iconPicked", (e: CustomEvent) => { 31 | this.command.icon = e.detail.icon; 32 | this.display(); 33 | }); 34 | addEventListener("M-commandAdded", (e: CustomEvent) => { 35 | this.coms.push(e.detail.command); 36 | this.display(); 37 | }); 38 | } 39 | 40 | onOpen() { 41 | super.onOpen(); 42 | this.display(); 43 | } 44 | 45 | display() { 46 | const { contentEl: el } = this; 47 | const command = this.command as Command; 48 | el.empty(); 49 | this.titleEl.setText("Add a new Macro") 50 | 51 | new Setting(el) 52 | .setName("Name") 53 | .setDesc("Specify the Name of your brand new Macro.") 54 | .addText(cb => { 55 | cb.setValue(command?.name?.replace(/Macro Plugin: /g, "") ?? "") 56 | .setPlaceholder("Super duper Macro") 57 | .setValue(this.name) 58 | .setDisabled(this.editing) 59 | .onChange(value => { 60 | this.name = value.trim().replace(/Macro Plugin: /g, ""); 61 | command.name = value.trim().replace(/Macro Plugin: /g, ""); 62 | command.id = value.trim().replace(/Macro Plugin: /g, "").replace(" ", "-").toLowerCase(); 63 | }); 64 | }); 65 | 66 | new Setting(el) 67 | .setName("Icon") 68 | .setDesc("Pick an Icon for your Macro.") 69 | .addButton(bt => { 70 | bt.setDisabled(this.editing); 71 | if (command.icon) { 72 | bt.setIcon(command.icon); 73 | } else { 74 | bt.setButtonText("Pick Icon"); 75 | } 76 | bt.onClick(() => { 77 | new IconPicker(this.plugin).open(); 78 | }); 79 | }); 80 | 81 | if (Platform.isMobile) { 82 | new Setting(el) 83 | .setName("Mobile Only?") 84 | .setDesc("Is this Macro Mobile only?") 85 | .addToggle(cb => { 86 | cb.setDisabled(this.editing); 87 | cb.setValue(command.mobileOnly) 88 | cb.onChange((value) => { 89 | this.command.mobileOnly = value; 90 | this.mobileOnly = value; 91 | }) 92 | }); 93 | } 94 | 95 | new Setting(el) 96 | .setName("Delay") 97 | .setDesc("Specify a Delay between every Command.") 98 | .addSlider(cb => { 99 | cb.setDisabled(this.editing); 100 | cb.setDynamicTooltip() 101 | .setLimits(10, 2000, 10) 102 | .setValue(this.delay) 103 | .onChange(value => { 104 | this.delay = value; 105 | }); 106 | }); 107 | 108 | new Setting(el) 109 | .setName("Add Command") 110 | .setDesc("Add a Command to your Macro.") 111 | .addButton(cb => { 112 | cb.setButtonText("+") 113 | .onClick(() => { 114 | new CommandSuggester(this.plugin).open() 115 | }) 116 | }); 117 | 118 | const commandsEl = el.createDiv({ cls: "M-commands" }) 119 | this.coms.forEach(c => { 120 | new Setting(commandsEl) 121 | //@ts-ignore 122 | .setName(this.app.commands.commands[c].name) 123 | .addButton(cb => { 124 | cb.setIcon("trash") 125 | .onClick(() => { 126 | this.coms.remove(c); 127 | this.display(); 128 | }) 129 | }); 130 | }); 131 | 132 | const btnDiv = el.createDiv({ cls: "M-flex-center" }) 133 | if (this.editing) { 134 | const btn = createEl("button", { text: "Finish" }) 135 | btnDiv.appendChild(btn); 136 | btn.addEventListener("click", () => { 137 | const c = this.command as Command; 138 | c.callback = async () => { 139 | for (let i = 0; i < this.coms.length; i++) { 140 | //@ts-ignore 141 | this.plugin.app.commands.executeCommandById(this.coms[i]); 142 | await wait(this.delay); 143 | } 144 | } 145 | dispatchEvent(new CustomEvent("M-macroAdded", { 146 | detail: { 147 | icon: this.command.icon, 148 | mobileOnly: this.mobileOnly, 149 | command: c, 150 | delay: this.delay, 151 | commands: this.coms, 152 | name: this.name, 153 | wasEdited: this.editing, 154 | } 155 | })); 156 | this.close(); 157 | }); 158 | } else { 159 | if (this.coms.length >= 2 && command.name && command.icon) { 160 | const cbtn = createEl("button", { text: "Create Macro" }) 161 | btnDiv.appendChild(cbtn); 162 | cbtn.addEventListener("click", () => { 163 | this.addCommand(); 164 | }); 165 | } 166 | const btn = createEl("button", { text: "Cancel" }) 167 | btnDiv.appendChild(btn); 168 | btn.addEventListener("click", () => { 169 | this.close(); 170 | }); 171 | } 172 | } 173 | 174 | addCommand() { 175 | const c = this.command as Command; 176 | c.callback = async () => { 177 | for (let i = 0; i < this.coms.length; i++) { 178 | //@ts-ignore 179 | this.plugin.app.commands.executeCommandById(this.coms[i]); 180 | await wait(this.delay); 181 | } 182 | } 183 | this.plugin.addCommand(c); 184 | dispatchEvent(new CustomEvent("M-macroAdded", { 185 | detail: { 186 | icon: this.command.icon, 187 | mobileOnly: this.mobileOnly, 188 | command: c, 189 | delay: this.delay, 190 | commands: this.coms, 191 | name: this.name, 192 | wasEdited: this.editing, 193 | } 194 | })); 195 | this.close(); 196 | } 197 | 198 | } -------------------------------------------------------------------------------- /src/ui/settingsTab.ts: -------------------------------------------------------------------------------- 1 | import { PluginSettingTab, Setting, Notice } from "obsidian"; 2 | import MacroPlugin from "src/main"; 3 | import MacroCreatorModal from "./macroModal"; 4 | 5 | export default class MacroSettingsTab extends PluginSettingTab { 6 | plugin: MacroPlugin; 7 | 8 | constructor(plugin: MacroPlugin) { 9 | super(plugin.app, plugin); 10 | this.plugin = plugin; 11 | addEventListener("M-macroAdded", async (e: CustomEvent) => { 12 | if (e.detail.wasEdited) { 13 | console.log("") 14 | const ids: string[] = []; 15 | e.detail.commands.forEach((element: string) => { 16 | ids.push(element); 17 | }); 18 | let m = this.plugin.settings.macros.find((m) => m.name === e.detail.name.replace(/Macro Plugin: /g, "")); 19 | console.log(m); 20 | m = { 21 | icon: e.detail.icon, 22 | mobileOnly: e.detail.mobileOnly, 23 | commandID: e.detail.command.id, 24 | commands: ids, 25 | delay: e.detail.delay, 26 | name: e.detail.name, 27 | }; 28 | await this.plugin.saveSettings(); 29 | this.display(); 30 | } else { 31 | const ids: string[] = []; 32 | e.detail.commands.forEach((element: string) => { 33 | ids.push(element); 34 | }); 35 | this.plugin.settings.macros.push({ 36 | mobileOnly: e.detail.mobileOnly, 37 | icon: e.detail.icon, 38 | commandID: e.detail.command.id, 39 | commands: ids, 40 | delay: e.detail.delay, 41 | name: e.detail.name, 42 | }); 43 | await this.plugin.saveSettings(); 44 | this.display(); 45 | } 46 | }); 47 | } 48 | 49 | 50 | display(): void { 51 | let { containerEl } = this; 52 | 53 | containerEl.empty(); 54 | 55 | containerEl.createEl('h2', { text: 'Macro Plugin Settings' }); 56 | 57 | new Setting(containerEl) 58 | .setName("Add new Macro") 59 | .setDesc("Create a new Group of Commands to execute one after another.") 60 | .addButton(cb => { 61 | cb.setButtonText("+") 62 | .onClick(() => { 63 | new MacroCreatorModal(this.plugin).open(); 64 | }) 65 | }) 66 | 67 | this.plugin.settings.macros.forEach(macro => { 68 | let dsc = ""; 69 | macro.commands.forEach((c, i) => { 70 | //@ts-ignore 71 | dsc += this.app.commands.commands[c].name; 72 | if (i != macro.commands.length - 1) { 73 | dsc += ", " 74 | } else { 75 | dsc += " | " 76 | } 77 | }); 78 | dsc += `(Delay: ${macro.delay})` 79 | new Setting(containerEl) 80 | .setName(macro.name) 81 | .setDesc(dsc) 82 | // .addButton(bt => { 83 | // bt.setButtonText("Edit"); 84 | // bt.onClick(() => { 85 | // new MacroCreatorModal(this.plugin, macro).open(); 86 | // }); 87 | // }) 88 | .addExtraButton(bt => { 89 | bt.setIcon("trash"); 90 | bt.onClick(async () => { 91 | this.plugin.settings.macros.remove(macro); 92 | this.display(); 93 | new Notice("You will need to restart Obsidian to fully remove the Macro.") 94 | await this.plugin.saveSettings(); 95 | }) 96 | }); 97 | }); 98 | 99 | new Setting(containerEl) 100 | .setName('Donate') 101 | .setDesc('If you like this Plugin, consider donating to support continued development:') 102 | .setClass("AT-extra") 103 | .addButton((bt) => { 104 | bt.buttonEl.outerHTML = ``; 105 | }); 106 | } 107 | } -------------------------------------------------------------------------------- /src/util.ts: -------------------------------------------------------------------------------- 1 | export async function wait(delay: number) { 2 | return new Promise(resolve => setTimeout(resolve, delay)); 3 | } -------------------------------------------------------------------------------- /styles.css: -------------------------------------------------------------------------------- 1 | .M-icon { 2 | transform: translateY(3px); 3 | margin-right: 8px; 4 | } 5 | 6 | .M-icon-container{ 7 | display: flex; 8 | } 9 | 10 | .M-commands { 11 | background-color: var(--background-secondary); 12 | margin: 1rem; 13 | padding: 1rem 1rem 0px 1rem; 14 | border-radius: 0.8rem; 15 | } 16 | 17 | .M-flex-center { 18 | display: flex; 19 | place-content: center; 20 | } 21 | 22 | a[href="https://www.buymeacoffee.com/phibr0"] > img { 23 | height: 2.2em; 24 | } 25 | 26 | a[href="https://www.buymeacoffee.com/phibr0"]{ 27 | transform: translate(0, 5%); 28 | } -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "baseUrl": ".", 4 | "inlineSourceMap": true, 5 | "inlineSources": true, 6 | "module": "ESNext", 7 | "target": "es6", 8 | "allowJs": true, 9 | "noImplicitAny": true, 10 | "moduleResolution": "node", 11 | "importHelpers": true, 12 | "lib": [ 13 | "dom", 14 | "es5", 15 | "scripthost", 16 | "es2015" 17 | ] 18 | }, 19 | "include": [ 20 | "**/*.ts" 21 | ] 22 | } 23 | -------------------------------------------------------------------------------- /versions.json: -------------------------------------------------------------------------------- 1 | { 2 | "1.0.1": "0.9.12", 3 | "1.0.0": "0.9.7" 4 | } 5 | --------------------------------------------------------------------------------