diff --git a/CHANGELOG.md b/CHANGELOG.md index cd17ca3..368450e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,15 @@ All notable changes to O-Tie are documented here. +## [1.0.13] — 2026-06-28 + +### Fixed + +- **Mobile inspector dismiss** — Tapping empty canvas on phone or tablet now closes the inspector bar, matching desktop click-away behaviour. +- **Inspector action labels** — + Stack row, + Safeguard, + Barrier, and related buttons use capitalised labels consistent with the toolbar. + +--- + ## [1.0.12] — 2026-06-27 ### Fixed diff --git a/manifest.json b/manifest.json index 0f97607..2e1fa5f 100644 --- a/manifest.json +++ b/manifest.json @@ -1,7 +1,7 @@ { "id": "o-tie", "name": "O-Tie", - "version": "1.0.12", + "version": "1.0.13", "minAppVersion": "1.4.0", "description": "Build risk bowtie diagrams in your vault: threats, prevention and mitigation barriers, escalation factors, barrier analysis stacks, and PNG export.", "author": "Andre482", diff --git a/package.json b/package.json index e5fe013..35ccf2f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "o-tie", - "version": "1.0.12", + "version": "1.0.13", "description": "Obsidian plugin for building risk bowtie diagrams", "main": "main.js", "scripts": { diff --git a/src/bowtieView.ts b/src/bowtieView.ts index 9513fa1..189bde0 100644 --- a/src/bowtieView.ts +++ b/src/bowtieView.ts @@ -436,6 +436,20 @@ export class BowtieView extends TextFileView { return btn; } + private createInspectorBtn( + parent: HTMLElement, + label: string, + action: (e: MouseEvent) => void, + opts: { primary?: boolean; warning?: boolean } = {} + ): HTMLButtonElement { + const cls = ["mod-small"]; + if (opts.primary) cls.push("mod-cta"); + if (opts.warning) cls.push("mod-warning"); + const btn = parent.createEl("button", { cls: cls.join(" "), text: label }); + btn.addEventListener("click", action); + return btn; + } + private renderInspector(): void { this.inspectorEl.empty(); if (!this.selectedRef) { @@ -493,23 +507,20 @@ export class BowtieView extends TextFileView { this.selectedRef.kind === "mitigationBarrier" || this.selectedRef.kind === "transitionBarrier" ) { - const stackBtn = actions.createEl("button", { text: "+ stack row", cls: "mod-small" }); - stackBtn.addEventListener("click", (e) => { - const rect = stackBtn.getBoundingClientRect(); + this.createInspectorBtn(actions, "+ Stack row", (e) => { + const rect = (e.currentTarget as HTMLElement).getBoundingClientRect(); this.showAddStackRowMenu( { clientX: rect.left, clientY: rect.bottom } as MouseEvent, this.selectedRef! ); }); - const degBtn = actions.createEl("button", { text: "⚡ Degradation factor", cls: "mod-small" }); - degBtn.addEventListener("click", () => { + this.createInspectorBtn(actions, "⚡ Degradation factor", () => { this.addDegradationFactor(this.selectedRef!); }); } if (this.selectedRef.kind === "degradationFactor") { - const sgBtn = actions.createEl("button", { text: "+ safeguard", cls: "mod-small" }); - sgBtn.addEventListener("click", () => { + this.createInspectorBtn(actions, "+ Safeguard", () => { this.addSafeguard(this.selectedRef!); }); } @@ -517,34 +528,47 @@ export class BowtieView extends TextFileView { if (this.selectedRef.kind === "topEvent" && this.selectedRef.eventId) { const eventIndex = this.bowtie.events.findIndex((e) => e.id === this.selectedRef!.eventId); if (eventIndex >= 0 && eventIndex < this.bowtie.events.length - 1) { - const barBtn = actions.createEl("button", { - text: "+ barrier to next event", - cls: "mod-cta mod-small", - }); - barBtn.addEventListener("click", () => { - this.addTransitionBarrier(this.selectedRef!.eventId!); - }); + this.createInspectorBtn( + actions, + "+ Barrier to next event", + () => { + this.addTransitionBarrier(this.selectedRef!.eventId!); + }, + { primary: true } + ); } } if (this.selectedRef.kind === "threat") { - const barBtn = actions.createEl("button", { text: "+ prevention barrier", cls: "mod-cta mod-small" }); - barBtn.addEventListener("click", () => { - this.addPreventionBarrier(this.selectedRef!.threatId!); - }); + this.createInspectorBtn( + actions, + "+ Prevention Barrier", + () => { + this.addPreventionBarrier(this.selectedRef!.threatId!); + }, + { primary: true } + ); } if (this.selectedRef.kind === "consequence") { - const barBtn = actions.createEl("button", { text: "+ mitigation barrier", cls: "mod-cta mod-small" }); - barBtn.addEventListener("click", () => { - this.addMitigationBarrier(this.selectedRef!.consequenceId!); - }); + this.createInspectorBtn( + actions, + "+ Mitigation Barrier", + () => { + this.addMitigationBarrier(this.selectedRef!.consequenceId!); + }, + { primary: true } + ); } - const delBtn = actions.createEl("button", { text: "Delete", cls: "mod-warning mod-small" }); - delBtn.addEventListener("click", () => { - this.deleteNode(this.selectedRef!); - }); + this.createInspectorBtn( + actions, + "Delete", + () => { + this.deleteNode(this.selectedRef!); + }, + { warning: true } + ); } private fitInspectorTextArea(textarea: HTMLTextAreaElement): void { @@ -1442,11 +1466,17 @@ export class BowtieView extends TextFileView { } if (e.pointerId === this.panPointerId) { + const tappedEmptyCanvas = !this.gestureMoved && !this.panStartedOnNode; if (this.gestureMoved && this.panStartedOnNode) { this.suppressNextClick = true; } this.panStartedOnNode = false; this.endPan(); + // Touch taps on empty canvas call preventDefault on pointerdown, so no click + // event fires to clear selection — dismiss the inspector on tap-up instead. + if (tappedEmptyCanvas) { + this.clearSelection(); + } } if (this.activePointers.size === 1) { diff --git a/versions.json b/versions.json index 26a5bbc..23faa24 100644 --- a/versions.json +++ b/versions.json @@ -11,5 +11,6 @@ "1.0.9": "1.4.0", "1.0.10": "1.4.0", "1.0.11": "1.4.0", - "1.0.12": "1.4.0" + "1.0.12": "1.4.0", + "1.0.13": "1.4.0" } \ No newline at end of file