diff --git a/README.md b/README.md
index 9e4fe9c..515e1ad 100644
--- a/README.md
+++ b/README.md
@@ -1,57 +1,21 @@
-## Obsidian Sample Plugin
+# Obsidian Customizable Sidebar Plugin [![GitHub tag (Latest by date)](https://img.shields.io/github/v/tag/phibr0/obsidian-customizable-sidebar)](https://github.com/phibr0/obsidian-customizable-sidebar/releases) ![GitHub all releases](https://img.shields.io/github/downloads/phibr0/obsidian-customizable-sidebar/total)
-This is a sample plugin for Obsidian (https://obsidian.md).
+This Plugin allows you to add any Command, including those of Plugins, to the Sidebar and assign Custom Icons to them.
-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.
+## Custom Icons
-**Note:** The Obsidian API is still in early alpha and is subject to change at any time!
+If the Command doesn't yet have any Icon, you can select from a Range of Icons, including Obsidian's internal Icons and all Feather Icons.
-This sample plugin demonstrates some of the basic functionality the plugin API can do.
-- Changes the default font color to red using `styles.css`.
-- Adds a ribbon icon, which shows a Notice when clicked.
-- Adds a command "Open Sample Modal" which opens a Modal.
-- Adds a plugin setting tab to the settings page.
-- Registers a global click event and output 'click' to the console.
-- Registers a global interval which logs 'setInterval' to the console.
-### First time developing plugins?
+## How to install
-Quick starting guide for new plugin devs:
+1. Go to **Community Plugins** in your [Obsidian](https://www.obsidian.md) Settings and **disable** Safe Mode
+2. Click on **Browse** and search for „Obsidian Customizable Sidebar“
+3. Click install
+4. Toggle the Plugin on in the **Community Plugins** Tab
-- Make a copy of this repo as a template with the "Use this template" button (login to GitHub if you don't see it).
-- Clone your repo to a local development folder. For convenience, you can place this folder in your `.obsidian/plugins/your-plugin-name` folder.
-- Install NodeJS, then run `npm i` in the command line under your repo folder.
-- Run `npm run dev` to compile your plugin from `main.ts` to `main.js`.
-- Make changes to `main.ts` (or create new `.ts` files). Those changes should be automatically compiled into `main.js`.
-- Reload Obsidian to load the new version of your plugin.
-- Enable plugin in settings window.
-- For updates to the Obsidian API run `npm update` in the command line under your repo folder.
+## Support me
-### Releasing new releases
+If you find this Plugin helpful, consider supporting me:
-- Update your `manifest.json` with your new version number, such as `1.0.1`, and the minimum Obsidian version required for your latest release.
-- Update your `versions.json` file with `"new-plugin-version": "minimum-obsidian-version"` so older versions of Obsidian can download an older version of your plugin that's compatible.
-- Create new GitHub release using your new version number as the "Tag version". Use the exact version number, don't include a prefix `v`. See here for an example: https://github.com/obsidianmd/obsidian-sample-plugin/releases
-- Upload the files `manifest.json`, `main.js`, `styles.css` as binary attachments.
-- Publish the release.
-
-### Adding your plugin to the community plugin list
-
-- 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.
-
-### How to use
-
-- Clone this repo.
-- `npm i` or `yarn` to install dependencies
-- `npm run dev` to start compilation in watch mode.
-
-### Manually installing the plugin
-
-- Copy over `main.js`, `styles.css`, `manifest.json` to your vault `VaultFolder/.obsidian/plugins/your-plugin-id/`.
-
-### API Documentation
-
-See https://github.com/obsidianmd/obsidian-api
+
diff --git a/main.ts b/main.ts
deleted file mode 100644
index eeb3dda..0000000
--- a/main.ts
+++ /dev/null
@@ -1,112 +0,0 @@
-import { App, Modal, Notice, Plugin, PluginSettingTab, Setting } from 'obsidian';
-
-interface MyPluginSettings {
- mySetting: string;
-}
-
-const DEFAULT_SETTINGS: MyPluginSettings = {
- mySetting: 'default'
-}
-
-export default class MyPlugin extends Plugin {
- settings: MyPluginSettings;
-
- async onload() {
- console.log('loading plugin');
-
- await this.loadSettings();
-
- this.addRibbonIcon('dice', 'Sample Plugin', () => {
- new Notice('This is a notice!');
- });
-
- this.addStatusBarItem().setText('Status Bar Text');
-
- this.addCommand({
- id: 'open-sample-modal',
- name: 'Open Sample Modal',
- // callback: () => {
- // console.log('Simple Callback');
- // },
- checkCallback: (checking: boolean) => {
- let leaf = this.app.workspace.activeLeaf;
- if (leaf) {
- if (!checking) {
- new SampleModal(this.app).open();
- }
- return true;
- }
- return false;
- }
- });
-
- this.addSettingTab(new SampleSettingTab(this.app, this));
-
- this.registerCodeMirror((cm: CodeMirror.Editor) => {
- console.log('codemirror', cm);
- });
-
- this.registerDomEvent(document, 'click', (evt: MouseEvent) => {
- console.log('click', evt);
- });
-
- this.registerInterval(window.setInterval(() => console.log('setInterval'), 5 * 60 * 1000));
- }
-
- onunload() {
- console.log('unloading plugin');
- }
-
- 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() {
- let {contentEl} = this;
- contentEl.setText('Woah!');
- }
-
- onClose() {
- let {contentEl} = this;
- contentEl.empty();
- }
-}
-
-class SampleSettingTab extends PluginSettingTab {
- plugin: MyPlugin;
-
- constructor(app: App, plugin: MyPlugin) {
- super(app, plugin);
- this.plugin = plugin;
- }
-
- display(): void {
- let {containerEl} = this;
-
- containerEl.empty();
-
- containerEl.createEl('h2', {text: 'Settings for my awesome plugin.'});
-
- new Setting(containerEl)
- .setName('Setting #1')
- .setDesc('It\'s a secret')
- .addText(text => text
- .setPlaceholder('Enter your secret')
- .setValue('')
- .onChange(async (value) => {
- console.log('Secret: ' + value);
- this.plugin.settings.mySetting = value;
- await this.plugin.saveSettings();
- }));
- }
-}
diff --git a/manifest.json b/manifest.json
index 4ca4889..4f8865b 100644
--- a/manifest.json
+++ b/manifest.json
@@ -1,10 +1,10 @@
{
- "id": "obsidian-sample-plugin",
- "name": "Sample Plugin",
- "version": "1.0.1",
- "minAppVersion": "0.9.12",
- "description": "This is a sample plugin for Obsidian. This plugin demonstrates some of the capabilities of the Obsidian API.",
- "author": "Obsidian",
+ "id": "customizable-sidebar",
+ "name": "Customizable Sidebar",
+ "version": "0.0.1",
+ "minAppVersion": "0.12.11",
+ "description": "This Plugin allows to add any Command to Obsidian's Sidebar Ribbon.",
+ "author": "phibr0",
"authorUrl": "https://obsidian.md/about",
"isDesktopOnly": false
}
diff --git a/package.json b/package.json
index 29e2406..6543fb0 100644
--- a/package.json
+++ b/package.json
@@ -14,10 +14,14 @@
"@rollup/plugin-commonjs": "^18.0.0",
"@rollup/plugin-node-resolve": "^11.2.1",
"@rollup/plugin-typescript": "^8.2.1",
+ "@types/feather-icons": "^4.7.0",
"@types/node": "^14.14.37",
"obsidian": "^0.12.0",
"rollup": "^2.32.1",
"tslib": "^2.2.0",
"typescript": "^4.2.4"
+ },
+ "dependencies": {
+ "feather-icons": "^4.28.0"
}
}
diff --git a/rollup.config.js b/rollup.config.js
index dd4d041..8e28e8d 100644
--- a/rollup.config.js
+++ b/rollup.config.js
@@ -12,7 +12,7 @@ if you want to view the source visit the plugins github repository
`;
export default {
- input: 'main.ts',
+ input: 'src/main.ts',
output: {
dir: '.',
sourcemap: 'inline',
diff --git a/src/main.ts b/src/main.ts
new file mode 100644
index 0000000..6b83012
--- /dev/null
+++ b/src/main.ts
@@ -0,0 +1,37 @@
+import { App, Command, FuzzyMatch, FuzzySuggestModal, Modal, Notice, Plugin, PluginSettingTab, setIcon, Setting } from 'obsidian';
+import { addFeatherIcons } from './ui/icons';
+import CustomSidebarSettingsTab, { CustomSidebarSettings, DEFAULT_SETTINGS } from './ui/settingsTab';
+
+export default class CustomSidebarPlugin extends Plugin {
+ settings: CustomSidebarSettings;
+ 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"];
+
+ async onload() {
+ console.log('loading plugin');
+
+ await this.loadSettings();
+
+ this.addSettingTab(new CustomSidebarSettingsTab(this.app, this));
+
+ addFeatherIcons(this.iconList);
+
+ this.settings.sidebarCommands.forEach(c => {
+ this.addRibbonIcon(c.icon, c.name, () => {
+ //@ts-ignore
+ this.app.commands.executeCommandById(this.command.id);
+ });
+ })
+ }
+
+ onunload() {
+ console.log('unloading plugin');
+ }
+
+ async loadSettings() {
+ this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData());
+ }
+
+ async saveSettings() {
+ await this.saveData(this.settings);
+ }
+}
\ No newline at end of file
diff --git a/src/ui/commandSuggester.ts b/src/ui/commandSuggester.ts
new file mode 100644
index 0000000..4ff06d1
--- /dev/null
+++ b/src/ui/commandSuggester.ts
@@ -0,0 +1,36 @@
+import { FuzzySuggestModal, Command } from "obsidian";
+import CustomSidebarPlugin from "src/main";
+import IconPicker from "./iconPicker";
+
+export default class CommandSuggester extends FuzzySuggestModal {
+
+ constructor(private plugin: CustomSidebarPlugin) {
+ super(plugin.app);
+ }
+
+ getItems(): Command[] {
+ //@ts-ignore
+ return this.app.commands.listCommands();
+ }
+
+ getItemText(item: Command): string {
+ return item.name;
+ }
+
+ async onChooseItem(item: Command, evt: MouseEvent | KeyboardEvent): Promise {
+ if (item.icon) {
+ this.plugin.addRibbonIcon(item.icon ?? "", item.name, () => {
+ //@ts-ignore
+ this.app.commands.executeCommandById(item.id);
+ })
+ this.plugin.settings.sidebarCommands.push(item);
+ await this.plugin.saveSettings();
+ setTimeout(() => {
+ dispatchEvent(new Event("CS-addedCommand"));
+ }, 100);
+ } else {
+ new IconPicker(this.plugin, item).open()
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/src/ui/iconPicker.ts b/src/ui/iconPicker.ts
new file mode 100644
index 0000000..ad4f218
--- /dev/null
+++ b/src/ui/iconPicker.ts
@@ -0,0 +1,52 @@
+import { FuzzySuggestModal, Command, FuzzyMatch, setIcon } from "obsidian";
+import CustomSidebarPlugin from "src/main";
+
+export default class IconPicker extends FuzzySuggestModal{
+ plugin: CustomSidebarPlugin;
+ command: Command;
+
+ constructor(plugin: CustomSidebarPlugin, command: Command) {
+ super(plugin.app);
+ this.plugin = plugin;
+ this.command = command;
+ this.setPlaceholder("Pick an Icon");
+ }
+
+ private cap(string: string): string {
+ const words = string.split(" ");
+
+ return words.map((word) => {
+ return word[0].toUpperCase() + word.substring(1);
+ }).join(" ");
+ }
+
+ getItems(): string[] {
+ return this.plugin.iconList;
+ }
+
+ getItemText(item: string): string {
+ return this.cap(item.replace("feather-", "").replace(/-/ig, " "));
+ }
+
+ renderSuggestion(item: FuzzyMatch, el: HTMLElement): void {
+ el.addClass("CS-icon-container");
+ const div = createDiv({ cls: "CS-icon" });
+ el.appendChild(div);
+ setIcon(div, item.item);
+ super.renderSuggestion(item, el);
+ }
+
+ async onChooseItem(item: string): Promise {
+ this.plugin.addRibbonIcon(item, this.command.name, () => {
+ //@ts-ignore
+ this.app.commands.executeCommandById(this.command.id);
+ })
+ this.command.icon = item;
+ this.plugin.settings.sidebarCommands.push(this.command);
+ await this.plugin.saveSettings();
+ setTimeout(() => {
+ dispatchEvent(new Event("CS-addedCommand"));
+ }, 100);
+ }
+
+}
diff --git a/src/ui/icons.ts b/src/ui/icons.ts
new file mode 100644
index 0000000..e424586
--- /dev/null
+++ b/src/ui/icons.ts
@@ -0,0 +1,11 @@
+import * as feather from "feather-icons";
+import { addIcon } from "obsidian";
+
+export function addFeatherIcons(iconList: string[]) {
+ Object.values(feather.icons).forEach((i) => {
+ const svg = i.toSvg({viewBox: "0 0 24 24", width: "100", height: "100"});
+ //Remove the svg tag: svg.match(/(?<=>).*(?=<\/svg>)/).first()
+ addIcon("feather-" + i.name, svg);
+ iconList.push("feather-" + i.name);
+ });
+}
\ No newline at end of file
diff --git a/src/ui/settingsTab.ts b/src/ui/settingsTab.ts
new file mode 100644
index 0000000..d5f3573
--- /dev/null
+++ b/src/ui/settingsTab.ts
@@ -0,0 +1,70 @@
+import { PluginSettingTab, App, Setting, setIcon, Command, Notice } from "obsidian";
+import CustomSidebarPlugin from "src/main";
+import CommandSuggester from "./commandSuggester";
+
+export interface CustomSidebarSettings {
+ sidebarCommands: Command[];
+}
+
+export const DEFAULT_SETTINGS: CustomSidebarSettings = {
+ sidebarCommands: [],
+}
+
+export default class CustomSidebarSettingsTab extends PluginSettingTab {
+ plugin: CustomSidebarPlugin;
+
+ constructor(app: App, plugin: CustomSidebarPlugin) {
+ super(app, plugin);
+ this.plugin = plugin;
+ addEventListener("CS-addedCommand", () => {
+ this.display();
+ });
+ }
+
+ display(): void {
+ let { containerEl } = this;
+
+ containerEl.empty();
+
+ containerEl.createEl('h2', { text: 'Customizable Sidebar Settings' });
+
+ new Setting(containerEl)
+ .setName("Add Command to Sidebar")
+ .setDesc("Add a new Command to the left Sidebar Ribbon")
+ .addButton((bt) => {
+ bt.setButtonText("Add Command")
+ .onClick(() => {
+ new CommandSuggester(this.plugin).open();
+ });
+ });
+
+ this.plugin.settings.sidebarCommands.forEach(c => {
+ const iconDiv = createDiv({ cls: "CS-settings-icon" });
+ setIcon(iconDiv, c.icon, 20);
+ const setting = new Setting(containerEl)
+ .setName(c.name)
+ .addButton(bt => {
+ bt.setButtonText("Remove Command")
+ .onClick(async () => {
+ this.plugin.settings.sidebarCommands.remove(c);
+ await this.plugin.saveSettings();
+ this.display();
+ new Notice("You will need to restart Obsidian for the Command to dissapear.")
+ })
+ });
+ setting.nameEl.prepend(iconDiv);
+ setting.nameEl.addClass("CS-flex");
+ })
+
+ new Setting(containerEl)
+ .setName('Donate')
+ .setDesc('If you like this Plugin, consider donating to support continued development:')
+ .setClass("AT-extra")
+ .addButton((bt) => {
+ bt.buttonEl.outerHTML = ``;
+ });
+ }
+}
+
+
+
diff --git a/styles.css b/styles.css
index cfd0fd7..3391602 100644
--- a/styles.css
+++ b/styles.css
@@ -1,4 +1,27 @@
-/* Sets all the text color to red! */
-body {
- color: red;
+/*Icon Picker*/
+.CS-icon {
+ transform: translateY(3px);
+ margin-right: 8px;
}
+
+.CS-icon-container{
+ display: flex;
+}
+
+.CS-settings-icon {
+ height: 20px;
+ margin-right: 0.5rem;
+ transform: translateY(2px);
+}
+
+.CS-flex {
+ display: flex;
+}
+
+a[href="https://www.buymeacoffee.com/phibr0"] > img {
+ height: 2.2em;
+}
+
+a[href="https://www.buymeacoffee.com/phibr0"]{
+ transform: translate(0, 5%);
+}
\ No newline at end of file
diff --git a/versions.json b/versions.json
index ba14785..9e26dfe 100644
--- a/versions.json
+++ b/versions.json
@@ -1,4 +1 @@
-{
- "1.0.1": "0.9.12",
- "1.0.0": "0.9.7"
-}
+{}
\ No newline at end of file