mirror of
https://github.com/tekknoman/obsidian-prio-plugin.git
synced 2026-07-22 04:34:13 +00:00
feat(plugin): implementing base functionality
This commit is contained in:
parent
3b016915fd
commit
556b40a5b2
8 changed files with 306 additions and 96 deletions
46
.gitignore
vendored
46
.gitignore
vendored
|
|
@ -1,22 +1,24 @@
|
|||
# vscode
|
||||
.vscode
|
||||
|
||||
# Intellij
|
||||
*.iml
|
||||
.idea
|
||||
|
||||
# npm
|
||||
node_modules
|
||||
|
||||
# Don't include the compiled main.js file in the repo.
|
||||
# They should be uploaded to GitHub releases instead.
|
||||
main.js
|
||||
|
||||
# Exclude sourcemaps
|
||||
*.map
|
||||
|
||||
# obsidian
|
||||
data.json
|
||||
|
||||
# Exclude macOS Finder (System Explorer) View States
|
||||
.DS_Store
|
||||
# vscode
|
||||
.vscode
|
||||
|
||||
# Intellij
|
||||
*.iml
|
||||
.idea
|
||||
|
||||
# npm
|
||||
node_modules
|
||||
|
||||
# Don't include the compiled main.js file in the repo.
|
||||
# They should be uploaded to GitHub releases instead.
|
||||
main.js
|
||||
|
||||
# Exclude sourcemaps
|
||||
*.map
|
||||
|
||||
# obsidian
|
||||
data.json
|
||||
|
||||
# Exclude macOS Finder (System Explorer) View States
|
||||
.DS_Store
|
||||
|
||||
app.css
|
||||
|
|
|
|||
149
main.ts
149
main.ts
|
|
@ -1,17 +1,39 @@
|
|||
import { App, Editor, MarkdownView, Modal, Notice, Plugin, PluginSettingTab, Setting } from 'obsidian';
|
||||
import {App, Editor, MarkdownView, Modal, Notice, Plugin, PluginSettingTab, Setting} from 'obsidian';
|
||||
import {PrioPluginSettings} from "./utils/Settings";
|
||||
import {SettingTab} from "./utils/SettingTab";
|
||||
import {decreasePrio, increasePrio, removePrio, setPrio} from "./utils/Priority";
|
||||
|
||||
// Remember to rename these classes and interfaces!
|
||||
|
||||
interface MyPluginSettings {
|
||||
mySetting: string;
|
||||
const DEFAULT_SETTINGS: PrioPluginSettings = {
|
||||
selectedPreset: 'default',
|
||||
levels: ['1', '2', '3', '4', '5', '6'],
|
||||
levelAliases: {
|
||||
'1': 'Major',
|
||||
'2': 'Minor',
|
||||
'3': 'Trivial',
|
||||
'4': 'Cosmetic',
|
||||
'5': 'Enhancement',
|
||||
'6': 'Bug'
|
||||
},
|
||||
presets: [{
|
||||
id: 'default',
|
||||
name: 'Default',
|
||||
settings: {
|
||||
levels: ['1', '2', '3', '4', '5', '6'],
|
||||
levelAliases: {
|
||||
'1': 'Major',
|
||||
'2': 'Minor',
|
||||
'3': 'Trivial',
|
||||
'4': 'Cosmetic',
|
||||
'5': 'Enhancement',
|
||||
'6': 'Bug'
|
||||
},
|
||||
}
|
||||
}]
|
||||
}
|
||||
|
||||
const DEFAULT_SETTINGS: MyPluginSettings = {
|
||||
mySetting: 'default'
|
||||
}
|
||||
|
||||
export default class MyPlugin extends Plugin {
|
||||
settings: MyPluginSettings;
|
||||
export default class PrioPlugin extends Plugin {
|
||||
settings: PrioPluginSettings;
|
||||
|
||||
async onload() {
|
||||
await this.loadSettings();
|
||||
|
|
@ -28,45 +50,65 @@ export default class MyPlugin extends Plugin {
|
|||
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',
|
||||
id: 'set-prio',
|
||||
name: 'Set priority',
|
||||
editorCallback: (editor: Editor, view: MarkdownView) => {
|
||||
console.log(editor.getSelection());
|
||||
editor.replaceSelection('Sample Editor Command');
|
||||
}
|
||||
setPrio(editor, view, this.settings);
|
||||
},
|
||||
hotkeys: [
|
||||
{
|
||||
modifiers: ['Ctrl', 'Shift', 'Alt'],
|
||||
key: 'p',
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
this.addCommand({
|
||||
id: 'remove-prio',
|
||||
name: 'Remove priority',
|
||||
editorCallback: (editor: Editor, view: MarkdownView) => {
|
||||
removePrio(editor, view, this.settings);
|
||||
},
|
||||
hotkeys: [
|
||||
{
|
||||
modifiers: ['Ctrl', 'Shift', 'Alt'],
|
||||
key: 'd',
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
this.addCommand({
|
||||
id: 'increase-prio',
|
||||
name: 'Increase priority',
|
||||
editorCallback: (editor: Editor, view: MarkdownView) => {
|
||||
increasePrio(editor, view, this.settings);
|
||||
},
|
||||
hotkeys: [
|
||||
{
|
||||
modifiers: ['Ctrl', 'Shift', 'Alt'],
|
||||
key: 'ArrowUp',
|
||||
}
|
||||
]
|
||||
});
|
||||
// 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;
|
||||
id: 'decrease-prio',
|
||||
name: 'Decrease priority',
|
||||
editorCallback: (editor: Editor, view: MarkdownView) => {
|
||||
decreasePrio(editor, view, this.settings);
|
||||
},
|
||||
hotkeys: [
|
||||
{
|
||||
modifiers: ['Ctrl', 'Shift', 'Alt'],
|
||||
key: 'ArrowDown',
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
// This adds a settings tab so the user can configure various aspects of the plugin
|
||||
this.addSettingTab(new SampleSettingTab(this.app, this));
|
||||
this.addSettingTab(new SettingTab(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.
|
||||
|
|
@ -107,31 +149,4 @@ class SampleModal extends Modal {
|
|||
}
|
||||
}
|
||||
|
||||
class SampleSettingTab extends PluginSettingTab {
|
||||
plugin: MyPlugin;
|
||||
|
||||
constructor(app: App, plugin: MyPlugin) {
|
||||
super(app, plugin);
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
display(): void {
|
||||
const {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(this.plugin.settings.mySetting)
|
||||
.onChange(async (value) => {
|
||||
console.log('Secret: ' + value);
|
||||
this.plugin.settings.mySetting = value;
|
||||
await this.plugin.saveSettings();
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
{
|
||||
"id": "obsidian-sample-plugin",
|
||||
"name": "Sample Plugin",
|
||||
"id": "obsidian-prio-plugin",
|
||||
"name": "Obsidian Prio Plugin",
|
||||
"version": "1.0.0",
|
||||
"minAppVersion": "0.15.0",
|
||||
"description": "This is a sample plugin for Obsidian. This plugin demonstrates some of the capabilities of the Obsidian API.",
|
||||
"author": "Obsidian",
|
||||
"authorUrl": "https://obsidian.md",
|
||||
"fundingUrl": "https://obsidian.md/pricing",
|
||||
"isDesktopOnly": false
|
||||
"description": "A plugin to prioritize your tasks and notes in Obsidian",
|
||||
"author": "EloiMusk",
|
||||
"authorUrl": "https://github.com/EloiMusk/",
|
||||
"fundingUrl": "",
|
||||
"isDesktopOnly": true
|
||||
}
|
||||
|
|
|
|||
35
styles.css
35
styles.css
|
|
@ -6,3 +6,38 @@ available in the app when your plugin is enabled.
|
|||
If your plugin does not need CSS, delete this file.
|
||||
|
||||
*/
|
||||
.preset-list {
|
||||
display: flex;
|
||||
flex-wrap: nowrap;
|
||||
width: 100%;
|
||||
border: 1px solid var(--color-base-10);
|
||||
box-shadow: inset var(--shadow-stationary);
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.preset-list-item {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
width: 100%;
|
||||
padding: 5px;
|
||||
border-top: 1px solid var(--background-modifier-border);
|
||||
border-bottom: 1px solid var(--background-modifier-border);
|
||||
}
|
||||
|
||||
.preset-list-item:hover {
|
||||
background-color: var(--background-modifier-hover);
|
||||
}
|
||||
|
||||
.btn {
|
||||
margin: 5px;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
background-color: var(--interactive-accent);
|
||||
}
|
||||
|
||||
.btn-primary:hover {
|
||||
background-color: var(--interactive-accent-hover);
|
||||
}
|
||||
|
|
|
|||
7
utils/Presets.ts
Normal file
7
utils/Presets.ts
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
import {PrioPluginSettings} from "./Settings";
|
||||
|
||||
export interface Preset {
|
||||
id: string;
|
||||
name: string;
|
||||
settings: PrioPluginSettings;
|
||||
}
|
||||
74
utils/Priority.ts
Normal file
74
utils/Priority.ts
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
import {Editor, MarkdownView} from "obsidian";
|
||||
import {PrioPluginSettings} from "./Settings";
|
||||
|
||||
export const setPrio = (editor: Editor, view: MarkdownView, settings: PrioPluginSettings) => {
|
||||
if (getPrio(editor, view, settings)) {
|
||||
return;
|
||||
}
|
||||
const cursor = editor.getCursor();
|
||||
const line = editor.getLine(cursor.line);
|
||||
const levels = settings.levels;
|
||||
const levelAliases = settings.levelAliases;
|
||||
const level = levels[Math.round((levels.length - 1) / 2)];
|
||||
const levelAlias = levelAliases[level];
|
||||
const newLine = `${line} #${levelAlias}`;
|
||||
editor.replaceRange(newLine, {line: cursor.line, ch: 0}, {line: cursor.line, ch: line.length});
|
||||
view.editor.focus();
|
||||
}
|
||||
|
||||
export const increasePrio = (editor: Editor, view: MarkdownView, settings: PrioPluginSettings) => {
|
||||
const currentPrio = getPrio(editor, view, settings);
|
||||
if (!currentPrio) {
|
||||
setPrio(editor, view, settings);
|
||||
return;
|
||||
}
|
||||
const currentLevelIndex = getLevelIndex(editor, view, settings, currentPrio);
|
||||
replacePrio(editor, view, settings, currentLevelIndex - 1 < 0 ? 0 : currentLevelIndex - 1);
|
||||
|
||||
}
|
||||
|
||||
export const decreasePrio = (editor: Editor, view: MarkdownView, settings: PrioPluginSettings) => {
|
||||
const currentPrio = getPrio(editor, view, settings);
|
||||
if (!currentPrio) {
|
||||
setPrio(editor, view, settings);
|
||||
return;
|
||||
}
|
||||
const currentLevelIndex = getLevelIndex(editor, view, settings, currentPrio);
|
||||
const levels = settings.levels;
|
||||
replacePrio(editor, view, settings, currentLevelIndex + 1 > levels.length - 1 ? levels.length - 1 : currentLevelIndex + 1);
|
||||
}
|
||||
|
||||
export const removePrio = (editor: Editor, view: MarkdownView, settings: PrioPluginSettings) => {
|
||||
const cursor = editor.getCursor();
|
||||
const line = editor.getLine(cursor.line);
|
||||
const newLine = line.replace(`#${getPrio(editor, view, settings)}`, '');
|
||||
editor.replaceRange(newLine, {line: cursor.line, ch: 0}, {line: cursor.line, ch: line.length});
|
||||
view.editor.focus();
|
||||
}
|
||||
|
||||
export const getLevelIndex = (editor: Editor, view: MarkdownView, settings: PrioPluginSettings, prio: string) => {
|
||||
const levels = settings.levels;
|
||||
const levelAliases = settings.levelAliases;
|
||||
const currentLevel = levels.find(level => levelAliases[level] === prio);
|
||||
return levels.indexOf(currentLevel as string);
|
||||
}
|
||||
|
||||
export const replacePrio = (editor: Editor, view: MarkdownView, settings: PrioPluginSettings, levelIndex: number) => {
|
||||
const cursor = editor.getCursor();
|
||||
const line = editor.getLine(cursor.line);
|
||||
const levels = settings.levels;
|
||||
const levelAliases = settings.levelAliases;
|
||||
const level = levels[levelIndex];
|
||||
const levelAlias = levelAliases[level];
|
||||
const newLine = line.replace(`#${getPrio(editor, view, settings)}`, `#${levelAlias}`);
|
||||
editor.replaceRange(newLine, {line: cursor.line, ch: 0}, {line: cursor.line, ch: line.length});
|
||||
view.editor.focus();
|
||||
}
|
||||
|
||||
export const getPrio = (editor: Editor, view: MarkdownView, settings: PrioPluginSettings) => {
|
||||
const cursor = editor.getCursor();
|
||||
const line = editor.getLine(cursor.line);
|
||||
return line.match(/#\w+/g)?.filter(tag =>
|
||||
Object.values(settings.levelAliases).includes(tag.replace('#', ''))
|
||||
).first()?.replace('#', '');
|
||||
}
|
||||
69
utils/SettingTab.ts
Normal file
69
utils/SettingTab.ts
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
import {App, PluginSettingTab, Setting} from "obsidian";
|
||||
import PrioPlugin from "../main";
|
||||
|
||||
export class SettingTab extends PluginSettingTab {
|
||||
plugin: PrioPlugin;
|
||||
|
||||
constructor(app: App, plugin: PrioPlugin) {
|
||||
super(app, plugin);
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
display(): void {
|
||||
const {containerEl} = this;
|
||||
|
||||
containerEl.empty();
|
||||
|
||||
let presets = this.plugin.settings.presets;
|
||||
|
||||
containerEl.createEl('h2', {text: 'General Settings'});
|
||||
if (this.plugin.settings.presets) {
|
||||
const dropDownOptions: Record<string, string> = {'default': 'Default'};
|
||||
this.plugin.settings.presets.map(preset => {
|
||||
return dropDownOptions[preset.id] = preset.name;
|
||||
});
|
||||
new Setting(containerEl)
|
||||
.setName('Preset')
|
||||
.setDesc('Select a preset to use.')
|
||||
.addSearch((search) => {
|
||||
search
|
||||
.setPlaceholder('Search Presets')
|
||||
.onChange(async (value) => {
|
||||
presets = this.plugin.settings.presets?.filter(preset => preset.name.toLowerCase().includes(value.toLowerCase()));
|
||||
});
|
||||
});
|
||||
}
|
||||
const presetList = createEl('ol', {
|
||||
cls: 'preset-list',
|
||||
parent: containerEl
|
||||
});
|
||||
|
||||
(presets || []).map(preset => {
|
||||
const el = createEl('li', {
|
||||
text: preset.name,
|
||||
cls: 'preset-list-item',
|
||||
parent: presetList
|
||||
});
|
||||
const btnGroup = el.createEl('div', {
|
||||
cls: 'btn-group'
|
||||
});
|
||||
|
||||
btnGroup.createEl('button', {
|
||||
text: 'Select',
|
||||
cls: ['preset-list-item-select', 'btn', 'btn-primary'],
|
||||
attr: {
|
||||
'onclick': 'alert("Preset Selected")'
|
||||
}
|
||||
})
|
||||
btnGroup.createEl('button', {
|
||||
text: 'Save',
|
||||
cls: ['preset-list-item-save', 'btn', 'btn-primary'],
|
||||
attr: {
|
||||
'onclick': 'alert("Save Preset")'
|
||||
}
|
||||
})
|
||||
return el;
|
||||
})
|
||||
|
||||
}
|
||||
}
|
||||
8
utils/Settings.ts
Normal file
8
utils/Settings.ts
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
import {Preset} from "./Presets";
|
||||
|
||||
export interface PrioPluginSettings {
|
||||
selectedPreset?: string;
|
||||
levels: string[];
|
||||
levelAliases: Record<string, string>;
|
||||
presets?: Preset[];
|
||||
}
|
||||
Loading…
Reference in a new issue