@life-and-dev/mdsite 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (133) hide show
  1. package/README.md +228 -0
  2. package/bin/mdsite.js +3 -0
  3. package/dist/commands/commands.test.d.ts +1 -0
  4. package/dist/commands/commands.test.js +302 -0
  5. package/dist/commands/commands.test.js.map +1 -0
  6. package/dist/commands/generate.d.ts +1 -0
  7. package/dist/commands/generate.js +20 -0
  8. package/dist/commands/generate.js.map +1 -0
  9. package/dist/commands/init.d.ts +1 -0
  10. package/dist/commands/init.js +16 -0
  11. package/dist/commands/init.js.map +1 -0
  12. package/dist/commands/prepare.d.ts +1 -0
  13. package/dist/commands/prepare.js +111 -0
  14. package/dist/commands/prepare.js.map +1 -0
  15. package/dist/commands/prepare.test.d.ts +1 -0
  16. package/dist/commands/prepare.test.js +131 -0
  17. package/dist/commands/prepare.test.js.map +1 -0
  18. package/dist/commands/preview.d.ts +5 -0
  19. package/dist/commands/preview.js +62 -0
  20. package/dist/commands/preview.js.map +1 -0
  21. package/dist/commands/start.d.ts +5 -0
  22. package/dist/commands/start.js +50 -0
  23. package/dist/commands/start.js.map +1 -0
  24. package/dist/commands/stop.d.ts +1 -0
  25. package/dist/commands/stop.js +26 -0
  26. package/dist/commands/stop.js.map +1 -0
  27. package/dist/commands/workflows.test.d.ts +1 -0
  28. package/dist/commands/workflows.test.js +183 -0
  29. package/dist/commands/workflows.test.js.map +1 -0
  30. package/dist/config/default-mdsite-config.d.ts +2 -0
  31. package/dist/config/default-mdsite-config.js +82 -0
  32. package/dist/config/default-mdsite-config.js.map +1 -0
  33. package/dist/config/default-mdsite-config.test.d.ts +1 -0
  34. package/dist/config/default-mdsite-config.test.js +42 -0
  35. package/dist/config/default-mdsite-config.test.js.map +1 -0
  36. package/dist/config/mdsite-config.d.ts +42 -0
  37. package/dist/config/mdsite-config.js +74 -0
  38. package/dist/config/mdsite-config.js.map +1 -0
  39. package/dist/config/mdsite-config.test.d.ts +1 -0
  40. package/dist/config/mdsite-config.test.js +115 -0
  41. package/dist/config/mdsite-config.test.js.map +1 -0
  42. package/dist/config/menu.d.ts +3 -0
  43. package/dist/config/menu.js +58 -0
  44. package/dist/config/menu.js.map +1 -0
  45. package/dist/config/menu.test.d.ts +1 -0
  46. package/dist/config/menu.test.js +53 -0
  47. package/dist/config/menu.test.js.map +1 -0
  48. package/dist/index.d.ts +2 -0
  49. package/dist/index.js +99 -0
  50. package/dist/index.js.map +1 -0
  51. package/dist/index.test.d.ts +1 -0
  52. package/dist/index.test.js +133 -0
  53. package/dist/index.test.js.map +1 -0
  54. package/dist/process/child-process.d.ts +9 -0
  55. package/dist/process/child-process.js +142 -0
  56. package/dist/process/child-process.js.map +1 -0
  57. package/dist/process/child-process.test.d.ts +1 -0
  58. package/dist/process/child-process.test.js +131 -0
  59. package/dist/process/child-process.test.js.map +1 -0
  60. package/dist/process/runtime-state.d.ts +16 -0
  61. package/dist/process/runtime-state.js +42 -0
  62. package/dist/process/runtime-state.js.map +1 -0
  63. package/dist/process/runtime-state.test.d.ts +1 -0
  64. package/dist/process/runtime-state.test.js +57 -0
  65. package/dist/process/runtime-state.test.js.map +1 -0
  66. package/dist/renderer/mdsite-nuxt.d.ts +22 -0
  67. package/dist/renderer/mdsite-nuxt.js +194 -0
  68. package/dist/renderer/mdsite-nuxt.js.map +1 -0
  69. package/dist/renderer/mdsite-nuxt.test.d.ts +1 -0
  70. package/dist/renderer/mdsite-nuxt.test.js +226 -0
  71. package/dist/renderer/mdsite-nuxt.test.js.map +1 -0
  72. package/mdsite-nuxt/app/app.vue +7 -0
  73. package/mdsite-nuxt/app/assets/css/bible-tooltips.css +87 -0
  74. package/mdsite-nuxt/app/assets/css/markdown.css +195 -0
  75. package/mdsite-nuxt/app/assets/css/print.css +133 -0
  76. package/mdsite-nuxt/app/components/AppBar.vue +138 -0
  77. package/mdsite-nuxt/app/components/AppFooter.vue +88 -0
  78. package/mdsite-nuxt/app/components/AppNavigation.vue +162 -0
  79. package/mdsite-nuxt/app/components/AppTableOfContents.vue +149 -0
  80. package/mdsite-nuxt/app/components/BreadcrumbNav.vue +139 -0
  81. package/mdsite-nuxt/app/components/NavigationTree.vue +169 -0
  82. package/mdsite-nuxt/app/components/SearchBox.vue +212 -0
  83. package/mdsite-nuxt/app/components/TocItem.vue +75 -0
  84. package/mdsite-nuxt/app/components/TreeNode.vue +264 -0
  85. package/mdsite-nuxt/app/components/content/MarkdownAlert.vue +42 -0
  86. package/mdsite-nuxt/app/components/content/Mermaid.vue +103 -0
  87. package/mdsite-nuxt/app/components/content/ProseA.vue +57 -0
  88. package/mdsite-nuxt/app/components/content/ProseBlockquote.vue +14 -0
  89. package/mdsite-nuxt/app/components/content/ProsePre.vue +49 -0
  90. package/mdsite-nuxt/app/components/content/ProseTable.vue +143 -0
  91. package/mdsite-nuxt/app/composables/useAppTheme.ts +89 -0
  92. package/mdsite-nuxt/app/composables/useBibleTooltips.ts +21 -0
  93. package/mdsite-nuxt/app/composables/useBreadcrumbs.ts +70 -0
  94. package/mdsite-nuxt/app/composables/useContentPostProcessing.ts +89 -0
  95. package/mdsite-nuxt/app/composables/useNavigationTree.ts +174 -0
  96. package/mdsite-nuxt/app/composables/useSearchIndex.ts +47 -0
  97. package/mdsite-nuxt/app/composables/useSearchRelevance.test.ts +255 -0
  98. package/mdsite-nuxt/app/composables/useSearchRelevance.ts +207 -0
  99. package/mdsite-nuxt/app/composables/useSidebarState.ts +62 -0
  100. package/mdsite-nuxt/app/composables/useSiteConfig.ts +37 -0
  101. package/mdsite-nuxt/app/composables/useSourceEdit.ts +69 -0
  102. package/mdsite-nuxt/app/composables/useTableOfContents.ts +141 -0
  103. package/mdsite-nuxt/app/composables/useTableParser.ts +106 -0
  104. package/mdsite-nuxt/app/composables/useTooltipConfig.ts +20 -0
  105. package/mdsite-nuxt/app/config/themes.ts +17 -0
  106. package/mdsite-nuxt/app/layouts/default.vue +376 -0
  107. package/mdsite-nuxt/app/pages/[...slug].vue +56 -0
  108. package/mdsite-nuxt/app/pages/index.vue +54 -0
  109. package/mdsite-nuxt/app/plugins/bible-tooltips.client.ts +401 -0
  110. package/mdsite-nuxt/app/plugins/bible-tooltips.test.ts +284 -0
  111. package/mdsite-nuxt/app/types/content.d.ts +10 -0
  112. package/mdsite-nuxt/app/types/table.ts +57 -0
  113. package/mdsite-nuxt/app/utils/bible-book-names.ts +37 -0
  114. package/mdsite-nuxt/app/utils/bible-verse-utils.test.ts +148 -0
  115. package/mdsite-nuxt/app/utils/bible-verse-utils.ts +236 -0
  116. package/mdsite-nuxt/content.config.ts +18 -0
  117. package/mdsite-nuxt/example.config.yml +67 -0
  118. package/mdsite-nuxt/nuxt.config.ts +247 -0
  119. package/mdsite-nuxt/package-lock.json +15922 -0
  120. package/mdsite-nuxt/package.json +50 -0
  121. package/mdsite-nuxt/playwright.config.js +47 -0
  122. package/mdsite-nuxt/public/robots.txt +2 -0
  123. package/mdsite-nuxt/scripts/generate-favicons.ts +192 -0
  124. package/mdsite-nuxt/scripts/generate-indices.ts +508 -0
  125. package/mdsite-nuxt/scripts/renderer-hooks.test.ts +277 -0
  126. package/mdsite-nuxt/scripts/renderer-hooks.ts +141 -0
  127. package/mdsite-nuxt/scripts/start.test.ts +164 -0
  128. package/mdsite-nuxt/scripts/start.ts +55 -0
  129. package/mdsite-nuxt/scripts/sync-content.ts +504 -0
  130. package/mdsite-nuxt/tsconfig.json +18 -0
  131. package/mdsite-nuxt/utils/mdsite-config.ts +240 -0
  132. package/mdsite-nuxt/vitest.config.ts +7 -0
  133. package/package.json +36 -0
