Files
contexter/src/ui.ts
2026-05-23 00:42:25 +02:00

86 lines
2.6 KiB
TypeScript

import { App, Menu, Platform, TFile, View, WorkspaceLeaf, normalizePath } from "obsidian";
export function menu(
ev: MouseEvent,
items: Array<{ title: string; icon?: string; onClick: () => void }>,
): void {
const m = new Menu();
for (const it of items) {
m.addItem((i) => {
i.setTitle(it.title);
if (it.icon) i.setIcon(it.icon);
i.onClick(it.onClick);
});
}
m.showAtMouseEvent(ev);
}
export async function openMarkdown(
app: App,
path: string,
leaf?: WorkspaceLeaf,
): Promise<void> {
const p = normalizePath(path);
const f = app.vault.getAbstractFileByPath(p);
if (!(f instanceof TFile)) return;
if (Platform.isMobile) {
const target = leaf ?? app.workspace.getLeaf(false);
await target.openFile(f);
return;
}
const existing = app.workspace.getLeavesOfType("markdown");
if (existing.length > 0) {
const target = existing[existing.length - 1];
await target.openFile(f);
app.workspace.revealLeaf(target);
} else {
const target = app.workspace.getLeaf("split", "vertical");
await target.openFile(f);
}
}
export interface BreadcrumbSegment {
label: string;
onClick?: () => void;
}
function renderBreadcrumbInto(wrap: HTMLElement, segments: BreadcrumbSegment[]): void {
segments.forEach((seg, i) => {
if (i > 0) wrap.createSpan({ cls: "pk-breadcrumb-sep", text: " > " });
if (seg.onClick) {
const a = wrap.createSpan({ cls: "pk-breadcrumb-link", text: seg.label });
a.addEventListener("click", seg.onClick);
} else {
wrap.createSpan({ cls: "pk-breadcrumb-current", text: seg.label });
}
});
}
export function breadcrumb(parent: HTMLElement, segments: BreadcrumbSegment[]): HTMLElement {
const wrap = parent.createDiv({ cls: "pk-breadcrumb" });
renderBreadcrumbInto(wrap, segments);
return wrap;
}
export function injectMobileBreadcrumb(
view: View & { contentEl?: HTMLElement },
segments: BreadcrumbSegment[],
): void {
const root = view.contentEl ?? view.containerEl.querySelector(".view-content");
if (!root) return;
root.querySelectorAll(".pk-mobile-breadcrumb").forEach((el) => el.remove());
if (segments.length === 0) return;
const target =
root.querySelector<HTMLElement>(".markdown-source-view .cm-sizer") ??
root.querySelector<HTMLElement>(".markdown-reading-view .markdown-preview-sizer");
if (!target) return;
const wrap = document.createElement("div");
wrap.className = "pk-breadcrumb pk-mobile-breadcrumb";
target.prepend(wrap);
renderBreadcrumbInto(wrap, segments);
}
export function emptyState(parent: HTMLElement, text: string): HTMLElement {
return parent.createDiv({ cls: "pk-empty", text });
}