diff --git a/css.d.ts b/css.d.ts new file mode 100644 index 0000000..31f07ea --- /dev/null +++ b/css.d.ts @@ -0,0 +1,4 @@ +declare module '*.css' { + const content: string; + export default content; +} diff --git a/esbuild.config.mjs b/esbuild.config.mjs index 6652498..b00a9e7 100644 --- a/esbuild.config.mjs +++ b/esbuild.config.mjs @@ -14,6 +14,7 @@ async function runBuild() { format: 'cjs', target: 'es2018', external: ['obsidian', '@codemirror/view', '@codemirror/state'], + loader: { '.css': 'text' }, outdir: '.', }; diff --git a/package.json b/package.json index e647d81..6ed15e7 100644 --- a/package.json +++ b/package.json @@ -1,15 +1,15 @@ { - "name": "obsidian-verse-plugin", + "name": "obsidian-wol-reference-viewer", "version": "1.0.0", - "description": "An Obsidian plugin that fetches and displays Bible verses from IAM Research Suite API", + "description": "An Obsidian plugin that looks up Bible verses and WOL research articles inline in your notes using !!reference!! syntax.", "main": "main.js", "scripts": { "dev": "node esbuild.config.mjs", "build": "tsc -noEmit -skipLibCheck && node esbuild.config.mjs production", "version": "node version-bump.mjs && git add manifest.json versions.json" }, - "keywords": ["obsidian", "bible", "verses", "research"], - "author": "Your Name", + "keywords": ["obsidian", "bible", "verses", "wol", "jw"], + "author": "@iaremarkus", "license": "MIT", "devDependencies": { "@types/node": "^16.11.6", @@ -21,4 +21,4 @@ "tslib": "2.4.0", "typescript": "^5.0.0" } -} \ No newline at end of file +} diff --git a/reference-stylist.ts b/reference-stylist.ts new file mode 100644 index 0000000..4d36447 --- /dev/null +++ b/reference-stylist.ts @@ -0,0 +1,66 @@ +// reference-stylist.ts + +/** + * Parses verse numbers from a user-provided reference string. + * Examples: "John 3:16" -> [16], "Romans 13:8-10" -> [8, 9, 10], "Ps 119:24,25" -> [24, 25] + */ +function parseReferenceNumbers(ref: string): number[] { + const refNumbers: number[] = []; + + const refPartMatch = ref.match(/:(.+)$/); + const refPart = refPartMatch ? refPartMatch[1] : ref; + + for (const segment of refPart.split(',')) { + const parts = segment.trim().match(/^(\d+)(?:-(\d+))?$/); + if (parts) { + const start = parseInt(parts[1], 10); + refNumbers.push(start); + if (parts[2]) { + const end = parseInt(parts[2], 10); + for (let i = start + 1; i <= end; i++) { + refNumbers.push(i); + } + } + } + } + + return refNumbers; +} + +/** + * Renders reference text into a container element, wrapping inline verse numbers + * (e.g. the leading "16" in "16 For God loved the world…") with styled spans. + * + * IMPORTANT: pass the original user-provided reference (e.g. "Romans 13:8-10"), + * NOT the `reference` field from the API response (which is the WOL page title). + */ +export function renderReferenceText(container: HTMLElement, text: string, ref: string): void { + const numbers = parseReferenceNumbers(ref); + + if (numbers.length === 0) { + container.appendText(text); + return; + } + + // Sort descending so "10" is matched before "1" + numbers.sort((a, b) => b - a); + + // Use digit lookahead/lookbehind instead of \b for reliable boundary matching + const pattern = numbers.map(n => `(? lastIndex) { + container.appendText(text.slice(lastIndex, match.index)); + } + container.createSpan({ cls: 'ref-number', text: match[0] }); + lastIndex = match.index + match[0].length; + } + + if (lastIndex < text.length) { + container.appendText(text.slice(lastIndex)); + } +} diff --git a/styles.css b/styles.css index 66f807b..5177761 100644 --- a/styles.css +++ b/styles.css @@ -1,173 +1,305 @@ -.verse-reference { - text-decoration: underline; - cursor: pointer; - color: #e6db74; - border-bottom: none; +.wol-ref-link { + color: var(--color-accent); + cursor: pointer; + display: inline-block; } -.verse-reference:hover { - opacity: 0.8; +.wol-ref-link::before { + content: " 📖 "; +} + +.wol-ref-link:hover { + opacity: 0.8; } /* New style for custom verlink class */ .verlink { - color: var(--text-accent); /* Use Obsidian's accent color */ - text-decoration: none; - font-weight: bold; + color: var(--text-accent); + text-decoration: none; + font-weight: bold; } .verlink:hover { - text-decoration: underline; + text-decoration: underline; } - -.verse-modal .modal-content { - padding: 20px; - font-family: var(--font-family); +.ref-modal .modal-content { + padding: 20px; + font-family: var(--font-family); } -.verse-modal p { - margin-bottom: 10px; - line-height: 1.8; /* Changed from 1.6 to 1.8 */ +.ref-modal p { + margin-bottom: 10px; + line-height: 1.8; } -.verse-modal p:last-child { - margin-bottom: 0; +.ref-modal p:last-child { + margin-bottom: 0; } -.verse-modal-reference { - font-size: 0.9em; - color: var(--text-muted); - font-style: italic; - margin-top: 15px; - text-align: right; +.ref-modal-reference { + font-size: 0.9em; + color: var(--text-muted); + font-style: italic; + margin-top: 15px; + text-align: right; } -.verse-modal-wol-link { - display: block; - margin-top: 10px; - text-align: right; - color: var(--text-accent); - text-decoration: none; +.ref-modal-wol-link, +.ref-popover-wol-link, +.ref-sidebar-wol-link { + text-decoration: none; + font-size: 80%; + font-weight: 500; + color: var(--color-accent); + display: inline-block; } -.verse-modal-wol-link:hover { - text-decoration: underline; +.ref-modal-wol-link:hover, +.ref-popover-wol-link:hover, +.ref-sidebar-wol-link:hover { + text-decoration: underline; +} + +.ref-modal-button-container button { + font-size: 80%; + font-weight: 600 !important; +} + +.ref-modal-result > li { + list-style: none; +} + +.ref-modal-result ol > li::marker, +.ref-modal-result ul > li::marker { + display: none !important; +} + +.resultItems { + margin: 0 !important; + padding: 0 !important; +} + +.resultItems ::marker { + display: none !important; + opacity: 0 !important; + color: transparent; +} + +.mod-cta { + padding: 8px 10px 10px !important; + line-height: 1 !important; + height: auto !important; } /* Live Preview editor decoration */ -.cm-verse-reference { - font-weight: bold; - color: var(--text-accent); +.cm-wol-ref { + color: var(--color-accent); + opacity: 0.8; + font-weight: 500; + cursor: pointer; +} + +.cm-wol-ref::before { + content: " "; +} + +.cm-wol-ref:hover { + opacity: 1; +} + +/* Inline reference result widget rendered in the editor for !!ref!!> */ +.cm-ref-inline-result, +.ref-callout { + background-color: transparent; + box-shadow: none; +} + +.cm-ref-inline-body, +.ref-callout .callout-content { + background: rgba(0, 0, 0, 0.1); + border: 1px solid var(--background-modifier-border); + padding: 15px; + border-radius: 10px; + font-size: 90%; + box-shadow: none; +} + +.cm-ref-inline-label, +.ref-callout .callout-title { + font-size: 90%; + font-weight: 500; + color: var(--text-normal) !important; + margin-left: 3%; + width: 94%; + background-color: rgba(0, 0, 0, 0.2); + padding: 5px 10px; + border-radius: 10px 10px 0 0; + box-shadow: none; + line-height: inherit; +} + +.ref-callout .callout-title-inner { + font-weight: inherit; +} + +.cm-ref-inline-item, +.ref-callout-result { + display: flex; + flex-direction: column; + gap: 5px; + margin-bottom: 6px; +} + +.cm-ref-inline-item:last-child, +.ref-callout-result:last-child { + margin-bottom: 0; +} + +.cm-ref-inline-item a, +.ref-callout-result a { + color: var(--text-accent); + text-decoration: none; +} + +.cm-ref-inline-item a:hover, +.ref-callout-result a:hover { + text-decoration: underline; +} + +.cm-ref-inline-body p, +.ref-callout .callout-content p { + margin: 0 !important; } /* Add style for popover paragraph text */ -.verse-popover p { - line-height: 1.8; +.ref-popover p { + line-height: 1.8; } -.verse-number { - font-weight: 700; - color: var(--text-accent); - font-size: 0.85em; +.ref-number, +span.v .vl { + font-size: 70%; + font-weight: 600; + opacity: 0.5; + padding: 1px 2px; + position: relative; + top: -1px; + margin: 0 3px; + line-height: 1; + background: rgba(0, 0, 0, 0.3); + border-radius: 3px; + text-decoration: none; +} + +span.v .b { + display: none; } /* Sidebar */ -.verse-sidebar { - padding: 12px; - display: flex; - flex-direction: column; - gap: 0; +.ref-sidebar { + padding: 12px; + display: flex; + flex-direction: column; + gap: 20px; } -.verse-sidebar-empty { - color: var(--text-muted); - font-style: italic; - font-size: var(--font-ui-small); - text-align: center; - margin-top: 24px; +.ref-sidebar-empty { + color: var(--text-muted); + font-style: italic; + font-size: var(--font-ui-small); + text-align: center; + margin-top: 24px; } -.verse-sidebar-item { - padding: 12px 0; - border-bottom: 1px solid var(--background-modifier-border); +.ref-sidebar-item { + padding: 12px 0; } -.verse-sidebar-item:last-child { - border-bottom: none; +.ref-sidebar .ref-sidebar-item:not(:last-of-type) { + border-bottom: 1px dotted rgba(255, 255, 255, 0.2); + padding-bottom: 20px; } -.verse-sidebar-header { - display: flex; - flex-direction: row; - justify-content: space-between; - align-items: center; - margin-bottom: 6px; +.ref-sidebar-header { + display: flex; + flex-direction: row; + width: 100%; + justify-content: space-between; + align-items: center; + margin-bottom: 6px; } -.verse-sidebar-ref { - font-size: var(--font-ui-small); - font-weight: 600; - color: var(--text-accent); +.ref-sidebar-ref { + font-size: 90%; + font-weight: 500; + color: var(--color-accent); + opacity: 0.5; } -.verse-sidebar-wol-icon { - display: flex; - align-items: center; - color: var(--text-muted); - line-height: 1; +.ref-sidebar-wol-icon { + display: flex; + align-items: center; + color: var(--text-muted); + line-height: 1; } -.verse-sidebar-wol-icon:hover { - color: var(--text-accent); +.ref-sidebar-wol-icon:hover { + color: var(--text-accent); } -.verse-sidebar-wol-icon svg { - width: 13px; - height: 13px; +.ref-sidebar-wol-icon svg { + width: 13px; + height: 13px; } -.verse-sidebar-body p { - font-size: var(--font-ui-small); - line-height: 1.7; - color: var(--text-normal); - margin: 0 0 6px 0; +.ref-sidebar-body p { + font-size: var(--font-ui-small); + line-height: 1.7; + color: var(--text-normal); + margin: 0 0 6px 0; } -.verse-sidebar-loading { - color: var(--text-muted); - font-style: italic; +.ref-sidebar-loading { + color: var(--text-muted); + font-style: italic; } -.verse-sidebar-error { - color: var(--text-error); - font-size: var(--font-ui-smaller); +.ref-sidebar-error { + color: var(--text-error); + font-size: var(--font-ui-smaller); } /* WOL search result cards */ -.verse-sidebar-wol-result { - font-size: var(--font-ui-small); - line-height: 1.6; - color: var(--text-normal); - padding: 6px 0; - border-top: 1px solid var(--background-modifier-border); +.ref-sidebar-wol-result { + font-size: var(--font-ui-small); + line-height: 1.6; + color: var(--text-normal); + padding: 6px 0; + border-top: 1px solid var(--background-modifier-border); } -.verse-sidebar-wol-result:first-child { - border-top: none; - padding-top: 0; +.ref-sidebar-wol-result:first-child { + border-top: none; + padding-top: 0; } -.verse-sidebar-wol-result img { - max-width: 100%; - height: auto; +.ref-sidebar-wol-result img { + max-width: 100%; + height: auto; } -.verse-sidebar-wol-result a { - color: var(--text-accent); - text-decoration: none; +.ref-sidebar-wol-result a { + color: var(--text-accent); + text-decoration: none; } -.verse-sidebar-wol-result a:hover { - text-decoration: underline; +.ref-sidebar-wol-result a:hover { + text-decoration: underline; +} + +/* Inline callout */ +.ref-callout-loading { + color: var(--text-muted); + font-style: italic; } diff --git a/types.ts b/types.ts index bc67827..9ec0ee7 100644 --- a/types.ts +++ b/types.ts @@ -1,13 +1,5 @@ -export interface VerseData { - type: 'verse'; - text: string; - reference: string; - translation?: string; +export interface ReferenceData { + type: 'reference'; + ref: string; // the original query string + results: string[]; // HTML strings from each result } - -export interface WolData { - type: 'wol'; - results: string[]; // outerHTML of each article.scalableui element -} - -export type ReferenceData = VerseData | WolData;