Skip to content

Commit

Permalink
feat(Hierarchy Note): ✨ Hierarchy Note Adjuster! (#143)
Browse files Browse the repository at this point in the history
  • Loading branch information
SkepticMystic committed Dec 4, 2021
1 parent ce8e8dd commit b5afae2
Show file tree
Hide file tree
Showing 6 changed files with 373 additions and 2 deletions.
120 changes: 120 additions & 0 deletions src/Components/ModifyHNItemComp.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
<script lang="ts">
import { error } from "console";
import { Notice, TFile } from "obsidian";
import { onMount } from "svelte";
import { ARROW_DIRECTIONS } from "../constants";
import type { BCSettings } from "../interfaces";
import type { ModifyHierItemModal } from "../ModifyHierItemModal";
import { dropWikilinks, makeWiki } from "../sharedFunctions";
export let modal: ModifyHierItemModal;
export let settings: BCSettings;
export let hnItem: HNItem;
export let file: TFile;
export let rel: "up" | "same" | "down";
interface HNItem {
depth: number;
line: string;
lineNo: number;
}
let inputEl: HTMLInputElement;
let newItem = "";
const buildNewItem = (
newItem: string,
depth = hnItem.depth,
preview = false
) =>
`${" ".repeat(Math.round(depth / (preview ? 2 : 1)))}- ${
preview ? newItem || "<Empty>" : makeWiki(newItem)
}`;
onMount(() => inputEl.focus());
</script>

<h5>Add an {ARROW_DIRECTIONS[rel]} to {dropWikilinks(hnItem.line)}</h5>
<div>
{#if rel === "up"}
{#if hnItem.depth === 0}
<div>Can't add parent to top level item, choose another direction</div>
{:else}
<div>
<pre>
{buildNewItem(newItem, hnItem.depth - 4, true)}
</pre>
</div>
{/if}
{/if}
<div>
<pre>
<strong>{buildNewItem(dropWikilinks(hnItem.line), hnItem.depth, true)}</strong>
</pre>
</div>
{#if rel === "same"}
<div>
<pre>
{buildNewItem(newItem, hnItem.depth, true)}
</pre>
</div>
{:else if rel === "down"}
<div>
<pre>
{buildNewItem(newItem, hnItem.depth + 4, true)}
</pre>
</div>
{/if}

<!-- svelte-ignore a11y-no-onchange -->
<select class="dropdown" width="1" bind:value={rel}>
<option value="up">up</option>
<option value="same">same</option>
<option value="down">down</option>
</select>

<input
type="text"
placeholder="New item"
bind:this={inputEl}
bind:value={newItem}
/>

<button
on:click={async (e) => {
if (rel === "up" && hnItem.depth === 0) {
new Notice(
"Can't add parent to top level item, choose another direction"
);
return;
} else {
try {
const content = await modal.app.vault.read(file);
const lines = content.split("\n");
const lineNo = rel === "up" ? hnItem.lineNo : hnItem.lineNo + 1;

const depth =
rel === "up"
? hnItem.depth - 4
: rel === "down"
? hnItem.depth + 4
: hnItem.depth;

lines.splice(lineNo, 0, buildNewItem(newItem, depth));
await modal.app.vault.modify(file, lines.join("\n"));
modal.close();
} catch (err) {
error(err);
new Notice("An error occured, please check the console");
}
}
}}>Add</button
>
</div>

<style>
pre {
display: inline;
}
</style>
4 changes: 2 additions & 2 deletions src/DownView.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { ItemView, WorkspaceLeaf } from "obsidian";
import { addFeatherIcon } from "obsidian-community-lib";
import Down from "./Components/Down.svelte";
import { DOWN_VIEW } from "./constants";
import type BCPlugin from "./main";
import Down from "./Components/Down.svelte";
import { addFeatherIcon } from "obsidian-community-lib";

export default class DownView extends ItemView {
private plugin: BCPlugin;
Expand Down
52 changes: 52 additions & 0 deletions src/HierNoteModal.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { App, FuzzyMatch, FuzzySuggestModal, Notice } from "obsidian";
import { HierarchyNoteManipulator } from "./HierarchyNoteManipulator";
import type { BCSettings } from "./interfaces";
import type BCPlugin from "./main";

export class HierarchyNoteSelectorModal extends FuzzySuggestModal<string> {
app: App;
plugin: BCPlugin;
settings: BCSettings;

constructor(app: App, plugin: BCPlugin) {
super(app);
this.app = app;
this.plugin = plugin;
this.settings = this.plugin.settings;
}

onOpen(): void {
this.setPlaceholder("HN Chooser");
const { hierarchyNotes } = this.settings;
if (hierarchyNotes.length === 0) {
this.close();
new Notice("No hierarchy notes found");
} else if (hierarchyNotes.length === 1) {
this.close();
new HierarchyNoteManipulator(
this.app,
this.plugin,
hierarchyNotes[0]
).open();
} else {
super.onOpen();
}
}

getItems(): string[] {
return this.settings.hierarchyNotes;
}

getItemText(item: string): string {
return `${item}`;
}

renderSuggestion(item: FuzzyMatch<string>, el: HTMLElement) {
super.renderSuggestion(item, el);
}

onChooseItem(item: string, evt: MouseEvent | KeyboardEvent): void {
new HierarchyNoteManipulator(this.app, this.plugin, item).open();
this.close();
}
}
140 changes: 140 additions & 0 deletions src/HierarchyNoteManipulator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
import { error } from "loglevel";
import {
App,
FuzzyMatch,
FuzzySuggestModal,
ListItemCache,
MarkdownView,
Notice,
TFile,
} from "obsidian";
import { ModifyHierItemModal } from "./ModifyHierItemModal";
import type { BCSettings } from "./interfaces";
import type BCPlugin from "./main";
import { dropWikilinks } from "./sharedFunctions";

interface HNItem {
depth: number;
line: string;
lineNo: number;
}

export class HierarchyNoteManipulator extends FuzzySuggestModal<HNItem> {
app: App;
plugin: BCPlugin;
settings: BCSettings;
hierNoteName: string;
lines: string[];
listItems: ListItemCache[];
file: TFile;

constructor(app: App, plugin: BCPlugin, hierNoteName: string) {
super(app);
this.app = app;
this.plugin = plugin;
this.settings = this.plugin.settings;
this.hierNoteName = hierNoteName;

const chooseOverride = (evt: KeyboardEvent) => {
// @ts-ignore
this.chooser.useSelectedItem(evt);
return false;
};
this.scope.register([], "Delete", chooseOverride);
this.scope.register(["Shift"], "ArrowUp", chooseOverride);
this.scope.register(["Shift"], "ArrowRight", chooseOverride);
this.scope.register(["Shift"], "ArrowDown", chooseOverride);
}

async onOpen(): Promise<void> {
this.setPlaceholder("HN Manipulator");
this.setInstructions([
{ command: "Enter/Click", purpose: "Jump to item" },
{ command: "Shift + ↑", purpose: "Add parent" },
{ command: "Shift + →", purpose: "Add sibling" },
{ command: "Shift + ↓", purpose: "Add child" },
{ command: "Delete", purpose: "Delete item" },
]);

this.file = this.app.metadataCache.getFirstLinkpathDest(
this.hierNoteName,
""
);
if (!this.file) this.lines = [];
const content = await this.app.vault.cachedRead(this.file);
this.lines = content.split("\n");

this.listItems = this.app.metadataCache.getFileCache(this.file).listItems;

super.onOpen();
}

getItems(): HNItem[] {
const items = this.listItems
.map((item) => {
const i = item.position.start.line;
return { i, line: this.lines[i] };
})
.map((item) => {
const splits = item.line.split("- ");
const depth = splits[0].length;
const line = splits.slice(1).join("- ");

return { depth, line, lineNo: item.i };
});

return items;
}

getItemText(item: HNItem): string {
return `${" ".repeat(item.depth)}- ${dropWikilinks(item.line)}`;
}

renderSuggestion(item: FuzzyMatch<HNItem>, el: HTMLElement) {
super.renderSuggestion(item, el);
el.innerText = `${" ".repeat(item.item.depth)}- ${dropWikilinks(
item.item.line
)}`;
}

async deleteItem(item: HNItem): Promise<void> {
try {
this.lines.splice(item.lineNo, 1);
this.listItems.splice(item.lineNo, 1);
await this.app.vault.modify(this.file, this.lines.join("\n"));
new Notice("Item deleted Succesfully");
} catch (err) {
error(err);
new Notice("An error occured. Please check the console");
}
}

onChooseItem(item: HNItem, evt: MouseEvent | KeyboardEvent): void {
if (evt instanceof KeyboardEvent && evt.key === "Delete") {
this.deleteItem(item);
} else if (evt instanceof KeyboardEvent && evt.shiftKey) {
const rel =
evt.key === "ArrowUp"
? "up"
: evt.key === "ArrowDown"
? "down"
: "same";

new ModifyHierItemModal(
this.app,
this.plugin,
item,
this.file,
rel
).open();
this.close();
} else {
const view = this.app.workspace.getActiveViewOfType(MarkdownView);
const { editor } = view ?? {};
if (!editor) return;
//@ts-ignore
view.leaf.openFile(this.file, { active: true, mode: "source" });
editor.setCursor({ line: item.lineNo, ch: item.depth + 2 });
}
}
}
52 changes: 52 additions & 0 deletions src/ModifyHierItemModal.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { App, Modal, TFile } from "obsidian";
import ModifyHNItemComp from "./Components/ModifyHNItemComp.svelte";
import type BCPlugin from "./main";

interface HNItem {
depth: number;
line: string;
lineNo: number;
}

export class ModifyHierItemModal extends Modal {
plugin: BCPlugin;
modal: ModifyHierItemModal;
hnItem: HNItem;
file: TFile;
rel: "up" | "same" | "down";

constructor(
app: App,
plugin: BCPlugin,
hnItem: HNItem,
file: TFile,
rel: "up" | "same" | "down"
) {
super(app);
this.plugin = plugin;
this.modal = this;
this.hnItem = hnItem;
this.file = file;
this.rel = rel;
}

onOpen() {
const { contentEl } = this;
contentEl.empty();

new ModifyHNItemComp({
target: contentEl,
props: {
modal: this,
settings: this.plugin.settings,
hnItem: this.hnItem,
file: this.file,
rel: this.rel,
},
});
}

onClose() {
this.contentEl.empty();
}
}
7 changes: 7 additions & 0 deletions src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ import {
splitAtYaml,
} from "./sharedFunctions";
import { VisModal } from "./VisModal";
import { HierarchyNoteSelectorModal } from "./HierNoteModal";

export default class BCPlugin extends Plugin {
settings: BCSettings;
Expand Down Expand Up @@ -276,6 +277,12 @@ export default class BCPlugin extends Plugin {
},
});

this.addCommand({
id: "manipulate-hierarchy-notes",
name: "Adjust Hierarchy Notes",
callback: () => new HierarchyNoteSelectorModal(this.app, this).open(),
});

this.addCommand({
id: "Refresh-Breadcrumbs-Index",
name: "Refresh Breadcrumbs Index",
Expand Down

0 comments on commit b5afae2

Please sign in to comment.