Skip to content

Commit

Permalink
Merge pull request #1 from chhoumann/choices
Browse files Browse the repository at this point in the history
  • Loading branch information
chhoumann authored Jun 12, 2021
2 parents 0a8ef2d + bcd17ed commit 61a70b1
Show file tree
Hide file tree
Showing 73 changed files with 3,163 additions and 14 deletions.
2 changes: 2 additions & 0 deletions .github/FUNDING.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
github: chhoumann
custom: https://www.buymeacoffee.com/chhoumann
84 changes: 84 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
# From https://github.com/st3v3nmw/obsidian-spaced-repetition/blob/master/.github/workflows/release.yml
name: Build obsidian plugin

on:
push:
# Sequence of patterns matched against refs/tags
tags:
- '*' # Push events to matching any tag format, i.e. 1.0, 20.15.10

env:
PLUGIN_NAME: quickadd # plugin id

jobs:
build:

runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v2
- name: Use Node.js
uses: actions/setup-node@v1
with:
node-version: '14.x' # You might need to adjust this value to your own version
- name: Build
id: build
run: |
npm install
npm run build --if-present
mkdir ${{ env.PLUGIN_NAME }}
cp main.js manifest.json styles.css ${{ env.PLUGIN_NAME }}
zip -r ${{ env.PLUGIN_NAME }}.zip ${{ env.PLUGIN_NAME }}
ls
echo "::set-output name=tag_name::$(git tag --sort version:refname | tail -n 1)"
- name: Create Release
id: create_release
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
VERSION: ${{ github.ref }}
with:
tag_name: ${{ github.ref }}
release_name: ${{ github.ref }}
draft: false
prerelease: false
- name: Upload zip file
id: upload-zip
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: ./${{ env.PLUGIN_NAME }}.zip
asset_name: ${{ env.PLUGIN_NAME }}-${{ steps.build.outputs.tag_name }}.zip
asset_content_type: application/zip
- name: Upload main.js
id: upload-main
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: ./main.js
asset_name: main.js
asset_content_type: text/javascript
- name: Upload manifest.json
id: upload-manifest
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: ./manifest.json
asset_name: manifest.json
asset_content_type: application/json
- name: Upload styles.css
id: upload-css
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: ./styles.css
asset_name: styles.css
asset_content_type: text/css
2 changes: 1 addition & 1 deletion manifest.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"id": "quickadd",
"name": "QuickAdd",
"version": "0.0.0",
"version": "0.1.0",
"minAppVersion": "0.12.00",
"description": "Quickly add new pages or content to your vault.",
"author": "Christian B. B. Houmann",
Expand Down
14 changes: 9 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "quickadd",
"version": "0.0.0",
"version": "0.1.0",
"description": "Quickly add new pages or content to your vault.",
"main": "main.js",
"scripts": {
Expand All @@ -15,12 +15,16 @@
"@babel/core": "7.14.3",
"@babel/preset-env": "7.14.2",
"@babel/preset-typescript": "7.13.0",
"@fortawesome/free-regular-svg-icons": "5.15.3",
"@fortawesome/free-solid-svg-icons": "5.15.3",
"@popperjs/core": "^2.9.2",
"@rollup/plugin-commonjs": "^18.0.0",
"@rollup/plugin-node-resolve": "^11.2.1",
"@rollup/plugin-typescript": "^8.2.1",
"@tsconfig/svelte": "1.0.10",
"@types/jest": "26.0.23",
"@types/node": "14.17.1",
"@types/uuid": "8.3.0",
"babel-core": "6.26.3",
"babel-jest": "27.0.1",
"jest": "27.0.1",
Expand All @@ -30,13 +34,13 @@
"rollup-plugin-strip-code": "0.2.7",
"rollup-plugin-svelte": "^7.1.0",
"svelte": "^3.37.0",
"svelte-awesome": "2.3.2",
"svelte-check": "^1.3.0",
"svelte-dnd-action": "0.9.8",
"svelte-preprocess": "^4.7.0",
"ts-jest": "27.0.0",
"tslib": "^2.2.0",
"typescript": "^4.2.4"
},
"dependencies": {
"@popperjs/core": "^2.9.2"
"typescript": "^4.2.4",
"uuid": "8.3.2"
}
}
146 changes: 146 additions & 0 deletions src/MacrosManager.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
import type {IMacro} from "./types/macros/IMacro";
import {App, ButtonComponent, Modal, Setting, TextComponent, ToggleComponent} from "obsidian";
import {MacroBuilder} from "./gui/MacroBuilder";
import {QuickAddMacro} from "./types/macros/QuickAddMacro";

