mirror of
https://github.com/poanse/obsidian-taskmap.git
synced 2026-07-22 06:05:58 +00:00
changed logo, added folder setting
This commit is contained in:
parent
7caa10f309
commit
3f659d1363
12 changed files with 135 additions and 39 deletions
|
|
@ -26,3 +26,15 @@ export function parseNumber(value: string | null | undefined): number | null {
|
|||
const num = Number(value);
|
||||
return isNaN(num) || value.trim() === "" ? null : num;
|
||||
}
|
||||
|
||||
export const LOGO_NAME = "TaskmapLogo";
|
||||
|
||||
export const LOGO_CONTENT = `
|
||||
<g transform="translate(50,50) scale(0.9) translate(-50,-50)">
|
||||
<path d="M66.66667 12.5L66.66667 29.16667C66.66667 31.46783 68.53217 33.33333 70.83333 33.33333L87.5 33.33333C89.80083 33.33333 91.66667 31.46783 91.66667 29.16667L91.66667 12.5C91.66667 10.19883 89.80083 8.33333 87.5 8.33333L70.83333 8.33333C68.53217 8.33333 66.66667 10.19883 66.66667 12.5Z" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" fill="none" stroke-width="8"/>
|
||||
<path d="M66.66667 70.83333L66.66667 87.5C66.66667 89.80083 68.53217 91.66667 70.83333 91.66667L87.5 91.66667C89.80083 91.66667 91.66667 89.80083 91.66667 87.5L91.66667 70.83333C91.66667 68.53217 89.80083 66.66667 87.5 66.66667L70.83333 66.66667C68.53217 66.66667 66.66667 68.53217 66.66667 70.83333Z" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" fill="none" stroke-width="8"/>
|
||||
<path d="M8.33333 41.66667L8.33333 58.33333C8.33333 60.6345 10.19883 62.5 12.5 62.5L29.16667 62.5C31.46783 62.5 33.33333 60.6345 33.33333 58.33333L33.33333 41.66667C33.33333 39.3655 31.46783 37.5 29.16667 37.5L12.5 37.5C10.19883 37.5 8.33333 39.3655 8.33333 41.66667Z" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" fill="none" stroke-width="8"/>
|
||||
<path d="M66.66667 79.16667L54.16667 79.16667C53.06158 79.16667 52.00175 78.72767 51.22042 77.94625C50.439 77.16492 50 76.10508 50 75L50 25C50 23.89492 50.439 22.83508 51.22042 22.05375C52.00175 21.27233 53.06158 20.83333 54.16667 20.83333L66.66667 20.83333" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" fill="none" stroke-width="8"/>
|
||||
<path d="M50 50L33.33333 50" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" fill="none" stroke-width="8"/>
|
||||
</g>
|
||||
`;
|
||||
|
|
|
|||
|
|
@ -88,7 +88,10 @@ export class Context {
|
|||
* so pan/zoom and the scene stay intact.
|
||||
*/
|
||||
public reloadFromDisk(projectData: ProjectData): void {
|
||||
this.versionedData = new VersionedData(projectData, new HistoryManager());
|
||||
this.versionedData = new VersionedData(
|
||||
projectData,
|
||||
new HistoryManager(),
|
||||
);
|
||||
this.taskDraggingManager.reset();
|
||||
this.draggedTaskId = NoTaskId;
|
||||
this.reparentingTaskId = NoTaskId;
|
||||
|
|
@ -409,7 +412,8 @@ export class Context {
|
|||
|
||||
public save() {
|
||||
// Cannot have reference to the view, so save all opened views
|
||||
this.app.workspace.getLeavesOfType(TASKMAP_VIEW_TYPE)
|
||||
this.app.workspace
|
||||
.getLeavesOfType(TASKMAP_VIEW_TYPE)
|
||||
.map((leaf) => leaf.view)
|
||||
.filter((view) => view instanceof TaskmapView)
|
||||
.forEach((view) => view.debouncedSave());
|
||||
|
|
@ -483,10 +487,18 @@ export class Context {
|
|||
* Creates note named after task name if not exists already.
|
||||
* Changes task name to a link to the node.
|
||||
* Opens the note on the right side.
|
||||
* @param taskId
|
||||
*/
|
||||
public async createLinkedNote(taskId: TaskId) {
|
||||
const filepath = this.filePathFromTask(taskId);
|
||||
public async createLinkedNote(taskId: TaskId, plugin: TaskmapPlugin) {
|
||||
const taskmapPath =
|
||||
plugin.app.workspace.getActiveViewOfType(TaskmapView)?.file?.parent
|
||||
?.path;
|
||||
let folderPath = "";
|
||||
if (plugin.settings.newNoteFolder) {
|
||||
folderPath = plugin.settings.newNoteFolder;
|
||||
} else if (taskmapPath) {
|
||||
folderPath = taskmapPath;
|
||||
}
|
||||
const filepath = this.filePathFromTask(taskId, folderPath);
|
||||
|
||||
try {
|
||||
const abstractFile = this.app.vault.getAbstractFileByPath(filepath);
|
||||
|
|
@ -499,7 +511,7 @@ export class Context {
|
|||
);
|
||||
this.versionedData.setName(
|
||||
taskId,
|
||||
tasknameFromFilePath(filepath),
|
||||
tasknameFromFilePath(this.versionedData.getTask(taskId).name),
|
||||
filepath,
|
||||
);
|
||||
this.save();
|
||||
|
|
@ -509,19 +521,25 @@ export class Context {
|
|||
await this.openOrFocusNote(tfile);
|
||||
} catch (error) {
|
||||
new Notice(
|
||||
"Error creating note. It might already exist or the name is invalid.",
|
||||
`Error creating note. It might already exist or the name is invalid. ${String(error)}`,
|
||||
);
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
|
||||
public filePathFromTask(taskId: TaskId) {
|
||||
public filePathFromTask(taskId: TaskId, folder: string = "") {
|
||||
const task = this.versionedData.getTask(taskId);
|
||||
const taskName = task.name;
|
||||
// Sanitize the name for Obsidian filenames
|
||||
let sanitizedName = taskName.replace(/[\\/:*?"<>|]/g, "-");
|
||||
sanitizedName = delink(sanitizedName);
|
||||
return `${sanitizedName}.md`;
|
||||
if (folder === "" || folder === "/") {
|
||||
return `${sanitizedName}.md`;
|
||||
}
|
||||
if (!folder.endsWith("/")) {
|
||||
folder = folder + "/";
|
||||
}
|
||||
return `${folder}${sanitizedName}.md`;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -569,7 +587,8 @@ export class Context {
|
|||
const candidateLeaves = rootLeaves
|
||||
.reverse()
|
||||
.filter(
|
||||
(leaf) => leaf !== activeLeaf && !(leaf.view instanceof TaskmapView),
|
||||
(leaf) =>
|
||||
leaf !== activeLeaf && !(leaf.view instanceof TaskmapView),
|
||||
);
|
||||
|
||||
let anotherUnpinnedLeaf: WorkspaceLeaf | null = null;
|
||||
|
|
|
|||
|
|
@ -1,12 +0,0 @@
|
|||
import { IconCode, StatusCode } from "./types";
|
||||
|
||||
export const LOGO_NAME = "TaskmapLogo";
|
||||
export const LOGO_CONTENT = `
|
||||
<path d="M88.9366 24.8308V33.8571H55.7464V24.8308H88.9366ZM91.1514 22.5714V11.2857C91.1514 10.0391 90.1586 9.02637 88.9366 9.02637H55.7464C54.5244 9.02637 53.5316 10.0391 53.5316 11.2857V22.5714C53.5316 23.818 54.5244 24.8308 55.7464 24.8308V33.8571L54.612 33.802C49.4075 33.2615 45.267 29.0378 44.7371 23.7287L44.683 22.5714V11.2857C44.683 5.05279 49.6363 9.0886e-08 55.7464 0H88.9366C95.0467 0 100 5.05279 100 11.2857V22.5714C100 28.4138 95.6484 33.2227 90.071 33.802L88.9366 33.8571V24.8308C90.1586 24.8308 91.1514 23.818 91.1514 22.5714Z" fill="currentColor"/>
|
||||
<path d="M88.9366 69.9736V79H55.7464V69.9736H88.9366ZM91.1514 67.7143V56.4286C91.1514 55.182 90.1586 54.1692 88.9366 54.1692H55.7464C54.5244 54.1692 53.5316 55.182 53.5316 56.4286V67.7143C53.5316 68.9609 54.5244 69.9736 55.7464 69.9736V79L54.612 78.9449C49.4075 78.4043 45.267 74.1806 44.7371 68.8715L44.683 67.7143V56.4286C44.683 50.1956 49.6363 45.1429 55.7464 45.1429H88.9366C95.0467 45.1429 100 50.1956 100 56.4286V67.7143C100 73.5566 95.6484 78.3656 90.071 78.9449L88.9366 79V69.9736C90.1586 69.9736 91.1514 68.9609 91.1514 67.7143Z" fill="currentColor"/>
|
||||
<path d="M22.8099 52.5212V26.4781C22.8099 17.752 29.7487 10.6737 38.3029 10.6737H47.6701V19.7111H38.3029C34.6368 19.7111 31.6692 22.7384 31.6692 26.4781V52.5212C31.6692 56.261 34.6368 59.2993 38.3029 59.2993H47.6701V68.3256H38.3029C29.7487 68.3256 22.8099 61.2473 22.8099 52.5212Z" fill="currentColor"/>
|
||||
<path d="M27.2371 34.9806V44.018H0V34.9806H27.2371Z" fill="currentColor"/>
|
||||
`;
|
||||
|
||||
export const LOGO_CONTENT_SMALL = `
|
||||
`;
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
import { PluginSettingTab, App, Setting } from "obsidian";
|
||||
import { PluginSettingTab, App, Setting, TFolder, Notice } from "obsidian";
|
||||
import type TaskmapPlugin from "./main";
|
||||
import { FolderSuggest } from "./helpers/FolderSuggest";
|
||||
|
||||
export class TaskmapSettingTab extends PluginSettingTab {
|
||||
plugin: TaskmapPlugin;
|
||||
|
|
@ -38,5 +39,26 @@ export class TaskmapSettingTab extends PluginSettingTab {
|
|||
await this.plugin.saveSettings();
|
||||
}),
|
||||
);
|
||||
new Setting(containerEl)
|
||||
.setName("Note folder")
|
||||
.setDesc(
|
||||
"Notes created from tasks will be placed in this folder. If blank, they will be placed in the default location for this vault.",
|
||||
)
|
||||
.addText((text) => {
|
||||
new FolderSuggest(this.app, text.inputEl);
|
||||
text.setPlaceholder("")
|
||||
.setValue(this.plugin.settings.newNoteFolder)
|
||||
.onChange(async (value) => {
|
||||
if (
|
||||
value === "" ||
|
||||
this.plugin.app.vault.getAbstractFileByPath(
|
||||
value,
|
||||
) instanceof TFolder
|
||||
) {
|
||||
this.plugin.settings.newNoteFolder = value;
|
||||
await this.plugin.saveSettings();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,11 @@
|
|||
export interface TaskmapPluginSettings {
|
||||
export interface TaskmapSettings {
|
||||
zoomSensitivityTouchpad: string;
|
||||
zoomSensitivityMouse: string;
|
||||
newNoteFolder: string;
|
||||
}
|
||||
|
||||
export const DEFAULT_SETTINGS: TaskmapPluginSettings = {
|
||||
export const DEFAULT_SETTINGS: TaskmapSettings = {
|
||||
zoomSensitivityTouchpad: "100",
|
||||
zoomSensitivityMouse: "100",
|
||||
newNoteFolder: "",
|
||||
};
|
||||
|
|
@ -89,7 +89,7 @@
|
|||
} else if (iconCode == IconCode.REMOVE_MULTIPLE) {
|
||||
context.removeTaskBranch(context.selectedTaskId);
|
||||
} else if (iconCode == IconCode.CREATE_LINKED_NOTE) {
|
||||
context.createLinkedNote(context.selectedTaskId);
|
||||
context.createLinkedNote(context.selectedTaskId, context.plugin);
|
||||
} else if (iconCode == IconCode.KEY) {
|
||||
context.chosenBlockedId = context.chosenBlockedId === NoTaskId ? context.selectedTaskId : NoTaskId;
|
||||
} else if (iconCode == IconCode.LOCK) {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
<script lang="ts">
|
||||
import {onMount, tick} from "svelte";
|
||||
import {Component, MarkdownRenderer, Notice} from "obsidian";
|
||||
import {LinkSuggest} from "../LinkSuggest";
|
||||
import {LinkSuggest} from "../helpers/LinkSuggest";
|
||||
import type {Context} from "../Context.svelte.js";
|
||||
import {delink, getFromRelativePath, isLink} from "../LinkManager";
|
||||
import {NoTaskId} from "../NodePositionsCalculator";
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
SUBTOOLBAR_PADDING
|
||||
} from "../Constants";
|
||||
import {quintOut} from 'svelte/easing';
|
||||
import {slideCustom} from '../Custom';
|
||||
import {slideCustom} from '../helpers/svelte';
|
||||
import type {Context} from "../Context.svelte.js";
|
||||
import {
|
||||
IconCode, StatusCode, type TaskId, toIconCode
|
||||
|
|
|
|||
56
src/helpers/FolderSuggest.ts
Normal file
56
src/helpers/FolderSuggest.ts
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
import {
|
||||
AbstractInputSuggest,
|
||||
App,
|
||||
prepareFuzzySearch,
|
||||
TFolder,
|
||||
} from "obsidian";
|
||||
|
||||
export class FolderSuggest extends AbstractInputSuggest<TFolder> {
|
||||
textInputEl: HTMLInputElement;
|
||||
|
||||
constructor(app: App, textInputEl: HTMLInputElement) {
|
||||
// Cast the textarea to HTMLInputElement to satisfy TypeScript.
|
||||
// This is a dirty hack, but runtime behavior is compatible
|
||||
super(app, textInputEl as unknown as HTMLInputElement);
|
||||
this.textInputEl = textInputEl;
|
||||
}
|
||||
|
||||
getSuggestions(): TFolder[] {
|
||||
const query = this.textInputEl.value;
|
||||
|
||||
// Perform the search
|
||||
const search = prepareFuzzySearch(query);
|
||||
|
||||
return this.app.vault
|
||||
.getAllFolders()
|
||||
.filter((file) => search(file.path))
|
||||
.sort((a, b) => {
|
||||
const resA = search(a.path);
|
||||
const resB = search(b.path);
|
||||
return (resB?.score || 0) - (resA?.score || 0);
|
||||
})
|
||||
.slice(0, 10);
|
||||
}
|
||||
|
||||
renderSuggestion(file: TFolder, el: HTMLElement) {
|
||||
el.createEl("div", { text: file.path });
|
||||
el.createEl("small", { text: file.path, cls: "text-muted" });
|
||||
}
|
||||
|
||||
selectSuggestion(file: TFolder) {
|
||||
const newLinkText = file.path;
|
||||
|
||||
this.textInputEl.value = newLinkText;
|
||||
|
||||
// Trigger Svelte update
|
||||
this.textInputEl.dispatchEvent(new Event("input"));
|
||||
|
||||
// Reset cursor
|
||||
const newCursor = newLinkText.length;
|
||||
this.textInputEl.setSelectionRange(newCursor, newCursor);
|
||||
|
||||
this.textInputEl.focus();
|
||||
this.textInputEl.blur();
|
||||
this.close();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
import { App, TFile, AbstractInputSuggest, prepareFuzzySearch } from "obsidian";
|
||||
import { AbstractInputSuggest, App, prepareFuzzySearch, TFile } from "obsidian";
|
||||
|
||||
export class LinkSuggest extends AbstractInputSuggest<TFile> {
|
||||
textInputEl: HTMLTextAreaElement;
|
||||
|
|
@ -10,7 +10,7 @@ export class LinkSuggest extends AbstractInputSuggest<TFile> {
|
|||
this.textInputEl = textInputEl;
|
||||
}
|
||||
|
||||
getSuggestions(query: string): TFile[] {
|
||||
getSuggestions(_query: string): TFile[] {
|
||||
const cursor = this.textInputEl.selectionStart;
|
||||
const text = this.textInputEl.value;
|
||||
|
||||
|
|
@ -31,9 +31,9 @@ export class LinkSuggest extends AbstractInputSuggest<TFile> {
|
|||
|
||||
// Perform the search
|
||||
const search = prepareFuzzySearch(linkQuery);
|
||||
const files = this.app.vault.getFiles();
|
||||
|
||||
return files
|
||||
return this.app.vault
|
||||
.getFiles()
|
||||
.filter((file) => search(file.path) || search(file.basename))
|
||||
.sort((a, b) => {
|
||||
const resA = search(a.path);
|
||||
11
src/main.ts
11
src/main.ts
|
|
@ -1,18 +1,15 @@
|
|||
import { addIcon, Plugin } from "obsidian";
|
||||
import { TASKMAP_VIEW_TYPE, TaskmapView } from "./TaskmapView";
|
||||
import {
|
||||
DEFAULT_SETTINGS,
|
||||
type TaskmapPluginSettings,
|
||||
} from "./TaskmapPluginSettings";
|
||||
import { DEFAULT_SETTINGS, type TaskmapSettings } from "./TaskmapSettings";
|
||||
import { TaskmapSettingTab } from "./TaskmapSettingTab";
|
||||
import { DEFAULT_DATA } from "./data/ProjectData.svelte";
|
||||
import { LOGO_CONTENT, LOGO_NAME } from "./IconService";
|
||||
import { FileWatcherWithCache } from "./FileWatcherWithCache";
|
||||
import { LOGO_CONTENT, LOGO_NAME } from "./Constants";
|
||||
|
||||
export const FILE_EXTENSION = "taskmap";
|
||||
|
||||
export default class TaskmapPlugin extends Plugin {
|
||||
settings: TaskmapPluginSettings;
|
||||
settings: TaskmapSettings;
|
||||
private readonly filewatcher = new FileWatcherWithCache();
|
||||
|
||||
async onload() {
|
||||
|
|
@ -59,7 +56,7 @@ export default class TaskmapPlugin extends Plugin {
|
|||
{},
|
||||
DEFAULT_SETTINGS,
|
||||
await this.loadData(),
|
||||
) as TaskmapPluginSettings;
|
||||
) as TaskmapSettings;
|
||||
}
|
||||
|
||||
async saveSettings() {
|
||||
|
|
|
|||
Loading…
Reference in a new issue