@@ -0,0 +1,57 @@
1
+ /**
2
+ * TypeScript types for table parsing and v-data-table integration
3
+ */
4
+
5
+ /**
6
+ * v-data-table header configuration
7
+ */
8
+ export interface TableHeader {
9
+ /** Display title for the column */
10
+ title: string
11
+ /** Unique key for accessing data */
12
+ key: string
13
+ /** Whether column is sortable (default: true) */
14
+ sortable?: boolean
15
+ /** Column alignment */
16
+ align?: 'start' | 'end' | 'center'
17
+ /** Column width */
18
+ width?: string | number
19
+ }
20
+
21
+ /**
22
+ * v-data-table item (row data)
23
+ * Dynamic object with keys matching header keys
24
+ */
25
+ export type TableItem = Record<string, any>
26
+
27
+ /**
28
+ * Parsed table structure ready for v-data-table
29
+ */
30
+ export interface ParsedTable {
31
+ /** Column headers */
32
+ headers: TableHeader[]
33
+ /** Row data */
34
+ items: TableItem[]
35
+ }
36
+
37
+ /**
38
+ * Raw table cell data during parsing
39
+ */
40
+ export interface TableCell {
41
+ /** Text content of cell */
42
+ text: string
43
+ /** HTML content of cell (for complex formatting) */
44
+ html: string
45
+ /** Column index */
46
+ colIndex: number
47
+ }
48
+
49
+ /**
50
+ * Raw table row data during parsing
51
+ */
52
+ export interface TableRow {
53
+ /** Cells in this row */
54
+ cells: TableCell[]
55
+ /** Row index */
56
+ rowIndex: number
57
+ }
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Bible book names whitelist (66 books)
3
+ * Used for detecting Bible references while avoiding false positives
4
+ */
5
+ export const BIBLE_BOOK_NAMES = [
6
+ 'Genesis', 'Exodus', 'Leviticus', 'Numbers', 'Deuteronomy', 'Joshua', 'Judges', 'Ruth',
7
+ '1 Samuel', '2 Samuel', '1 Kings', '2 Kings', '1 Chronicles', '2 Chronicles',
8
+ 'Ezra', 'Nehemiah', 'Esther', 'Job', 'Psalm', 'Psalms', 'Proverbs', 'Ecclesiastes',
9
+ 'Song of Solomon', 'Isaiah', 'Jeremiah', 'Lamentations', 'Ezekiel', 'Daniel',
10
+ 'Hosea', 'Joel', 'Amos', 'Obadiah', 'Jonah', 'Micah', 'Nahum', 'Habakkuk',
11
+ 'Zephaniah', 'Haggai', 'Zechariah', 'Malachi',
12
+ 'Matthew', 'Mark', 'Luke', 'John', 'Acts', 'Romans',
13
+ '1 Corinthians', '2 Corinthians', 'Galatians', 'Ephesians', 'Philippians',
14
+ 'Colossians', '1 Thessalonians', '2 Thessalonians', '1 Timothy', '2 Timothy',
15
+ 'Titus', 'Philemon', 'Hebrews', 'James', '1 Peter', '2 Peter',
16
+ '1 John', '2 John', '3 John', 'Jude', 'Revelation'
17
+ ] as const
18
+
19
+ /**
20
+ * Creates Bible reference detection patterns using book name whitelist
21
+ * @returns Array of RegExp patterns for matching Bible references (with optional translation in brackets)
22
+ */
23
+ export function createBibleReferencePatterns(): RegExp[] {
24
+ const bookPattern = BIBLE_BOOK_NAMES.join('|').replace(/\s/g, '\\s+')
25
+ const translationPattern = '(?:\\s*\\([A-Z]+\\))?' // Optional (ESV), (KJV), etc.
26
+
27
+ return [
28
+ // Cross-chapter range: "2 Corinthians 4:16-5:9 (ESV)"
29
+ new RegExp(`\\b(${bookPattern})\\s+(\\d+):(\\d+)-(\\d+):(\\d+)${translationPattern}\\b`, 'g'),
30
+ // Same chapter range: "John 3:16-18 (ESV)" - ensure we don't match if followed by digits (prevents matching "3:16-5" in "3:16-5:9")
31
+ new RegExp(`\\b(${bookPattern})\\s+(\\d+):(\\d+)-(\\d+)${translationPattern}\\b(?!\\d)`, 'g'),
32
+ // Single verse: "John 3:16 (ESV)" - ensure we don't match if followed by dash or digits (allows punctuation like colon, period, comma)
33
+ new RegExp(`\\b(${bookPattern})\\s+(\\d+):(\\d+)${translationPattern}\\b(?![\\d-])`, 'g'),
34
+ // Chapter only: "John 3 (ESV)", "Psalm 23 (ESV)" - ensure not followed by colon
35
+ new RegExp(`\\b(${bookPattern})\\s+(\\d+)${translationPattern}\\b(?!\\s*:)`, 'g')
36
+ ]
37
+ }
@@ -0,0 +1,148 @@
1
+ import { describe, it, expect } from 'vitest'
2
+ import { createBibleHubInterlinearUrl, parseReference } from './bible-verse-utils'
3
+
4
+ /**
5
+ * Unit tests for BibleHub interlinear URL generation
6
+ */
7
+ describe('BibleHub Interlinear URL Generation', () => {
8
+ it('should create URL for single verse reference', () => {
9
+ const url = createBibleHubInterlinearUrl('John 3:16')
10
+ expect(url).toBe('https://biblehub.com/interlinear/john/3-16.htm')
11
+ })
12
+
13
+ it('should create URL for chapter-only reference', () => {
14
+ const url = createBibleHubInterlinearUrl('Psalm 23')
15
+ expect(url).toBe('https://biblehub.com/interlinear/psalm/23.htm')
16
+ })
17
+
18
+ it('should create URL for verse range (use first verse)', () => {
19
+ const url = createBibleHubInterlinearUrl('John 3:16-18')
20
+ expect(url).toBe('https://biblehub.com/interlinear/john/3-16.htm')
21
+ })
22
+
23
+ it('should handle book names with spaces', () => {
24
+ const url = createBibleHubInterlinearUrl('1 Corinthians 13:4')
25
+ expect(url).toBe('https://biblehub.com/interlinear/1_corinthians/13-4.htm')
26
+ })
27
+
28
+ it('should handle book names with numbers', () => {
29
+ const url = createBibleHubInterlinearUrl('2 Timothy 3:16')
30
+ expect(url).toBe('https://biblehub.com/interlinear/2_timothy/3-16.htm')
31
+ })
32
+
33
+ it('should handle multi-word book names', () => {
34
+ const url = createBibleHubInterlinearUrl('Song of Solomon 2:1')
35
+ expect(url).toBe('https://biblehub.com/interlinear/song_of_solomon/2-1.htm')
36
+ })
37
+
38
+ it('should handle cross-chapter ranges (use first reference)', () => {
39
+ const url = createBibleHubInterlinearUrl('2 Corinthians 4:16-5:9')
40
+ expect(url).toBe('https://biblehub.com/interlinear/2_corinthians/4-16.htm')
41
+ })
42
+
43
+ it('should handle Genesis references', () => {
44
+ const url = createBibleHubInterlinearUrl('Genesis 1:1')
45
+ expect(url).toBe('https://biblehub.com/interlinear/genesis/1-1.htm')
46
+ })
47
+
48
+ it('should handle Revelation references', () => {
49
+ const url = createBibleHubInterlinearUrl('Revelation 1:5')
50
+ expect(url).toBe('https://biblehub.com/interlinear/revelation/1-5.htm')
51
+ })
52
+
53
+ it('should handle Ecclesiastes references', () => {
54
+ const url = createBibleHubInterlinearUrl('Ecclesiastes 1:2')
55
+ expect(url).toBe('https://biblehub.com/interlinear/ecclesiastes/1-2.htm')
56
+ })
57
+
58
+ it('should handle references with multiple spaces', () => {
59
+ const url = createBibleHubInterlinearUrl('1 Corinthians 13:4')
60
+ expect(url).toBe('https://biblehub.com/interlinear/1_corinthians/13-4.htm')
61
+ })
62
+
63
+ it('should fallback to main page for invalid reference', () => {
64
+ const url = createBibleHubInterlinearUrl('InvalidBook')
65
+ expect(url).toBe('https://biblehub.com/interlinear/')
66
+ })
67
+
68
+ it('should fallback to main page for empty reference', () => {
69
+ const url = createBibleHubInterlinearUrl('')
70
+ expect(url).toBe('https://biblehub.com/interlinear/')
71
+ })
72
+
73
+ it('should normalize book names to lowercase', () => {
74
+ const url = createBibleHubInterlinearUrl('JOHN 3:16')
75
+ expect(url).toBe('https://biblehub.com/interlinear/john/3-16.htm')
76
+ })
77
+
78
+ it('should handle chapter with large verse number', () => {
79
+ const url = createBibleHubInterlinearUrl('Psalm 119:105')
80
+ expect(url).toBe('https://biblehub.com/interlinear/psalm/119-105.htm')
81
+ })
82
+ })
83
+
84
+ /**
85
+ * Unit tests for Bible reference parsing with translation extraction
86
+ */
87
+ describe('parseReference', () => {
88
+ it('should parse reference with ESV translation', () => {
89
+ const result = parseReference('John 3:16 (ESV)')
90
+ expect(result.reference).toBe('John 3:16')
91
+ expect(result.translation).toBe('ESV')
92
+ })
93
+
94
+ it('should parse reference with KJV translation', () => {
95
+ const result = parseReference('Genesis 1:1 (KJV)')
96
+ expect(result.reference).toBe('Genesis 1:1')
97
+ expect(result.translation).toBe('KJV')
98
+ })
99
+
100
+ it('should parse reference with NIV translation', () => {
101
+ const result = parseReference('Matthew 5:3-12 (NIV)')
102
+ expect(result.reference).toBe('Matthew 5:3-12')
103
+ expect(result.translation).toBe('NIV')
104
+ })
105
+
106
+ it('should default to ESV when no translation specified', () => {
107
+ const result = parseReference('John 3:16')
108
+ expect(result.reference).toBe('John 3:16')
109
+ expect(result.translation).toBe('ESV')
110
+ })
111
+
112
+ it('should default to ESV for chapter-only reference', () => {
113
+ const result = parseReference('Psalm 23')
114
+ expect(result.reference).toBe('Psalm 23')
115
+ expect(result.translation).toBe('ESV')
116
+ })
117
+
118
+ it('should handle extra whitespace around translation', () => {
119
+ const result = parseReference('John 3:16 (ESV) ')
120
+ expect(result.reference).toBe('John 3:16')
121
+ expect(result.translation).toBe('ESV')
122
+ })
123
+
124
+ it('should handle references with extra whitespace', () => {
125
+ const result = parseReference(' John 3:16 ')
126
+ expect(result.reference).toBe('John 3:16')
127
+ expect(result.translation).toBe('ESV')
128
+ })
129
+
130
+ it('should parse cross-chapter range with translation', () => {
131
+ const result = parseReference('2 Corinthians 4:16-5:9 (ESV)')
132
+ expect(result.reference).toBe('2 Corinthians 4:16-5:9')
133
+ expect(result.translation).toBe('ESV')
134
+ })
135
+
136
+ it('should handle translation codes with varying lengths', () => {
137
+ const result = parseReference('John 3:16 (NKJV)')
138
+ expect(result.reference).toBe('John 3:16')
139
+ expect(result.translation).toBe('NKJV')
140
+ })
141
+
142
+ it('should not parse lowercase translations', () => {
143
+ // Lowercase should not match - treated as no translation
144
+ const result = parseReference('John 3:16 (esv)')
145
+ expect(result.reference).toBe('John 3:16 (esv)')
146
+ expect(result.translation).toBe('ESV')
147
+ })
148
+ })
@@ -0,0 +1,236 @@
1
+ /**
2
+ * Shared utility functions for Bible verse handling with Bolls.life API
3
+ */
4
+
5
+ /**
6
+ * Bolls.life API response format for single verse
7
+ */
8
+ interface BollsVerseResponse {
9
+ pk: number
10
+ verse: number
11
+ text: string
12
+ comment?: string // HTML cross-references
13
+ }
14
+
15
+ export interface ProcessedBibleVerse {
16
+ text: string
17
+ translation: string
18
+ }
19
+
20
+ export interface ParsedReference {
21
+ reference: string // Reference without translation (e.g., "John 3:16")
22
+ translation: string // Translation code (e.g., "ESV", defaults to "ESV")
23
+ }
24
+
25
+ /**
26
+ * Standard Bible book numbering (1-66)
27
+ * Used by Bolls.life API
28
+ */
29
+ const BOOK_NUMBERS: Record<string, number> = {
30
+ // Old Testament (1-39)
31
+ 'genesis': 1, 'gen': 1,
32
+ 'exodus': 2, 'exo': 2, 'exod': 2,
33
+ 'leviticus': 3, 'lev': 3,
34
+ 'numbers': 4, 'num': 4,
35
+ 'deuteronomy': 5, 'deut': 5, 'deu': 5,
36
+ 'joshua': 6, 'josh': 6, 'jos': 6,
37
+ 'judges': 7, 'judg': 7, 'jdg': 7,
38
+ 'ruth': 8, 'rut': 8,
39
+ '1 samuel': 9, '1samuel': 9, '1sam': 9, '1sa': 9, 'i samuel': 9,
40
+ '2 samuel': 10, '2samuel': 10, '2sam': 10, '2sa': 10, 'ii samuel': 10,
41
+ '1 kings': 11, '1kings': 11, '1kgs': 11, '1ki': 11, 'i kings': 11,
42
+ '2 kings': 12, '2kings': 12, '2kgs': 12, '2ki': 12, 'ii kings': 12,
43
+ '1 chronicles': 13, '1chronicles': 13, '1chr': 13, '1ch': 13, 'i chronicles': 13,
44
+ '2 chronicles': 14, '2chronicles': 14, '2chr': 14, '2ch': 14, 'ii chronicles': 14,
45
+ 'ezra': 15, 'ezr': 15,
46
+ 'nehemiah': 16, 'neh': 16,
47
+ 'esther': 17, 'est': 17, 'esth': 17,
48
+ 'job': 18,
49
+ 'psalm': 19, 'psalms': 19, 'psa': 19, 'ps': 19,
50
+ 'proverbs': 20, 'prov': 20, 'pro': 20,
51
+ 'ecclesiastes': 21, 'eccl': 21, 'ecc': 21, 'eccles': 21,
52
+ 'song of solomon': 22, 'song': 22, 'sos': 22, 'song of songs': 22,
53
+ 'isaiah': 23, 'isa': 23,
54
+ 'jeremiah': 24, 'jer': 24,
55
+ 'lamentations': 25, 'lam': 25,
56
+ 'ezekiel': 26, 'ezek': 26, 'eze': 26,
57
+ 'daniel': 27, 'dan': 27,
58
+ 'hosea': 28, 'hos': 28,
59
+ 'joel': 29, 'joe': 29,
60
+ 'amos': 30, 'amo': 30,
61
+ 'obadiah': 31, 'obad': 31, 'oba': 31,
62
+ 'jonah': 32, 'jon': 32,
63
+ 'micah': 33, 'mic': 33,
64
+ 'nahum': 34, 'nah': 34, 'nam': 34,
65
+ 'habakkuk': 35, 'hab': 35,
66
+ 'zephaniah': 36, 'zeph': 36, 'zep': 36,
67
+ 'haggai': 37, 'hag': 37,
68
+ 'zechariah': 38, 'zech': 38, 'zec': 38,
69
+ 'malachi': 39, 'mal': 39,
70
+ // New Testament (40-66)
71
+ 'matthew': 40, 'matt': 40, 'mat': 40, 'mt': 40,
72
+ 'mark': 41, 'mar': 41, 'mk': 41, 'mrk': 41,
73
+ 'luke': 42, 'luk': 42, 'lk': 42,
74
+ 'john': 43, 'joh': 43, 'jn': 43,
75
+ 'acts': 44, 'act': 44,
76
+ 'romans': 45, 'rom': 45, 'rm': 45,
77
+ '1 corinthians': 46, '1corinthians': 46, '1cor': 46, '1co': 46, 'i corinthians': 46,
78
+ '2 corinthians': 47, '2corinthians': 47, '2cor': 47, '2co': 47, 'ii corinthians': 47,
79
+ 'galatians': 48, 'gal': 48,
80
+ 'ephesians': 49, 'eph': 49,
81
+ 'philippians': 50, 'phil': 50, 'php': 50,
82
+ 'colossians': 51, 'col': 51,
83
+ '1 thessalonians': 52, '1thessalonians': 52, '1thess': 52, '1th': 52, 'i thessalonians': 52,
84
+ '2 thessalonians': 53, '2thessalonians': 53, '2thess': 53, '2th': 53, 'ii thessalonians': 53,
85
+ '1 timothy': 54, '1timothy': 54, '1tim': 54, '1ti': 54, 'i timothy': 54,
86
+ '2 timothy': 55, '2timothy': 55, '2tim': 55, '2ti': 55, 'ii timothy': 55,
87
+ 'titus': 56, 'tit': 56,
88
+ 'philemon': 57, 'philem': 57, 'phm': 57,
89
+ 'hebrews': 58, 'heb': 58,
90
+ 'james': 59, 'jas': 59, 'jam': 59,
91
+ '1 peter': 60, '1peter': 60, '1pet': 60, '1pe': 60, 'i peter': 60,
92
+ '2 peter': 61, '2peter': 61, '2pet': 61, '2pe': 61, 'ii peter': 61,
93
+ '1 john': 62, '1john': 62, '1jn': 62, 'i john': 62,
94
+ '2 john': 63, '2john': 63, '2jn': 63, 'ii john': 63,
95
+ '3 john': 64, '3john': 64, '3jn': 63, 'iii john': 64,
96
+ 'jude': 65, 'jud': 65,
97
+ 'revelation': 66, 'rev': 66,
98
+ }
99
+
100
+ /**
101
+ * Get standard book number (1-66) from book name
102
+ * @param bookName - Bible book name (case-insensitive)
103
+ * @returns Book number or null if not found
104
+ */
105
+ export function getBookNumber(bookName: string): number | null {
106
+ const normalized = bookName.toLowerCase().trim()
107
+ return BOOK_NUMBERS[normalized] ?? null
108
+ }
109
+
110
+ /**
111
+ * Parse a Bible reference and extract translation
112
+ * @param fullReference - Full reference with optional translation (e.g., "John 3:16 (KJV)" or "John 3:16")
113
+ * @returns Parsed reference object with reference and translation
114
+ */
115
+ export function parseReference(fullReference: string): ParsedReference {
116
+ // Match translation in parentheses at the end: (ESV), (KJV), etc.
117
+ const match = fullReference.match(/^(.+?)\s*\(([A-Z]+)\)\s*$/)
118
+
119
+ if (match && match[1] && match[2]) {
120
+ return {
121
+ reference: match[1].trim(),
122
+ translation: match[2]
123
+ }
124
+ }
125
+
126
+ // No translation specified, default to ESV
127
+ return {
128
+ reference: fullReference.trim(),
129
+ translation: 'ESV'
130
+ }
131
+ }
132
+
133
+ const MAX_VERSES = 4
134
+
135
+ /**
136
+ * Strip HTML tags from text, preserving content
137
+ * @param html - HTML string
138
+ * @returns Plain text
139
+ */
140
+ function stripHtml(html: string): string {
141
+ return html
142
+ .replace(/<S>\d+<\/S>/g, '') // Remove Strong's numbers
143
+ .replace(/<i>(.*?)<\/i>/g, '$1') // Keep italicized content
144
+ .replace(/<a[^>]*>(.*?)<\/a>/g, '$1') // Keep link text
145
+ .replace(/<[^>]+>/g, '') // Remove all other tags
146
+ .replace(/\s+/g, ' ') // Normalize whitespace
147
+ .trim()
148
+ }
149
+
150
+ /**
151
+ * Process Bolls.life API response for single verse
152
+ * @param data - Response from Bolls.life API
153
+ * @param translation - Translation code
154
+ * @returns Processed verse with stripped HTML
155
+ */
156
+ export function processBollsVerse(data: BollsVerseResponse, translation: string): ProcessedBibleVerse {
157
+ const text = stripHtml(data.text)
158
+
159
+ return {
160
+ text,
161
+ translation: translation.toUpperCase()
162
+ }
163
+ }
164
+
165
+ /**
166
+ * Process Bolls.life API response for verse range
167
+ * @param data - Array of verses from Bolls.life API
168
+ * @param translation - Translation code
169
+ * @param startVerse - Starting verse number (optional, for range filtering)
170
+ * @param endVerse - Ending verse number (optional, for range filtering)
171
+ * @returns Processed verses with truncation if needed
172
+ */
173
+ export function processBollsVerseRange(
174
+ data: BollsVerseResponse[],
175
+ translation: string,
176
+ startVerse?: number,
177
+ endVerse?: number
178
+ ): ProcessedBibleVerse {
179
+ let verses = data
180
+
181
+ // Filter to verse range if specified
182
+ if (startVerse !== undefined) {
183
+ const end = endVerse ?? startVerse
184
+ verses = data.filter(v => v.verse >= startVerse && v.verse <= end)
185
+ }
186
+
187
+ // Truncate to first 4 verses if needed
188
+ const wasTruncated = verses.length > MAX_VERSES
189
+ const limitedVerses = verses.slice(0, MAX_VERSES)
190
+
191
+ // Join and strip HTML
192
+ const text = limitedVerses
193
+ .map(v => stripHtml(v.text))
194
+ .join(' ')
195
+
196
+ const finalText = wasTruncated ? text + ' ...' : text
197
+
198
+ return {
199
+ text: finalText,
200
+ translation: translation.toUpperCase()
201
+ }
202
+ }
203
+
204
+ /**
205
+ * Create BibleHub interlinear URL from a Bible reference
206
+ * @param reference - Bible reference (e.g., "John 3:16", "Genesis 1:1-3", "Psalm 23")
207
+ * @returns BibleHub interlinear URL
208
+ */
209
+ export function createBibleHubInterlinearUrl(reference: string): string {
210
+ // Parse reference: "Book Chapter:Verse" or "Book Chapter:Verse-Verse2" or "Book Chapter"
211
+ const match = reference.match(/^(.+?)\s+(\d+)(?::(\d+))?(?:-(\d+))?/)
212
+
213
+ if (!match) {
214
+ // Fallback to main interlinear page if we can't parse
215
+ return 'https://biblehub.com/interlinear/'
216
+ }
217
+
218
+ const [, book, chapter, verse] = match
219
+
220
+ // Type guard: ensure book and chapter exist
221
+ if (!book || !chapter) {
222
+ return 'https://biblehub.com/interlinear/'
223
+ }
224
+
225
+ // Normalize book name for URL (lowercase, replace spaces with underscores)
226
+ const bookSlug = book.toLowerCase().replace(/\s+/g, '_')
227
+
228
+ // Build URL
229
+ if (verse) {
230
+ // Specific verse: /interlinear/book/chapter-verse.htm
231
+ return `https://biblehub.com/interlinear/${bookSlug}/${chapter}-${verse}.htm`
232
+ } else {
233
+ // Chapter only: /interlinear/book/chapter.htm
234
+ return `https://biblehub.com/interlinear/${bookSlug}/${chapter}.htm`
235
+ }
236
+ }
@@ -0,0 +1,18 @@
1
+ import { defineCollection, defineContentConfig } from '@nuxt/content'
2
+ import { loadMdsiteConfigSync } from './utils/mdsite-config.js'
3
+
4
+ const { contentDir } = loadMdsiteConfigSync()
5
+
6
+ export default defineContentConfig({
7
+ collections: {
8
+ content: defineCollection({
9
+ type: 'page',
10
+ source: {
11
+ cwd: contentDir,
12
+ include: '**/*.md',
13
+ exclude: ['**/*.draft.md'],
14
+ prefix: '/'
15
+ }
16
+ })
17
+ }
18
+ })
@@ -0,0 +1,67 @@
1
+ content:
2
+ git:
3
+ branch: main
4
+ path: ../example # Path where git content is cloned/checked out relative to this file
5
+ repo: https://github.com/life-and-dev/md-site # If missing, assume content is part of this git repo
6
+ path: ../example/docs # Path where md files are located relative to this file
7
+ features:
8
+ bibleTooltips: true
9
+ sourceEdit: false
10
+ site:
11
+ canonical: 'https://life-and-dev.github.io/md-site'
12
+ name: 'Example Site'
13
+ themes:
14
+ light:
15
+ colors:
16
+ primary: '#802020'
17
+ secondary: '#ffffff'
18
+ selected: '#802020'
19
+ error: '#d64d5b'
20
+ warning: '#c29e4a'
21
+ info: '#548af7'
22
+ success: '#6aab73'
23
+ background: '#f9f9f9'
24
+ surface: '#ffffff'
25
+ surface-rail: '#f5f5f5'
26
+ surface-appbar: '#f0f0f0'
27
+ on-surface-rail: '#2a2a2a'
28
+ on-surface-appbar: '#000000'
29
+ on-background: '#292929'
30
+ on-surface: '#292929'
31
+ on-primary: '#ffffff'
32
+ on-secondary: '#ffffff'
33
+ on-selectable: '#292929'
34
+ on-selected: '#ffffff'
35
+ on-error: '#ffffff'
36
+ on-warning: '#ffffff'
37
+ on-info: '#ffffff'
38
+ on-success: '#ffffff'
39
+ outline: '#d7d7d7'
40
+ outline-bars: '#f4f4f4'
41
+ dark:
42
+ colors:
43
+ primary: '#af5f5f'
44
+ secondary: '#302d2b'
45
+ selected: '#af5f5f'
46
+ error: '#d64d5b'
47
+ warning: '#c29e4a'
48
+ info: '#548af7'
49
+ success: '#6aab73'
50
+ background: '#161616'
51
+ surface: '#0d0d0d'
52
+ surface-rail: '#252525'
53
+ surface-appbar: '#282828'
54
+ on-surface-rail: '#d0d0d0'
55
+ on-surface-appbar: '#ffffff'
56
+ on-background: '#d1d1d1'
57
+ on-surface: '#d1d1d1'
58
+ on-primary: '#111111'
59
+ on-secondary: '#111111'
60
+ on-selectable: '#d1d1d1'
61
+ on-selected: '#ffffff'
62
+ on-error: '#ffffff'
63
+ on-warning: '#ffffff'
64
+ on-info: '#ffffff'
65
+ on-success: '#ffffff'
66
+ outline: '#303030'
67
+ outline-bars: '#161616'