export class MacrosManager extends Modal {
public waitForClose: Promise<IMacro[]>;
private resolvePromise: (macros: IMacro[]) => void;
private rejectPromise: (reason?: any) => void;
private updateMacroContainer: () => void;

constructor(public app: App, private macros: IMacro[]) {
super(app)

this.waitForClose = new Promise<IMacro[]>(
((resolve, reject) => {
this.rejectPromise = reject;
this.resolvePromise = resolve;
})
);

this.open();
this.display();
}

private display(): void {
this.contentEl.createEl('h2', {text: 'Macro Manager'}).style.textAlign = "center";
this.addMacroSettings();
this.addAddMacroBar();
}

private addMacroSettings() {
const macroContainer: HTMLDivElement = this.contentEl.createDiv();
this.updateMacroContainer = () => {
if (this.macros.length <= 1)
macroContainer.className = "macroContainer macroContainer1";
if (this.macros.length === 2)
macroContainer.className = "macroContainer macroContainer2";
if (this.macros.length > 2)
macroContainer.className = "macroContainer macroContainer3";
}

this.macros.forEach(macro => this.addMacroSetting(macro, macroContainer));

this.updateMacroContainer();
}

private addMacroSetting(macro: IMacro, container: HTMLDivElement) {
const configureMacroContainer = container.createDiv();

const macroSetting: Setting = new Setting(configureMacroContainer);
macroSetting.setName(macro.name);
macroSetting.infoEl.style.fontWeight = "bold";

this.addMacroConfigurationItem(configureMacroContainer, itemContainerEl => {
this.addSpanWithText(itemContainerEl, "Run on plugin load");

const toggle: ToggleComponent = new ToggleComponent(itemContainerEl);
toggle.setValue(macro.runOnStartup);

toggle.onChange(value => {
macro.runOnStartup = value;

this.updateMacro(macro);
});
});

configureMacroContainer.addClass("configureMacroDiv");
this.addMacroConfigurationItem(configureMacroContainer, itemContainerEl => {
const deleteButton: ButtonComponent = new ButtonComponent(itemContainerEl);
deleteButton.setClass('mod-warning');
deleteButton.buttonEl.style.marginRight = "0";

deleteButton.setButtonText("Delete").onClick(evt => {
this.macros = this.macros.filter(m => m.id !== macro.id);
this.reload();
});

const configureButton: ButtonComponent = new ButtonComponent(itemContainerEl);
configureButton.setClass('mod-cta');
configureButton.buttonEl.style.marginRight = "0";

configureButton.setButtonText("Configure").onClick(async evt => {
const newMacro = await new MacroBuilder(this.app, macro).waitForClose;

if (newMacro) {
this.updateMacro(newMacro);
this.reload();
}
});
});

}

private addMacroConfigurationItem(container: HTMLDivElement, callback: (itemContainerEl) => void, classString: string = "configureMacroDivItem") {
const item: HTMLDivElement = container.createDiv();
item.addClass(classString);

callback(item);
}

private addSpanWithText(container: HTMLDivElement, text: string) {
const configureText: HTMLSpanElement = container.createEl('span');
configureText.setText(text);
}

private updateMacro(macro: IMacro) {
const index = this.macros.findIndex(v => v.id === macro.id);
this.macros[index] = macro;

if (this.updateMacroContainer)
this.updateMacroContainer();

this.reload();
}

private reload(): void {
this.contentEl.empty();
this.display();
}

private addAddMacroBar() {
const addMacroBarContainer: HTMLDivElement = this.contentEl.createDiv();
addMacroBarContainer.addClass("addMacroBarContainer");

const nameInput: TextComponent = new TextComponent(addMacroBarContainer);
nameInput.setPlaceholder("Macro name");

const addMacroButton: ButtonComponent = new ButtonComponent(addMacroBarContainer);
addMacroButton.setButtonText("Add macro")
.setClass("mod-cta")
.onClick(() => {
const inputValue = nameInput.getValue();

if (inputValue !== "" && !this.macros.find(m => m.name === inputValue)) {
this.macros.push(new QuickAddMacro(inputValue));
this.reload();
}
})
}

onClose() {
super.onClose();
this.resolvePromise(this.macros);
}
}
19 changes: 19 additions & 0 deletions src/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
export const FORMAT_SYNTAX: string[] = [
"{{DATE}}", "{{DATE:<DATEFORMAT>}}", "{{VDATE:<VARIABLE NAME>, <DATE FORMAT>}}",
"{{VALUE}}", "{{NAME}}", "{{VALUE:<VARIABLE NAME>}}", "{{LINKCURRENT}}"
];

