Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
muness committed Apr 8, 2024
2 parents b196afe + 0c58b91 commit 1398e23
Show file tree
Hide file tree
Showing 12 changed files with 428 additions and 242 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ jobs:
gh release create "$tag" \
--title="$tag" \
--draft \
dist/styles.css \
dist/main-debug.js \
dist/main.js \
dist/manifest.json \
${{ env.PLUGIN_NAME }}.zip
39 changes: 34 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ The Amazing Marvin Plugin provides a way to bring your tasks and project structu
- **Parent Links**: For easy navigation, notes for subcategories and subprojects include backlinks to their parent category or project.
- **Wiki Links**: Sub-Categories and projects Amazing Marvin are added as wiki links.
- **Categories and Projects are folder notes**: Categories and projects are created as folder notes, compatible with [Obsidian folder notes](https://github.com/LostPaul/obsidian-folder-notes).
- **Task Creation**: Users can create Amazing Marvin tasks directly within Obsidian, with support for standard Marvin shorthand notations like `+` for dates or `@` for labels.
- **Deep Linking**: Each task and category is equipped with a deep link, providing quick navigation back to Amazing Marvin.

## Usage Instructions

Expand All @@ -35,16 +37,43 @@ To initiate a sync:
2. Search for and select the command `Sync Amazing Marvin categories and projects`.
3. The plugin will then proceed to update your Obsidian vault with the current structure and content from Amazing Marvin.

Once synced, your Obsidian vault will contain a new `AmazingMarvin` folder. Inside, you'll find the structured notes corresponding to your categories and projects from Amazing Marvin.

### Creating a Marvin Task

The task creation dialog is designed to mirror the task input experience in Amazing Marvin closely. It includes the following features:

- Autocomplete for Categories and Projects using `#` syntax or a search sub-dialog.
- Recognizes shorthand notations for properties like start date (`~`), due date (`@`), and labels (`+`).
- Places a link to the Marvin task as a deep link in Obsidian at the cursor location upon task creation.
- The created Marvin task contains an Advanced URI-friendly link back to the Obsidian note that instigated the task.

To create a task:

1. Open Obsidian's Command Palette with `Ctrl/Cmd + P`.
2. Search for and select the command `Create Marvin Task`.
3. Input the task details and select the appropriate category from the dropdown, which shows suggestions as you type.
4. Upon task creation, a markdown checklist item with a link to the Marvin task is inserted at your cursor location in Obsidian.

### Auto-Mark as Done Feature

One of the highlights in this version is the ability to auto-mark tasks as done in Amazing Marvin when they are checked off in Obsidian. When this feature is enabled in the plugin settings, checking a task off in your Obsidian note will automatically update the task status in Amazing Marvin.

Here's how to enable this feature:

1. Go to `Settings > Obsidian Amazing Marvin Plugin`.
2. Check the option `Attempt to mark tasks as done in Amazing Marvin when checked off in Obsidian`.
3. Save your settings.

Now, when you check off a task with an Amazing Marvin Link in an Obsidian note, a request will be sent to Amazing Marvin to mark the task as done there as well.

### Important Considerations

- **Data Loss**: Be cautious when editing Amazing Marvin-generated notes in Obsidian, as these changes will be overwritten by the next sync.
- **Backup Recommended**: It's advisable to back up your Obsidian vault before running the sync, especially if you've made local modifications to the synchronized notes.

By following these guidelines, you can ensure your Amazing Marvin data is accurately reflected in Obsidian while being mindful of the plugin's current limitations.

### Viewing Synced Content

Once synced, your Obsidian vault will contain a new `AmazingMarvin` folder. Inside, you'll find the structured notes corresponding to your categories and projects from Amazing Marvin.

## Installing

Expand All @@ -53,7 +82,7 @@ Once synced, your Obsidian vault will contain a new `AmazingMarvin` folder. Insi
1. Install the BRAT plugin
1. Open `Settings` -> `Community Plugins`
2. Disable safe mode, if enabled
3. *Browse*, and search for "BRAT"
3. *Browse*, and search for "BRAT"
4. Install the latest version of **Obsidian42 - BRAT**
2. Open BRAT settings (`Settings` -> `BRAT`)
1. Scroll to the `Beta Plugin List` section
Expand All @@ -64,7 +93,7 @@ Once synced, your Obsidian vault will contain a new `AmazingMarvin` folder. Insi
### Manually

1. If you haven't enabled community plugins in Obsidian, follow these [instructions](https://help.obsidian.md/Extending+Obsidian/Community+plugins#Install+a+community+plugin) to do so.
2. Download the latest release from the [releases](https://github.com/cloud-atlas-ai/obsidian-am/releases) page.
2. Download `cloudatlas-obsidian-am.zip` from the [releases](https://github.com/cloud-atlas-ai/obsidian-am/releases).
3. Unzip the release and copy the directory into your vault's plugins folder: `<vault>/.obsidian/plugins/cloudatlas-o-am`.
4. Restart Obsidian to recognize the new plugin.
5. In Obsidian's settings under "Community Plugins," find and enable the Obsidian Amazing Marvin Plugin.
Expand Down
2 changes: 1 addition & 1 deletion manifest-beta.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"id": "cloudatlas-o-am",
"name": "Amazing Marvin",
"version": "0.4.2b",
"version": "0.9.0",
"minAppVersion": "1.4.16",
"description": "Integration with Amazing Marvin",
"author": "Cloud Atlas",
Expand Down
4 changes: 2 additions & 2 deletions manifest.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"id": "cloudatlas-o-am",
"name": "Amazing Marvin",
"version": "0.3.1",
"name": "Amazing Marvin by Cloud Atlas",
"version": "0.9.2",
"minAppVersion": "1.4.16",
"description": "Integration with Amazing Marvin",
"author": "Cloud Atlas",
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "cloud-atlas",
"version": "0.4.2b",
"version": "0.9.2",
"description": "Interoperability between Obsidian and Amazing Marvin",
"main": "dist/main.js",
"scripts": {
Expand Down
181 changes: 181 additions & 0 deletions src/addTaskModal.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
import { App, Modal, Setting, DropdownComponent, TextAreaComponent, FuzzySuggestModal, FuzzyMatch, Notice } from "obsidian";
import { Category } from "./interfaces";

const inboxCategory: Category = {
_id: "__inbox-faux__", // Arbitrary unique ID for the Inbox faux category
title: "Inbox",
type: "faux",
updatedAt: 0,
parentId: "root",
startDate: "",
endDate: "",
note: "",
isRecurring: false,
priority: "",
deepLink: "",
dueDate: "",
done: false,
};

function getTitleWithParent(category: Category, categories: Category[]): string {
let parent = category.parentId;

let parentTitle = [];
while (parent && parent !== "root") {
const parentCategory = categories.find(category => category._id === parent);
if (parentCategory) {
parentTitle.push(parentCategory.title);
parent = parentCategory.parentId;
} else {
break;
}
}
if (parentTitle.length > 0) {
return category.title + ` in ${parentTitle.reverse().join("/")}`;
}
return category.title;
}

// Suggester Modal Class for Category Selection
class CategorySuggesterModal extends FuzzySuggestModal<Category> {
categories: Category[];

onChooseItem: (item: Category, _evt: MouseEvent | KeyboardEvent) => void;
getItems(): Category[] {

// Include the Inbox at the beginning of the categories list
return [inboxCategory, ...this.categories];
}
getItemText(category: Category): string {
if (category.type === "faux") {
return "Inbox";
}
return getTitleWithParent(category, this.categories);
}

constructor(app: App, categories: Category[], onChooseItem: (item: Category, _evt: MouseEvent | KeyboardEvent) => void) {
super(app);
this.categories = categories;
this.onChooseItem = onChooseItem;
}

onChooseSuggestion(item: FuzzyMatch<Category>, _evt: MouseEvent | KeyboardEvent): void {
this.onChooseItem(item.item, _evt);
}
}

export class AddTaskModal extends Modal {
result: { catId: string, task: string };
onSubmit: (result: { catId: string, task: string }) => void;
categories: Category[];

constructor(app: App, categories: Category[], onSubmit: (result: { catId: string; task: string; }) => void) {
super(app);
this.onSubmit = onSubmit;
this.categories = categories.sort((a, b) => {
return this.getFullPathToCategoryTitle(a, categories).localeCompare(this.getFullPathToCategoryTitle(b, categories));
});
this.result = { catId: inboxCategory._id, task: '' };
}

onOpen() {
const { contentEl } = this;
let categoryInput: HTMLInputElement;

contentEl.createEl("h1", { text: "New Amazing Marvin Task" });

new Setting(contentEl)
.setName("Category")
.addText(text => {
categoryInput = text.inputEl;
text.setValue(inboxCategory.title);
this.result.catId = inboxCategory._id;
text.onChange(value => {
const suggester = new CategorySuggesterModal(this.app, this.categories, (item: Category) => {
categoryInput.value = item.title;
this.result.catId = item._id;
suggester.close();
});
suggester.open();
});
});

new Setting(contentEl)
.setHeading().setName("Task");

new Setting(contentEl)
.addTextArea((textArea: TextAreaComponent) => {
textArea.onChange((value: string) => {
this.result.task = value;
});
}).settingEl.addClass("am-task-textarea-setting");

const shortcutsDesc = document.createDocumentFragment();
shortcutsDesc.appendText('The Task field accepts labels (@), time estimates (~), and scheduled dates (+). See ');
shortcutsDesc.appendChild(this.getShortcutsLink());
shortcutsDesc.appendText('.');

new Setting(contentEl)
.setDesc(shortcutsDesc);

new Setting(contentEl)
.addButton((btn) =>
btn
.setButtonText("Add")
.setCta()
.onClick(() => {
this.addTask();
}));

this.modalEl.addEventListener("keydown", (e: KeyboardEvent) => {
if (e.key === "Enter" && e.ctrlKey) {
e.preventDefault();
this.addTask();
}
});

}

private addTask() {
if (!this.result.task.trim()) {
new Notice('Please enter a task description.', 4000);
return;
}
this.close();
if (this.onSubmit && this.result.task) {
this.onSubmit(this.result);
}
}



private getShortcutsLink(): HTMLAnchorElement {
const a = document.createElement('a');
a.href = 'https://help.amazingmarvin.com/en/articles/1949399-using-shortcuts-while-creating-a-task';
a.text = 'Using shortcuts while creating a task';
a.target = '_blank';
return a;
}

private getFullPathToCategoryTitle(category: Category, categories: Category[]): string {
let parent = category.parentId;

let parentTitle = [];
parentTitle.push('/');
while (parent && parent !== "root") {
const parentCategory = categories.find(c => c._id === parent);
if (parentCategory) {
parentTitle.push(parentCategory.title);
parent = parentCategory.parentId;
} else {
break;
}
}
return `${parentTitle.reverse().join("/")}${category.title}`;
}

onClose() {
let { contentEl } = this;
contentEl.empty();
}
}
13 changes: 5 additions & 8 deletions src/amTaskWatcher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,11 @@ export function amTaskWatcher(_app: App, plugin: AmazingMarvinPlugin) {
return;
}
update.changes.iterChanges((fromA, _toA, _fromB, _toB, change) => {
//only match if the change is a single character and it's an X or x
if (change.length === 1 && (change.sliceString(0, 1) === "X" || change.sliceString(0, 1) === "x")) {
let line = update.state.doc.lineAt(fromA).text;

const match = line.match(COMPLETED_AM_TASK);
if (match && match[1]) {
plugin.markDone(match[1]);
}
//only match if the change is on an AM task and it's a completed task
let line = update.state.doc.lineAt(fromA).text;
const match = line.match(COMPLETED_AM_TASK);
if (match && match[1]) {
plugin.markDone(match[1]);
}
});
}
Expand Down
Loading

0 comments on commit 1398e23

Please sign in to comment.