text highlight and og image
This commit is contained in:
@@ -0,0 +1,199 @@
|
||||
// ---------------------------------------------------------------------------
|
||||
// Source-reference helpers (browser-only)
|
||||
//
|
||||
// These functions access `window` and `document` and therefore can only run in
|
||||
// the browser. They are intentionally NOT marked "use client" because they are
|
||||
// plain utility functions, not React components or hooks. Any React component
|
||||
// that calls them must itself be a client component.
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
import { BOOK_NAMES, CC_LILAS } from "@/lib/constants";
|
||||
import { buildHighlightUrl } from "@/lib/text-highlight";
|
||||
|
||||
/**
|
||||
* Parse the current page URL into a human-readable source reference.
|
||||
* Returns { title, detail, url } or null if on a non-content page.
|
||||
*/
|
||||
export function getSourceReference(): {
|
||||
title: string;
|
||||
detail: string | null;
|
||||
url: string;
|
||||
} | null {
|
||||
const url = window.location.href;
|
||||
const path = window.location.pathname;
|
||||
const parts = path.split("/").filter(Boolean);
|
||||
|
||||
// /books/bg/1/1 → Bhagavad-gītā As It Is, Chapter 1, Verse 1
|
||||
if (parts[0] === "books" && parts.length >= 2) {
|
||||
const code = parts[1];
|
||||
const bookName = BOOK_NAMES[code] || code.toUpperCase();
|
||||
|
||||
// Verse-based: /books/bg/[chapter]/[verse]
|
||||
if (code === "bg" && parts.length >= 4) {
|
||||
return {
|
||||
title: bookName,
|
||||
detail: `Chapter ${parts[2]}, Verse ${parts[3]}`,
|
||||
url,
|
||||
};
|
||||
}
|
||||
// SB: /books/sb/[canto]/[chapter]/[verse]
|
||||
if (code === "sb" && parts.length >= 5) {
|
||||
return {
|
||||
title: bookName,
|
||||
detail: `Canto ${parts[2]}, Chapter ${parts[3]}, Verse ${parts[4]}`,
|
||||
url,
|
||||
};
|
||||
}
|
||||
// CC: /books/cc/[lila]/[chapter]/[verse]
|
||||
if (code === "cc" && parts.length >= 5) {
|
||||
const lila = CC_LILAS[parts[2]] || parts[2];
|
||||
return {
|
||||
title: bookName,
|
||||
detail: `${lila}, Chapter ${parts[3]}, Verse ${parts[4]}`,
|
||||
url,
|
||||
};
|
||||
}
|
||||
// CC lila index: /books/cc/[lila]
|
||||
if (code === "cc" && parts.length === 3) {
|
||||
const lila = CC_LILAS[parts[2]] || parts[2];
|
||||
return { title: bookName, detail: lila, url };
|
||||
}
|
||||
// SB1962: /books/sb1962/[chapter]/[verse]
|
||||
if (code === "sb1962" && parts.length >= 4) {
|
||||
return {
|
||||
title: bookName,
|
||||
detail: `Chapter ${parts[2]}, Verse ${parts[3]}`,
|
||||
url,
|
||||
};
|
||||
}
|
||||
// ISO/NOI: /books/iso/[mantra]
|
||||
if ((code === "iso" || code === "noi") && parts.length >= 3) {
|
||||
const num = parts[2];
|
||||
const label = code === "iso" ? "Mantra" : "Text";
|
||||
return { title: bookName, detail: `${label} ${num}`, url };
|
||||
}
|
||||
// BS/MM/NBS: /books/{code}/[chapter]/[verse]
|
||||
if (
|
||||
(code === "bs" || code === "mm" || code === "nbs") &&
|
||||
parts.length >= 4
|
||||
) {
|
||||
return {
|
||||
title: bookName,
|
||||
detail: `Chapter ${parts[2]}, Verse ${parts[3]}`,
|
||||
url,
|
||||
};
|
||||
}
|
||||
// KB: /books/kb/[volume]/[slug]
|
||||
if (code === "kb" && parts.length >= 4) {
|
||||
return {
|
||||
title: bookName,
|
||||
detail: `Volume ${parts[2]}, Chapter ${parts[3]}`,
|
||||
url,
|
||||
};
|
||||
}
|
||||
// Generic prose: /books/{code}/[chapter]
|
||||
if (parts.length >= 3) {
|
||||
const chSlug = parts[2];
|
||||
const chNum = parseInt(chSlug, 10);
|
||||
const detail = isNaN(chNum)
|
||||
? chSlug.replace(/-/g, " ")
|
||||
: `Chapter ${chNum}`;
|
||||
return { title: bookName, detail, url };
|
||||
}
|
||||
// Book index page
|
||||
return { title: bookName, detail: null, url };
|
||||
}
|
||||
|
||||
// /letters/[slug]
|
||||
if (
|
||||
parts[0] === "letters" &&
|
||||
parts.length === 2 &&
|
||||
parts[1] !== "year" &&
|
||||
parts[1] !== "recipient" &&
|
||||
parts[1] !== "location"
|
||||
) {
|
||||
// h1 contains "Letter to Mukunda" — use it as the title
|
||||
const h1 = document.querySelector("h1");
|
||||
const title = h1?.textContent?.trim() || "Letter";
|
||||
|
||||
// The <p> sibling after h1 contains "15 January, 1968 · Calcutta"
|
||||
const metaP = document.querySelector(
|
||||
"header p.text-muted-foreground, header p[class*='muted']",
|
||||
);
|
||||
const meta = metaP?.textContent?.trim() || null;
|
||||
|
||||
return { title, detail: meta, url };
|
||||
}
|
||||
|
||||
// /essays/[slug]
|
||||
if (parts[0] === "essays" && parts.length === 2) {
|
||||
const h1 = document.querySelector("h1");
|
||||
const title = h1?.textContent?.trim() || parts[1].replace(/-/g, " ");
|
||||
return { title, detail: "Essay by Śrīla Prabhupāda", url };
|
||||
}
|
||||
|
||||
// /journals/[slug]/[chapter]
|
||||
if (parts[0] === "journals" && parts.length >= 3) {
|
||||
const backLink = document.querySelector("header a[href^='/journals/']");
|
||||
const parentTitle =
|
||||
backLink?.textContent?.replace(/^←\s*/, "").trim() || "Journal";
|
||||
const h1 = document.querySelector("h1");
|
||||
const chapterTitle = h1?.textContent?.trim() || null;
|
||||
return { title: parentTitle, detail: chapterTitle, url };
|
||||
}
|
||||
|
||||
// /magazines/[slug]/[issue]
|
||||
if (parts[0] === "magazines" && parts.length >= 3) {
|
||||
const backLink = document.querySelector("header a[href^='/magazines/']");
|
||||
const parentTitle =
|
||||
backLink?.textContent?.replace(/^←\s*/, "").trim() || "Magazine";
|
||||
const h1 = document.querySelector("h1");
|
||||
const issueTitle = h1?.textContent?.trim() || null;
|
||||
return { title: parentTitle, detail: issueTitle, url };
|
||||
}
|
||||
|
||||
// /other-documents/[slug]/[chapter]
|
||||
if (parts[0] === "other-documents" && parts.length >= 3) {
|
||||
const backLink = document.querySelector(
|
||||
"header a[href^='/other-documents/']",
|
||||
);
|
||||
const parentTitle =
|
||||
backLink?.textContent?.replace(/^←\s*/, "").trim() || "Document";
|
||||
const h1 = document.querySelector("h1");
|
||||
const chapterTitle = h1?.textContent?.trim() || null;
|
||||
return { title: parentTitle, detail: chapterTitle, url };
|
||||
}
|
||||
|
||||
// /glossary — general
|
||||
if (parts[0] === "glossary") {
|
||||
return { title: "Glossary", detail: null, url };
|
||||
}
|
||||
|
||||
// Fallback: try the h1
|
||||
const h1 = document.querySelector("h1");
|
||||
if (h1) {
|
||||
return {
|
||||
title: h1.textContent?.trim() || "Prabhupāda Says",
|
||||
detail: null,
|
||||
url,
|
||||
};
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Format selected text with source attribution appended.
|
||||
*/
|
||||
export function formatCopyText(selectedText: string): string {
|
||||
const ref = getSourceReference();
|
||||
if (!ref) return selectedText;
|
||||
|
||||
const highlightUrl = buildHighlightUrl(selectedText);
|
||||
|
||||
let source = `\n\nSource:\n${ref.title}`;
|
||||
if (ref.detail) source += `\n${ref.detail}`;
|
||||
source += `\n${highlightUrl}`;
|
||||
|
||||
return selectedText + source;
|
||||
}
|
||||
Reference in New Issue
Block a user