export const FILE_NAME_FORMAT_SYNTAX: string[] = [
"{{DATE}}", "{{DATE:<DATEFORMAT>}}", "{{VDATE:<VARIABLE NAME>, <DATE FORMAT>}}",
"{{VALUE}}", "{{NAME}}", "{{VALUE:<VARIABLE NAME>}}",
]

export const FILE_NUMBER_REGEX: RegExp = new RegExp(/([0-9]*)\.md$/);
export const DATE_REGEX: RegExp = new RegExp(/{{DATE(\+[0-9]*)?}}/);
export const DATE_REGEX_FORMATTED: RegExp = new RegExp(/{{DATE:([^}\n\r+]*)(\+[0-9]*)?}}/);
export const NAME_VALUE_REGEX: RegExp = new RegExp(/{{NAME}}|{{VALUE}}/);
export const VARIABLE_REGEX: RegExp = new RegExp(/{{VALUE:([^\n\r}]*)}}/);
export const DATE_VARIABLE_REGEX: RegExp = new RegExp(/{{VDATE:([^\n\r},]*),\s*([^\n\r},]*)}}/);
export const LINK_TO_CURRENT_FILE_REGEX: RegExp = new RegExp(/{{LINKCURRENT}}/);
export const MARKDOWN_FILE_EXTENSION_REGEX: RegExp = new RegExp(/\.md$/);
export const JAVASCRIPT_FILE_EXTENSION_REGEX: RegExp = new RegExp(/\.js$/);
63 changes: 63 additions & 0 deletions src/engine/CaptureChoiceEngine.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import {QuickAddEngine} from "./QuickAddEngine";
import type ICaptureChoice from "../types/choices/ICaptureChoice";
import type {App, TFile} from "obsidian";
import {log} from "../logger/logManager";
import GenericInputPrompt from "../gui/GenericInputPrompt/genericInputPrompt";
import {CaptureChoiceFormatter} from "../formatters/captureChoiceFormatter";
import {appendToCurrentLine} from "../utility";
import {MARKDOWN_FILE_EXTENSION_REGEX} from "../constants";

export class CaptureChoiceEngine extends QuickAddEngine {
choice: ICaptureChoice;
private formatter: CaptureChoiceFormatter;

constructor(app: App, choice: ICaptureChoice) {
super(app);
this.choice = choice;
this.formatter = new CaptureChoiceFormatter(app);
}

async run(): Promise<void> {
const captureTo = this.choice.captureTo;
if (!captureTo) {
log.logError(`Invalid capture to for ${this.choice.name}`);
return;
}

const filePath = await this.getFilePath(captureTo);
let content: string;

if (!this.choice.format.enabled)
content = await GenericInputPrompt.Prompt(this.app, this.choice.name);
else
content = this.choice.format.format;

if (this.choice.task)
content = `- [ ] ${content}`;

if (await this.fileExists(filePath)) {
const file: TFile = await this.getFileByPath(filePath);
if (!file) return;

const fileContent: string = await this.app.vault.read(file);
const newFileContent: string = await this.formatter.formatContent(content, this.choice, fileContent, file);

await this.app.vault.modify(file, newFileContent);
} else {
const createdFile = await this.createFileWithInput(filePath, content);
if (!createdFile) {
log.logError(`could not create '${filePath}.'`);
return;
}
}

if (this.choice.appendLink)
appendToCurrentLine(`[[${filePath.replace(MARKDOWN_FILE_EXTENSION_REGEX, '')}]]`, this.app);
}

private async getFilePath(captureTo: string) {
const formattedCaptureTo: string = await this.formatter.formatFileName(captureTo, this.choice.name);
return this.formatFilePath("", formattedCaptureTo);
}

}
Loading

0 comments on commit 61a70b1

Please sign in to comment.