Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 | 1x 1x 1x 1x 1x 1x 9x 9x 9x 9x 9x 5x 5x 5x 5x 5x 5x 4x 4x 1x 21x 5x 5x 16x 21x 6x 6x 21x 3x 3x 7x 7x 10x 10x 10x 1x 1x 10x 2x 2x 10x 7x 7x 10x 10x | import type { App, Vault } from "obsidian";
import type { LilbeeClient } from "../api";
import type { Source } from "../types";
import { CONTENT_TYPE, isPdfContentType } from "../types";
import { SourcePreviewModal } from "../views/source-preview-modal";
/** Discriminator tags for `SourceClickAction`. */
export const SOURCE_ACTION = {
VAULT_MARKDOWN: "vault-markdown",
VAULT_NOTE: "vault-note",
PREVIEW: "preview",
} as const;
/**
* The resolved intent of clicking a Source chip or card. One of:
* - `vault-markdown`: open the markdown file and scroll to a specific line.
* - `vault-note`: open the vault file without deep-linking.
* - `preview`: file is not in the vault, OR is a PDF — fetch via `/api/source`
* and show the source-preview modal so we can deep-link to a page via
* `<object data="...?page=N">` (Obsidian's PDF viewer doesn't honour the
* `#page=N` fragment in `openLinkText`).
*/
export type SourceClickAction =
| { kind: typeof SOURCE_ACTION.VAULT_MARKDOWN; path: string; line: number }
| { kind: typeof SOURCE_ACTION.VAULT_NOTE; path: string }
| { kind: typeof SOURCE_ACTION.PREVIEW; source: Source };
function isMarkdownish(contentType: string): boolean {
return contentType === CONTENT_TYPE.MARKDOWN || contentType === CONTENT_TYPE.HTML;
}
function vaultAction(source: Source, path: string): SourceClickAction {
if (isMarkdownish(source.content_type) && source.line_start !== null) {
return {
kind: SOURCE_ACTION.VAULT_MARKDOWN,
path,
line: source.line_start,
};
}
return { kind: SOURCE_ACTION.VAULT_NOTE, path };
}
/**
* Resolve what should happen when the user clicks a source reference.
*
* PDFs always route to the preview modal — Obsidian's built-in PDF viewer
* does not honour `#page=N` fragments passed through `openLinkText`, so we
* use the modal's `<object data="…?page=N">` path that does. The modal
* exposes an "Open in vault" button for users who want the file opened in
* the main pane.
*
* For non-PDFs, prefer the server-supplied `vault_path`. If absent (older
* server builds, or external-server mode), fall back to `source.source` —
* sources ingested via a vault-native flow often match a vault-relative
* path directly. Only fall through to the preview modal when no vault file
* can be resolved.
*/
export function sourceClickAction(source: Source, vault: Vault): SourceClickAction {
if (isPdfContentType(source.content_type)) {
return { kind: SOURCE_ACTION.PREVIEW, source };
}
const vaultPath = source.vault_path;
if (vaultPath && vault.getAbstractFileByPath(vaultPath)) {
return vaultAction(source, vaultPath);
}
if (source.source && vault.getAbstractFileByPath(source.source)) {
return vaultAction(source, source.source);
}
return { kind: SOURCE_ACTION.PREVIEW, source };
}
/**
* Dispatch a resolved `SourceClickAction`. Opens the vault file with the
* appropriate deep-link for markdown, or opens the preview modal for PDFs
* and sources that only live on the server.
*/
export async function executeSourceClick(app: App, api: LilbeeClient, action: SourceClickAction): Promise<void> {
switch (action.kind) {
case SOURCE_ACTION.VAULT_MARKDOWN:
app.workspace.openLinkText(action.path, "", false, { eState: { line: action.line } });
return;
case SOURCE_ACTION.VAULT_NOTE:
app.workspace.openLinkText(action.path, "");
return;
case SOURCE_ACTION.PREVIEW:
new SourcePreviewModal(app, api, action.source).open();
return;
}
}
|