Skip to content

Commit

Permalink
feat: #10 add quick notes via tray or hotkey
Browse files Browse the repository at this point in the history
  • Loading branch information
dragonwocky committed Apr 9, 2023
1 parent d34a8ed commit da54fc0
Show file tree
Hide file tree
Showing 2 changed files with 130 additions and 43 deletions.
16 changes: 13 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,19 +1,29 @@
<img alt="" src="tray.png" align="right" height="128px">

**Tray** is an [Obsidian](https://obsidian.md/) plugin that can be used to launch the app
on system startup and run it in the background, adding an icon to the system tray that it
can be minimised to and a global hotkey to toggle visibility of the app's windows.
on system startup and run it in the background, adding global hotkeys and a tray menu that
toggle app window visibility and can create quick notes from anywhere in your operating system.

## Configuration

### Window management

| Option | Description | Default |
| -------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------- |
| Launch on startup | Open Obsidian automatically whenever you log into your computer. | Disabled |
| Hide on launch | Minimises Obsidian automatically whenever the app is launched. If the "Run in background" option is enabled, windows will be hidden to the system tray/menubar instead of minimised to the taskbar/dock. | Disabled |
| Run in background | Hide the app and continue to run it in the background instead of quitting it when pressing the window close button or toggle focus hotkey. | Disabled |
| Hide taskbar icon | Hides the window's icon from from the dock/taskbar. This may not work on all Linux-based OSes. | Disabled |
| Create tray icon | Add an icon to your system tray/menubar to bring hidden Obsidian windows back into focus on click or force a full quit/relaunch of the app through the right-click menu. _Changing this option requires a restart to take effect._ | Enabled |
| Toggle window focus hotkey | Format: [Electron accelerator](https://www.electronjs.org/docs/latest/api/accelerator) | CmdOrCtrl+Shift+Tab |
| Toggle window focus hotkey | This hotkey is registered globally and will be detected even if Obsidian does not have keyboard focus. Format: [Electron accelerator](https://www.electronjs.org/docs/latest/api/accelerator) | CmdOrCtrl+Shift+Tab |

### Quick notes

| Option | Description | Default |
| ---------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------- |
| Quick note location | New quick notes will be placed in this folder. | |
| Quick note date format | New quick notes will use a filename of this pattern. Format: [Moment.js format string](https://momentjs.com/docs/#/displaying/format/) | YYYY-MM-DD |
| Quick note hotkey | This hotkey is registered globally and will be detected even if Obsidian does not have keyboard focus. Format: [Electron accelerator](https://www.electronjs.org/docs/latest/api/accelerator) | Disabled |

## Installation

Expand Down
157 changes: 117 additions & 40 deletions main.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@

"use strict";

const DEFAULT_DATE_FORMAT = "YYYY-MM-DD";

let tray;
const obsidian = require("obsidian"),
{
Expand Down Expand Up @@ -61,7 +63,17 @@ const onWindowClose = (event) => {
closeBtn.removeEventListener("click", onWindowClose, true);
};

const setHideTaskbarIcon = (plugin) => {
const addQuickNote = (plugin) => {
const { quickNoteLocation, quickNoteDateFormat } = plugin.settings,
format = quickNoteDateFormat || DEFAULT_DATE_FORMAT,
date = obsidian.moment().format(format),
name = obsidian
.normalizePath(`${quickNoteLocation ?? ""}/${date}`)
.replace(/\*|"|\\|<|>|:|\||\?/g, "-");
plugin.app.fileManager.createAndOpenMarkdownFile(name);
showWindows();
},
setHideTaskbarIcon = (plugin) => {
const win = getCurrentWindow();
win.setSkipTaskbar(plugin.settings.hideTaskbarIcon);
},
Expand All @@ -84,6 +96,12 @@ const createTrayIcon = (plugin) => {
`data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAHZSURBVDhPlZKxTxRBFMa/XZcF7nIG7mjxjoRCwomJxgsFdhaASqzQxFDzB1AQKgstLGxIiBQGJBpiCCGx8h+wgYaGgAWNd0dyHofeEYVwt/PmOTMZV9aDIL/s5pvZvPfN9yaL/+HR3eXcypta0m4juFbP5GHuXc9IbunDFc9db/G81/ZzhDMN7g8td47mll4R5BfHwZN4LOaA+fHa259PbUmIYzWkt3e2NZNo3/V9v1vvU6kkstk+tLW3ItUVr/m+c3N8MlkwxYqmBFcbwUQQCNOcyVzDwEAWjuPi5DhAMV/tKOYPX5hCyz8Gz1zX5SmWjBvZfmTSaRBJkGAIoxJHv+pVW2yIGNxOJ8bUVNcFEWLxuG1ia6JercTbttwQTeDwPS0kCMXiXtgk/jQrFUw7ptYSMWApF40yo/ytjHq98fdk3ayVE+cn2CxMb6ruz9qAJKFUKoWza1VJSi/n0+ffgYHdWW2gHuxXymg0gjCB0sjpmiaDnkL3RzDyzLqBUKns2ztQqUR0fk2TwSrGSf1eczqF5vsPZRCQSSAFLk6gqctgQRkc6TWRQLV2YMYQki9OoNkqzFQ9r+WOGuW5CrJbOzyAlPKr6MSGLbkcDwbf35oY/jRkt6cAfgNwowruAMz9AgAAAABJRU5ErkJggg==`
),
contextMenu = Menu.buildFromTemplate([
{
type: "normal",
label: "Add Quick Note",
accelerator: plugin.settings.quickNoteHotkey,
click: () => addQuickNote(plugin),
},
{
type: "normal",
label: "Open Obsidian",
Expand Down Expand Up @@ -112,25 +130,36 @@ const createTrayIcon = (plugin) => {
tray.on("click", () => toggleWindows(plugin.settings.runInBackground, false));
};

const registerHotkey = (plugin) => {
const registerHotkeys = (plugin) => {
console.log("obsidian-tray: registering hotkey");
try {
const accelerator = plugin.settings.toggleWindowFocusHotkey;
globalShortcut.register(accelerator, () => {
const runInBackground = plugin.settings.runInBackground;
toggleWindows(runInBackground);
});
const toggleAccelerator = plugin.settings.toggleWindowFocusHotkey,
quicknoteAccelerator = plugin.settings.quickNoteHotkey;
if (toggleAccelerator) {
globalShortcut.register(toggleAccelerator, () => {
const runInBackground = plugin.settings.runInBackground;
toggleWindows(runInBackground);
});
}
if (quicknoteAccelerator) {
globalShortcut.register(quicknoteAccelerator, () => {
addQuickNote(plugin);
});
}
} catch {}
},
unregisterHotkey = (plugin) => {
unregisterHotkeys = (plugin) => {
console.log("obsidian-tray: unregistering hotkey");
try {
const accelerator = plugin.settings.toggleWindowFocusHotkey;
globalShortcut.unregister(accelerator);
const toggle = plugin.settings.toggleWindowFocusHotkey,
quicknote = plugin.settings.quickNoteHotkey;
globalShortcut.unregister(toggle);
globalShortcut.unregister(quicknote);
} catch {}
};

const OPTIONS = [
"Window management",
{
key: "launchOnStartup",
desc: "Open Obsidian automatically whenever you log into your computer.",
Expand Down Expand Up @@ -185,16 +214,26 @@ const OPTIONS = [
},
{
key: "toggleWindowFocusHotkey",
desc: `
Format:
<a href="https://www.electronjs.org/docs/latest/api/accelerator">
Electron accelerator
</a>
`,
type: "text",
type: "hotkey",
default: "CmdOrCtrl+Shift+Tab",
onBeforeChange: unregisterHotkey,
onChange: registerHotkey,
},
"Quick notes",
{
key: "quickNoteLocation",
desc: "New quick notes will be placed in this folder.",
type: "text",
placeholder: "Example: notes/quick",
},
{
key: "quickNoteDateFormat",
desc: "New quick notes will use a filename of this pattern.",
type: "moment",
default: DEFAULT_DATE_FORMAT,
},
{
key: "quickNoteHotkey",
type: "hotkey",
default: "CmdOrCtrl+Shift+Q",
},
];

Expand All @@ -210,6 +249,18 @@ const keyToLabel = (key) =>
.createRange()
.createContextualFragment((html ?? "").replace(/\s+/g, " "));

const acceleratorFormat = `
This hotkey is registered globally and will be detected even if Obsidian does
not have keyboard focus. Format:
<a href="https://www.electronjs.org/docs/latest/api/accelerator" target="_blank" rel="noopener">
Electron accelerator</a>
`,
momentFormat = `
Format:
<a href="https://momentjs.com/docs/#/displaying/format/" target="_blank" rel="noopener">
Moment.js format string</a>
<br>Preview:
`;
class SettingsTab extends obsidian.PluginSettingTab {
constructor(app, plugin) {
super(app, plugin);
Expand All @@ -218,32 +269,58 @@ class SettingsTab extends obsidian.PluginSettingTab {
display() {
this.containerEl.empty();
for (const opt of OPTIONS) {
const name = keyToLabel(opt.key),
desc = htmlToFragment(opt.desc),
onChange = async (value) => {
const setting = new obsidian.Setting(this.containerEl);
if (typeof opt === "string") {
setting.setName(opt);
setting.setHeading();
} else {
if (opt.default) {
opt.placeholder ??= `Example: ${opt.default}`;
}
if (opt.type === "hotkey") {
opt.desc ??= "";
opt.desc += acceleratorFormat;
opt.onBeforeChange = unregisterHotkeys;
opt.onChange = registerHotkeys;
}
if (opt.type === "moment") {
opt.desc = `${opt.desc ? `${opt.desc}<br>` : ""}${momentFormat}`;
}

setting.setName(keyToLabel(opt.key));
setting.setDesc(htmlToFragment(opt.desc));
const onChange = async (value) => {
await opt.onBeforeChange?.(this.plugin);
this.plugin.settings[opt.key] = value;
await this.plugin.saveSettings();
await opt.onChange?.(this.plugin);
};

const setting = new obsidian.Setting(this.containerEl)
.setName(name)
.setDesc(desc);
switch (opt.type) {
case "toggle":
setting.addToggle((toggle) =>
toggle.setValue(this.plugin.settings[opt.key]).onChange(onChange)
);
break;
case "text":
default:
setting.addText((text) =>
if (opt.type === "toggle") {
setting.addToggle((toggle) => {
toggle
.setValue(this.plugin.settings[opt.key] ?? opt.default)
.onChange(onChange);
});
} else if (opt.type === "moment") {
setting.addMomentFormat((moment) => {
const sampleEl = setting.descEl.createEl("b");
sampleEl.className = "u-pop";
moment
.setPlaceholder(opt.placeholder)
.setDefaultFormat(opt.default ?? "")
.setValue(this.plugin.settings[opt.key] ?? opt.default ?? "")
.setSampleEl(sampleEl)
.onChange(onChange);
});
} else {
setting.addText((text) => {
text
.setPlaceholder(opt.default)
.setValue(this.plugin.settings[opt.key])
.onChange(onChange)
);
.setPlaceholder(opt.placeholder)
.setValue(this.plugin.settings[opt.key] ?? opt.default ?? "")
.onChange(onChange);
});
}
}
}
}
Expand All @@ -256,7 +333,7 @@ class TrayPlugin extends obsidian.Plugin {
this.addSettingTab(new SettingsTab(this.app, this));
const { settings } = this;

registerHotkey(this);
registerHotkeys(this);
setHideTaskbarIcon(this);
setLaunchOnStartup(this);
if (settings.createTrayIcon) createTrayIcon(this);
Expand All @@ -273,7 +350,7 @@ class TrayPlugin extends obsidian.Plugin {
}
}
onunload() {
unregisterHotkey(this);
unregisterHotkeys(this);
cleanupWindowClose();
}

Expand Down

0 comments on commit da54fc0

Please sign in to comment.