diff --git a/Models/ProjectRule.ts b/Models/ProjectRule.ts new file mode 100644 index 0000000..7486a56 --- /dev/null +++ b/Models/ProjectRule.ts @@ -0,0 +1,31 @@ +import { MovingRule } from "./MovingRule"; + +/** + * Project rules for defining how files should be moved inside project folders + */ +export class ProjectRule { + /** + * The name of the project this rule belongs to + * e.g. "Project A" + * e.g. "Book collection" + * e.g. "Music albums 2025" + */ + public projectName: string; + /** + * Project destination folder + * e.g. "Projects/Project A" + * e.g. "Projects/Project B/ + */ + public folder: string; + /** + * Rules for moving files inside the project folder + */ + public rules: Array; + public collapsed: boolean; + constructor(projectName?: string, folder?: string, rules?: Array, collapsed?: boolean) { + this.projectName = projectName || ""; + this.folder = folder || ""; + this.rules = rules || []; + this.collapsed = collapsed || false; + } +} diff --git a/README.md b/README.md index 6e332c2..ad0696a 100644 --- a/README.md +++ b/README.md @@ -206,3 +206,9 @@ Thank you! - [ ] Add undo button to the notification popup for the moved files +- [x] Add collapse/expand all rules button +- [x] Add Project moving rules + - [x] Project name and destination path + - [x] Subfield that contain the moving rules for the project +- [ ] Add project rules UI +- [ ] Project rules business logic diff --git a/Settings/ProjectSection.ts b/Settings/ProjectSection.ts new file mode 100644 index 0000000..b882c01 --- /dev/null +++ b/Settings/ProjectSection.ts @@ -0,0 +1,84 @@ +import { MovingRule } from "Models/MovingRule"; +import * as obsidian from "obsidian"; +import type AutoMoverPlugin from "main"; +import { ProjectRule } from "Models/ProjectRule"; + +export function projectSection(containerEl: HTMLElement, plugin: AutoMoverPlugin, display: () => void) { + /** + * Header for excluded folders + */ + const projectRuleContainer = containerEl.createDiv({ + cls: "moving_rules_container", + }); + + // Class used from obdsidian's css for consistency + const projectRuleDetails = projectRuleContainer.createEl("details", {}); + projectRuleDetails.createEl("summary", { text: "Project rules", cls: ["setting-item-heading"] }); + + projectRuleDetails.open = !plugin.settings.collapseSections.projectRules; + projectRuleDetails.addEventListener("toggle", async () => { + plugin.settings.collapseSections.projectRules = !projectRuleDetails.open; + await plugin.saveData(plugin.settings); + }); + + const projectList = projectRuleDetails.createDiv({ + cls: "rule_list", + }); + const projectHeader = projectList.createDiv({ + cls: "rule margig_right", + }); + projectHeader.createEl("p", { + text: "Project search criteria (string or regex)", + cls: "rule_title", + }); + + const addProjectButton = projectHeader.createEl("button", { + text: "+", + cls: "rule_button", + }); + addProjectButton.addEventListener("click", () => { + plugin.settings.projectRules.push(new ProjectRule()); + display(); + }); + + /** + * List of project rules + */ + for (const project of plugin.settings.projectRules) { + const child = projectList.createDiv({ cls: "rule" }); + child.createEl("input", { + value: project.projectName, + cls: "rule_input", + }).onchange = (e) => { + project.projectName = (e.target as HTMLInputElement).value; + plugin.settings.projectRules.map((r) => (r === project ? project : r)); + plugin.saveData(plugin.settings); + }; + child.createEl("input", { + value: project.folder, + cls: "rule_input", + }).onchange = (e) => { + project.folder = (e.target as HTMLInputElement).value; + plugin.settings.projectRules.map((r) => (r === project ? project : r)); + plugin.saveData(plugin.settings); + }; + + const duplicateRuleButton = child.createEl("button", { + text: "⿻", + cls: "rule_button rule_button_duplicate", + }); + duplicateRuleButton.addEventListener("click", () => { + plugin.settings.projectRules.push(new ProjectRule(project.projectName, project.folder)); + display(); + }); + + const deleteRuleButton = child.createEl("button", { + text: "x", + cls: "rule_button rule_button_remove", + }); + deleteRuleButton.addEventListener("click", () => { + plugin.settings.projectRules = plugin.settings.projectRules.filter((r) => r !== project); + display(); + }); + } +} diff --git a/Settings/Settings.ts b/Settings/Settings.ts index 0d30fe7..07f3915 100644 --- a/Settings/Settings.ts +++ b/Settings/Settings.ts @@ -1,6 +1,7 @@ import type AutoMoverPlugin from "main"; import type { ExclusionRule } from "Models/ExclusionRule"; import type { MovingRule } from "Models/MovingRule"; +import { ProjectRule } from "Models/ProjectRule"; export interface AutoMoverSettings { moveOnOpen: boolean; @@ -8,6 +9,7 @@ export interface AutoMoverSettings { movingRules: MovingRule[]; exclusionRules: ExclusionRule[]; tagRules: MovingRule[]; + projectRules: ProjectRule[]; automaticMoving: boolean; timer: number | null; // in miliseconds collapseSections: { @@ -15,6 +17,7 @@ export interface AutoMoverSettings { movingRules: boolean; exclusionRules: boolean; tagRules: boolean; + projectRules: boolean; }; } @@ -24,6 +27,7 @@ export const DEFAULT_SETTINGS: Partial = { movingRules: [], exclusionRules: [], tagRules: [], + projectRules: [], automaticMoving: false, timer: null, collapseSections: { @@ -31,6 +35,7 @@ export const DEFAULT_SETTINGS: Partial = { movingRules: false, exclusionRules: false, tagRules: false, + projectRules: false, }, }; diff --git a/Settings/SettingsTab.ts b/Settings/SettingsTab.ts index bf8f319..a2f6439 100644 --- a/Settings/SettingsTab.ts +++ b/Settings/SettingsTab.ts @@ -6,6 +6,7 @@ import { exclusionSection } from "./ExclusionSection"; import movingRuleSection from "./MovingRuleSection"; import { tagSection } from "./TagSection"; import { groupCollapsed } from "console"; +import { projectSection } from "./ProjectSection"; export class SettingsTab extends PluginSettingTab { plugin: AutoMoverPlugin; @@ -159,5 +160,6 @@ export class SettingsTab extends PluginSettingTab { movingRuleSection(containerEl, this.plugin, this.display); tagSection(containerEl, this.plugin, this.display); exclusionSection(containerEl, this.plugin, this.display); + projectSection(containerEl, this.plugin, this.display); }; }