metanorma-document 0.2.9 → 0.2.12

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 (390) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop_todo.yml +164 -66
  3. data/CLAUDE.md +26 -0
  4. data/README.adoc +144 -0
  5. data/Rakefile +14 -2
  6. data/TODO.finalize/01-split-multi-class-files.md +8 -0
  7. data/TODO.finalize/02-remove-data-dist-iso-document-frontend.md +6 -0
  8. data/TODO.finalize/03-align-frontend-iife-and-gha-build.md +11 -0
  9. data/TODO.finalize/04-theme-per-flavor-config-driven.md +9 -0
  10. data/TODO.finalize/05-migrate-all-html-to-liquid.md +16 -0
  11. data/TODO.finalize/06-integrate-pubid-library.md +16 -0
  12. data/TODO.finalize/07-replace-relaton-models-with-relaton-bib.md +39 -0
  13. data/TODO.finalize/08-refactor-renderer-architecture.md +25 -0
  14. data/TODO.finalize/09-eliminate-code-smells.md +14 -0
  15. data/TODO.finalize/10-comprehensive-spec-coverage.md +24 -0
  16. data/TODO.finalize/11-config-driven-flavor-metadata.md +20 -0
  17. data/TODO.finalize/12-add-frozen-string-literal.md +6 -0
  18. data/TODO.finalize/13-extract-composition-from-god-class.md +96 -0
  19. data/TODO.finalize/14-config-driven-section-ordering.md +31 -0
  20. data/TODO.finalize/15-theme-directories-per-flavor.md +46 -0
  21. data/TODO.finalize/16-theme-lutaml-model-schema.md +44 -0
  22. data/data/javascripts/components/mn-footnotes.js +68 -0
  23. data/data/javascripts/components/mn-lightbox.js +18 -2
  24. data/data/javascripts/components/mn-shortcuts.js +2 -0
  25. data/data/javascripts/core/mn-navigation.js +8 -0
  26. data/data/javascripts/core/mn-theme.js +9 -9
  27. data/data/logos/oiml-logo-full-dark.svg +1 -0
  28. data/data/logos/oiml-logo-full-light.svg +1 -0
  29. data/data/logos/oiml-logo-icon-dark.svg +1 -0
  30. data/data/logos/oiml-logo-icon-light.svg +1 -0
  31. data/data/logos/oiml-logo.svg +1 -0
  32. data/data/logos/pdfa-logo.svg +31 -94
  33. data/data/stylesheets/base/_layout.css +3 -0
  34. data/data/stylesheets/base/_reset.css +3 -3
  35. data/data/stylesheets/base/_typography.css +0 -5
  36. data/data/stylesheets/components/bibliography.css +3 -3
  37. data/data/stylesheets/components/cover.css +3 -1
  38. data/data/stylesheets/components/figure.css +13 -1
  39. data/data/stylesheets/components/footnote.css +65 -5
  40. data/data/stylesheets/components/formula.css +44 -0
  41. data/data/stylesheets/components/header.css +17 -2
  42. data/data/stylesheets/components/inline.css +1 -1
  43. data/data/stylesheets/components/table.css +15 -2
  44. data/data/stylesheets/components/term.css +0 -1
  45. data/data/themes/bipm.yaml +60 -0
  46. data/data/themes/cc.yaml +43 -0
  47. data/data/themes/icc.yaml +39 -0
  48. data/data/themes/iec.yaml +44 -0
  49. data/data/themes/ieee.yaml +43 -0
  50. data/data/themes/ietf.yaml +45 -0
  51. data/data/themes/iho.yaml +46 -0
  52. data/data/themes/iso.yaml +40 -0
  53. data/data/themes/itu.yaml +45 -0
  54. data/data/themes/ogc.yaml +51 -0
  55. data/data/themes/oiml.yaml +56 -0
  56. data/data/themes/pdfa.yaml +44 -0
  57. data/data/themes/ribose.yaml +43 -0
  58. data/exe/metanorma-document +11 -0
  59. data/frontend/e2e/sample-html.test.ts +256 -0
  60. data/frontend/index.html +12 -0
  61. data/frontend/package-lock.json +4725 -0
  62. data/frontend/package.json +32 -0
  63. data/frontend/postcss.config.js +6 -0
  64. data/frontend/src/App.vue +79 -0
  65. data/frontend/src/app.ts +21 -0
  66. data/frontend/src/components/AppSidebar.vue +77 -0
  67. data/frontend/src/components/DocumentReader.vue +180 -0
  68. data/frontend/src/components/MirrorRenderer.vue +23 -0
  69. data/frontend/src/components/ReadingProgressBar.vue +29 -0
  70. data/frontend/src/components/TextRenderer.vue +131 -0
  71. data/frontend/src/components/TocItem.vue +57 -0
  72. data/frontend/src/components/TopBar.vue +49 -0
  73. data/frontend/src/components/__tests__/MirrorRenderer.test.ts +178 -0
  74. data/frontend/src/components/blocks/AdmonitionBlock.vue +74 -0
  75. data/frontend/src/components/blocks/ClauseBlock.vue +53 -0
  76. data/frontend/src/components/blocks/ExampleBlock.vue +21 -0
  77. data/frontend/src/components/blocks/FallbackBlock.vue +18 -0
  78. data/frontend/src/components/blocks/FigureBlock.vue +26 -0
  79. data/frontend/src/components/blocks/FootnotesBlock.vue +25 -0
  80. data/frontend/src/components/blocks/ListBlocks.vue +62 -0
  81. data/frontend/src/components/blocks/NoteBlock.vue +21 -0
  82. data/frontend/src/components/blocks/ParagraphBlock.vue +25 -0
  83. data/frontend/src/components/blocks/QuoteBlock.vue +25 -0
  84. data/frontend/src/components/blocks/ReviewBlock.vue +39 -0
  85. data/frontend/src/components/blocks/SourcecodeBlock.vue +52 -0
  86. data/frontend/src/components/blocks/TableBlock.vue +48 -0
  87. data/frontend/src/components/blocks/index.ts +36 -0
  88. data/frontend/src/stores/__tests__/documentStore.fixture.test.ts +272 -0
  89. data/frontend/src/stores/__tests__/documentStore.test.ts +143 -0
  90. data/frontend/src/stores/__tests__/ebookStore.test.ts +145 -0
  91. data/frontend/src/stores/__tests__/uiStore.test.ts +42 -0
  92. data/frontend/src/stores/documentStore.ts +153 -0
  93. data/frontend/src/stores/ebookStore.ts +179 -0
  94. data/frontend/src/stores/uiStore.ts +32 -0
  95. data/frontend/src/styles.css +156 -0
  96. data/frontend/src/types/__tests__/rendering-contract.test.ts +172 -0
  97. data/frontend/src/types/rendering-contract.ts +209 -0
  98. data/frontend/src/utils/__tests__/typeMetadata.test.ts +102 -0
  99. data/frontend/src/utils/typeMetadata.ts +121 -0
  100. data/frontend/tailwind.config.js +18 -0
  101. data/frontend/test/fixtures/iso-document.json +271 -0
  102. data/frontend/tmp/debug_e2e.cjs +46 -0
  103. data/frontend/tsconfig.json +25 -0
  104. data/frontend/tsconfig.node.json +11 -0
  105. data/frontend/vite.config.ts +37 -0
  106. data/frontend/vitest.e2e.config.ts +9 -0
  107. data/lib/metanorma/bipm_document/metadata/bipm_bibliographic_item.rb +0 -14
  108. data/lib/metanorma/bipm_document/metadata/depiction_element.rb +18 -0
  109. data/lib/metanorma/bipm_document/metadata.rb +1 -1
  110. data/lib/metanorma/document/cli.rb +116 -0
  111. data/lib/metanorma/document/components/ancillary_blocks/callout_annotation.rb +27 -0
  112. data/lib/metanorma/document/components/ancillary_blocks/sourcecode_block.rb +0 -65
  113. data/lib/metanorma/document/components/ancillary_blocks/sourcecode_body.rb +18 -0
  114. data/lib/metanorma/document/components/ancillary_blocks.rb +4 -0
  115. data/lib/metanorma/document/components/bib_data/bib_data.rb +7 -0
  116. data/lib/metanorma/document/components/blocks/classification_value.rb +21 -0
  117. data/lib/metanorma/document/components/blocks/permission_model.rb +28 -0
  118. data/lib/metanorma/document/components/blocks/recommendation_model.rb +28 -0
  119. data/lib/metanorma/document/components/blocks/requirement_base.rb +30 -0
  120. data/lib/metanorma/document/components/blocks/requirement_classification.rb +20 -0
  121. data/lib/metanorma/document/components/blocks/requirement_description.rb +43 -0
  122. data/lib/metanorma/document/components/blocks/requirement_inherit.rb +24 -0
  123. data/lib/metanorma/document/components/blocks/requirement_model.rb +0 -131
  124. data/lib/metanorma/document/components/blocks.rb +8 -7
  125. data/lib/metanorma/document/components/id_elements/image.rb +2 -0
  126. data/lib/metanorma/document/components/inline/asciimath_element.rb +2 -0
  127. data/lib/metanorma/document/components/inline/attribution_element.rb +2 -0
  128. data/lib/metanorma/document/components/inline/bcp14_element.rb +2 -0
  129. data/lib/metanorma/document/components/inline/biblio_tag_element.rb +2 -0
  130. data/lib/metanorma/document/components/inline/br_element.rb +2 -0
  131. data/lib/metanorma/document/components/inline/comma_element.rb +2 -0
  132. data/lib/metanorma/document/components/inline/concept_element.rb +2 -0
  133. data/lib/metanorma/document/components/inline/display_text_element.rb +2 -0
  134. data/lib/metanorma/document/components/inline/em_raw_element.rb +2 -0
  135. data/lib/metanorma/document/components/inline/enum_comma_element.rb +2 -0
  136. data/lib/metanorma/document/components/inline/eref_element.rb +2 -0
  137. data/lib/metanorma/document/components/inline/fmt_admitted_element.rb +4 -0
  138. data/lib/metanorma/document/components/inline/fmt_annotation_body_element.rb +4 -0
  139. data/lib/metanorma/document/components/inline/fmt_annotation_end_element.rb +4 -0
  140. data/lib/metanorma/document/components/inline/fmt_annotation_start_element.rb +4 -0
  141. data/lib/metanorma/document/components/inline/fmt_concept_element.rb +4 -0
  142. data/lib/metanorma/document/components/inline/fmt_definition_element.rb +4 -0
  143. data/lib/metanorma/document/components/inline/fmt_fn_body_element.rb +4 -0
  144. data/lib/metanorma/document/components/inline/fmt_fn_label_element.rb +4 -0
  145. data/lib/metanorma/document/components/inline/fmt_footnote_container_element.rb +4 -0
  146. data/lib/metanorma/document/components/inline/fmt_identifier_element.rb +4 -0
  147. data/lib/metanorma/document/components/inline/fmt_name_element.rb +4 -0
  148. data/lib/metanorma/document/components/inline/fmt_preferred_element.rb +4 -0
  149. data/lib/metanorma/document/components/inline/fmt_sourcecode_element.rb +4 -0
  150. data/lib/metanorma/document/components/inline/fmt_stem_element.rb +10 -0
  151. data/lib/metanorma/document/components/inline/fmt_termsource_element.rb +4 -0
  152. data/lib/metanorma/document/components/inline/fmt_title_element.rb +4 -0
  153. data/lib/metanorma/document/components/inline/fmt_xref_element.rb +4 -0
  154. data/lib/metanorma/document/components/inline/fmt_xref_label_element.rb +4 -0
  155. data/lib/metanorma/document/components/inline/fn_element.rb +2 -0
  156. data/lib/metanorma/document/components/inline/link_element.rb +2 -0
  157. data/lib/metanorma/document/components/inline/localized_string_element.rb +2 -0
  158. data/lib/metanorma/document/components/inline/localized_strings_element.rb +2 -0
  159. data/lib/metanorma/document/components/inline/location_element.rb +24 -0
  160. data/lib/metanorma/document/components/inline/math_element.rb +2 -0
  161. data/lib/metanorma/document/components/inline/name_with_id_element.rb +4 -0
  162. data/lib/metanorma/document/components/inline/rendered_display.rb +23 -0
  163. data/lib/metanorma/document/components/inline/rendered_math_element.rb +21 -0
  164. data/lib/metanorma/document/components/inline/semantic_content.rb +51 -0
  165. data/lib/metanorma/document/components/inline/semantic_math_element.rb +20 -0
  166. data/lib/metanorma/document/components/inline/semx_child_element.rb +2 -0
  167. data/lib/metanorma/document/components/inline/semx_element.rb +13 -1
  168. data/lib/metanorma/document/components/inline/small_cap_element.rb +2 -0
  169. data/lib/metanorma/document/components/inline/span_element.rb +10 -15
  170. data/lib/metanorma/document/components/inline/stem_inline_element.rb +7 -1
  171. data/lib/metanorma/document/components/inline/strong_raw_element.rb +2 -0
  172. data/lib/metanorma/document/components/inline/sub_element.rb +2 -0
  173. data/lib/metanorma/document/components/inline/sup_element.rb +2 -0
  174. data/lib/metanorma/document/components/inline/tab_element.rb +2 -0
  175. data/lib/metanorma/document/components/inline/title_with_annotation_element.rb +4 -0
  176. data/lib/metanorma/document/components/inline/tt_element.rb +2 -0
  177. data/lib/metanorma/document/components/inline/variant_title_element.rb +2 -0
  178. data/lib/metanorma/document/components/inline/vocabulary.rb +184 -0
  179. data/lib/metanorma/document/components/inline/xref_element.rb +10 -0
  180. data/lib/metanorma/document/components/inline.rb +12 -0
  181. data/lib/metanorma/document/components/multi_paragraph/quote_author_element.rb +20 -0
  182. data/lib/metanorma/document/components/multi_paragraph/quote_block.rb +0 -29
  183. data/lib/metanorma/document/components/multi_paragraph.rb +2 -0
  184. data/lib/metanorma/document/components/reference_elements/source_element.rb +0 -31
  185. data/lib/metanorma/document/components/reference_elements/source_modification.rb +21 -0
  186. data/lib/metanorma/document/components/reference_elements/source_origin.rb +28 -0
  187. data/lib/metanorma/document/components/reference_elements.rb +2 -2
  188. data/lib/metanorma/document/components/tables/col_element.rb +18 -0
  189. data/lib/metanorma/document/components/tables/col_group_element.rb +18 -0
  190. data/lib/metanorma/document/components/tables/table_block.rb +0 -22
  191. data/lib/metanorma/document/components/tables/table_body_section.rb +16 -0
  192. data/lib/metanorma/document/components/tables/table_foot_section.rb +16 -0
  193. data/lib/metanorma/document/components/tables/table_head_section.rb +16 -0
  194. data/lib/metanorma/document/components/tables/table_section.rb +0 -25
  195. data/lib/metanorma/document/components/tables.rb +5 -3
  196. data/lib/metanorma/document/relaton/address.rb +0 -27
  197. data/lib/metanorma/document/relaton/bib_item_locality.rb +3 -12
  198. data/lib/metanorma/document/relaton/copyright_association.rb +0 -10
  199. data/lib/metanorma/document/relaton/copyright_owner.rb +16 -0
  200. data/lib/metanorma/document/relaton/edition.rb +4 -7
  201. data/lib/metanorma/document/relaton/formatted_address.rb +29 -0
  202. data/lib/metanorma/document/relaton/logo_element.rb +18 -0
  203. data/lib/metanorma/document/relaton/organization.rb +0 -14
  204. data/lib/metanorma/document/relaton/phone.rb +3 -9
  205. data/lib/metanorma/document/relaton/place_type.rb +0 -13
  206. data/lib/metanorma/document/relaton/price_type.rb +3 -9
  207. data/lib/metanorma/document/relaton/region_element.rb +18 -0
  208. data/lib/metanorma/document/relaton.rb +6 -1
  209. data/lib/metanorma/document/version.rb +1 -1
  210. data/lib/metanorma/document.rb +2 -0
  211. data/lib/metanorma/html/asset_pipeline.rb +1 -0
  212. data/lib/metanorma/html/base_renderer.rb +261 -1008
  213. data/lib/metanorma/html/bipm_renderer.rb +15 -144
  214. data/lib/metanorma/html/cc_renderer.rb +1 -45
  215. data/lib/metanorma/html/component/base.rb +2 -7
  216. data/lib/metanorma/html/component/index_section.rb +41 -43
  217. data/lib/metanorma/html/drops/admonition_drop.rb +1 -4
  218. data/lib/metanorma/html/drops/biblio_entry_drop.rb +50 -0
  219. data/lib/metanorma/html/drops/block_element_drop.rb +7 -2
  220. data/lib/metanorma/html/drops/example_drop.rb +1 -4
  221. data/lib/metanorma/html/drops/figure_drop.rb +31 -22
  222. data/lib/metanorma/html/drops/footnote_drop.rb +1 -1
  223. data/lib/metanorma/html/drops/formula_drop.rb +45 -16
  224. data/lib/metanorma/html/drops/note_drop.rb +9 -7
  225. data/lib/metanorma/html/drops/sourcecode_drop.rb +12 -5
  226. data/lib/metanorma/html/drops.rb +2 -0
  227. data/lib/metanorma/html/generator.rb +2 -2
  228. data/lib/metanorma/html/icc_renderer.rb +0 -39
  229. data/lib/metanorma/html/iec_renderer.rb +1 -44
  230. data/lib/metanorma/html/ieee_renderer.rb +1 -45
  231. data/lib/metanorma/html/ietf_renderer.rb +1 -48
  232. data/lib/metanorma/html/iho_renderer.rb +1 -46
  233. data/lib/metanorma/html/iso_renderer.rb +290 -343
  234. data/lib/metanorma/html/itu_renderer.rb +1 -45
  235. data/lib/metanorma/html/ogc_renderer.rb +15 -76
  236. data/lib/metanorma/html/oiml_renderer.rb +18 -38
  237. data/lib/metanorma/html/pdfa_renderer.rb +0 -39
  238. data/lib/metanorma/html/renderers/block_renderer.rb +372 -0
  239. data/lib/metanorma/html/renderers/inline_renderer.rb +655 -0
  240. data/lib/metanorma/html/renderers/pubid_renderer.rb +69 -0
  241. data/lib/metanorma/html/renderers/section_renderer.rb +193 -0
  242. data/lib/metanorma/html/renderers.rb +8 -0
  243. data/lib/metanorma/html/ribose_renderer.rb +1 -45
  244. data/lib/metanorma/html/standard_renderer.rb +341 -229
  245. data/lib/metanorma/html/templates/_audio.html.liquid +1 -0
  246. data/lib/metanorma/html/templates/_biblio_entry.html.liquid +1 -0
  247. data/lib/metanorma/html/templates/_bipm_cover.html.liquid +27 -0
  248. data/lib/metanorma/html/templates/_boilerplate.html.liquid +1 -0
  249. data/lib/metanorma/html/templates/_bookmark.html.liquid +1 -0
  250. data/lib/metanorma/html/templates/_br.html.liquid +1 -0
  251. data/lib/metanorma/html/templates/_definition_list.html.liquid +6 -0
  252. data/lib/metanorma/html/templates/_element.html.liquid +1 -0
  253. data/lib/metanorma/html/templates/_fn_marker.html.liquid +1 -0
  254. data/lib/metanorma/html/templates/_footnotes.html.liquid +6 -6
  255. data/lib/metanorma/html/templates/_formula.html.liquid +1 -1
  256. data/lib/metanorma/html/templates/_header.html.liquid +1 -1
  257. data/lib/metanorma/html/templates/_heading.html.liquid +1 -0
  258. data/lib/metanorma/html/templates/_image.html.liquid +1 -0
  259. data/lib/metanorma/html/templates/_inline_span.html.liquid +1 -0
  260. data/lib/metanorma/html/templates/_iso_cover.html.liquid +1 -1
  261. data/lib/metanorma/html/templates/_link.html.liquid +1 -0
  262. data/lib/metanorma/html/templates/_list.html.liquid +3 -0
  263. data/lib/metanorma/html/templates/_list_item.html.liquid +1 -0
  264. data/lib/metanorma/html/templates/_main_content.html.liquid +1 -0
  265. data/lib/metanorma/html/templates/_math_container.html.liquid +1 -0
  266. data/lib/metanorma/html/templates/_paragraph.html.liquid +1 -0
  267. data/lib/metanorma/html/templates/_prefatory_section.html.liquid +1 -0
  268. data/lib/metanorma/html/templates/_pubid_identifier.html.liquid +1 -0
  269. data/lib/metanorma/html/templates/_quote.html.liquid +4 -0
  270. data/lib/metanorma/html/templates/_ref_date.html.liquid +1 -0
  271. data/lib/metanorma/html/templates/_ref_title.html.liquid +1 -0
  272. data/lib/metanorma/html/templates/_section.html.liquid +5 -0
  273. data/lib/metanorma/html/templates/_standard_cover.html.liquid +31 -0
  274. data/lib/metanorma/html/templates/_standard_doc_title.html.liquid +3 -0
  275. data/lib/metanorma/html/templates/_stem_span.html.liquid +1 -0
  276. data/lib/metanorma/html/templates/_table.html.liquid +9 -0
  277. data/lib/metanorma/html/templates/_term_domain.html.liquid +1 -0
  278. data/lib/metanorma/html/templates/_term_example.html.liquid +1 -0
  279. data/lib/metanorma/html/templates/_term_note.html.liquid +1 -0
  280. data/lib/metanorma/html/templates/_term_number.html.liquid +1 -0
  281. data/lib/metanorma/html/templates/_term_source.html.liquid +1 -0
  282. data/lib/metanorma/html/templates/_term_text_note.html.liquid +1 -0
  283. data/lib/metanorma/html/templates/_video.html.liquid +1 -0
  284. data/lib/metanorma/html/templates/_wrapped_preface.html.liquid +1 -0
  285. data/lib/metanorma/html/templates/document.html.liquid +4 -0
  286. data/lib/metanorma/html/theme.rb +180 -107
  287. data/lib/metanorma/html.rb +13 -0
  288. data/lib/metanorma/ietf_document/metadata/ietf_bib_data_extension_type.rb +0 -25
  289. data/lib/metanorma/ietf_document/metadata/pi_settings.rb +32 -0
  290. data/lib/metanorma/ietf_document/metadata.rb +2 -0
  291. data/lib/metanorma/iso_document/metadata/doctype_element.rb +20 -0
  292. data/lib/metanorma/iso_document/metadata/iso_bib_data_extension_type.rb +0 -48
  293. data/lib/metanorma/iso_document/metadata/iso_bibliographic_item.rb +0 -72
  294. data/lib/metanorma/iso_document/metadata/iso_document_status.rb +0 -30
  295. data/lib/metanorma/iso_document/metadata/iso_localized_title.rb +4 -1
  296. data/lib/metanorma/iso_document/metadata/language_element.rb +18 -0
  297. data/lib/metanorma/iso_document/metadata/project_number.rb +22 -0
  298. data/lib/metanorma/iso_document/metadata/script_element.rb +18 -0
  299. data/lib/metanorma/iso_document/metadata/stage_element.rb +26 -0
  300. data/lib/metanorma/iso_document/metadata/stagename_element.rb +18 -0
  301. data/lib/metanorma/iso_document/metadata/structured_identifier.rb +0 -17
  302. data/lib/metanorma/iso_document/metadata/title_collection.rb +1 -0
  303. data/lib/metanorma/iso_document/metadata.rb +9 -4
  304. data/lib/metanorma/iso_document/terms/iso_term.rb +0 -13
  305. data/lib/metanorma/iso_document/terms/term_domain_element.rb +18 -0
  306. data/lib/metanorma/iso_document/terms.rb +1 -0
  307. data/lib/metanorma/itu_document/metadata/itu_bib_data_extension_type.rb +0 -37
  308. data/lib/metanorma/itu_document/metadata/meeting_date.rb +18 -0
  309. data/lib/metanorma/itu_document/metadata/meeting_element.rb +18 -0
  310. data/lib/metanorma/itu_document/metadata/study_period.rb +18 -0
  311. data/lib/metanorma/itu_document/metadata.rb +3 -4
  312. data/lib/metanorma/mirror/default_registry.rb +170 -0
  313. data/lib/metanorma/mirror/handler_registry.rb +60 -0
  314. data/lib/metanorma/mirror/handler_result.rb +37 -0
  315. data/lib/metanorma/mirror/handlers/admonition.rb +18 -0
  316. data/lib/metanorma/mirror/handlers/example.rb +21 -0
  317. data/lib/metanorma/mirror/handlers/figure.rb +53 -0
  318. data/lib/metanorma/mirror/handlers/formula.rb +35 -0
  319. data/lib/metanorma/mirror/handlers/inline/rich_html_renderer.rb +159 -0
  320. data/lib/metanorma/mirror/handlers/inline/text_extractor.rb +116 -0
  321. data/lib/metanorma/mirror/handlers/inline.rb +225 -0
  322. data/lib/metanorma/mirror/handlers/list.rb +110 -0
  323. data/lib/metanorma/mirror/handlers/note.rb +26 -0
  324. data/lib/metanorma/mirror/handlers/paragraph.rb +19 -0
  325. data/lib/metanorma/mirror/handlers/quote.rb +16 -0
  326. data/lib/metanorma/mirror/handlers/review.rb +19 -0
  327. data/lib/metanorma/mirror/handlers/section.rb +149 -0
  328. data/lib/metanorma/mirror/handlers/sourcecode.rb +27 -0
  329. data/lib/metanorma/mirror/handlers/structural.rb +68 -0
  330. data/lib/metanorma/mirror/handlers/table.rb +81 -0
  331. data/lib/metanorma/mirror/handlers/term.rb +100 -0
  332. data/lib/metanorma/mirror/handlers.rb +60 -0
  333. data/lib/metanorma/mirror/id_strategy/positional.rb +166 -0
  334. data/lib/metanorma/mirror/id_strategy/preserve.rb +12 -0
  335. data/lib/metanorma/mirror/id_strategy.rb +34 -0
  336. data/lib/metanorma/mirror/math_util.rb +53 -0
  337. data/lib/metanorma/mirror/metadata.rb +37 -0
  338. data/lib/metanorma/mirror/metanorma_to_mirror.rb +101 -0
  339. data/lib/metanorma/mirror/model/container.rb +47 -0
  340. data/lib/metanorma/mirror/model/factory.rb +52 -0
  341. data/lib/metanorma/mirror/model/guide.rb +25 -0
  342. data/lib/metanorma/mirror/model/leaf.rb +17 -0
  343. data/lib/metanorma/mirror/model/mark.rb +53 -0
  344. data/lib/metanorma/mirror/model/node.rb +47 -0
  345. data/lib/metanorma/mirror/model/soft_break.rb +33 -0
  346. data/lib/metanorma/mirror/model/text.rb +34 -0
  347. data/lib/metanorma/mirror/model.rb +16 -0
  348. data/lib/metanorma/mirror/output/builder.rb +39 -0
  349. data/lib/metanorma/mirror/output/formats/base_format.rb +90 -0
  350. data/lib/metanorma/mirror/output/formats/inline_format.rb +81 -0
  351. data/lib/metanorma/mirror/output/formats.rb +53 -0
  352. data/lib/metanorma/mirror/output/html_renderer.rb +95 -0
  353. data/lib/metanorma/mirror/output/html_renderers/block_renderers.rb +178 -0
  354. data/lib/metanorma/mirror/output/html_renderers/inline_renderer.rb +61 -0
  355. data/lib/metanorma/mirror/output/html_renderers/list_renderers.rb +96 -0
  356. data/lib/metanorma/mirror/output/html_renderers/mark_renderers.rb +64 -0
  357. data/lib/metanorma/mirror/output/html_renderers/section_renderers.rb +129 -0
  358. data/lib/metanorma/mirror/output/html_renderers/structural_renderers.rb +80 -0
  359. data/lib/metanorma/mirror/output/html_renderers/table_renderers.rb +87 -0
  360. data/lib/metanorma/mirror/output/html_renderers.rb +76 -0
  361. data/lib/metanorma/mirror/output/pipeline.rb +92 -0
  362. data/lib/metanorma/mirror/output/pipeline_context.rb +22 -0
  363. data/lib/metanorma/mirror/output.rb +14 -0
  364. data/lib/metanorma/mirror/rewriter.rb +121 -0
  365. data/lib/metanorma/mirror/safe_attr.rb +16 -0
  366. data/lib/metanorma/mirror/serialization/json_serializer.rb +25 -0
  367. data/lib/metanorma/mirror/serialization/yaml_serializer.rb +20 -0
  368. data/lib/metanorma/mirror/serialization.rb +10 -0
  369. data/lib/metanorma/mirror/transformer.rb +22 -0
  370. data/lib/metanorma/mirror.rb +32 -0
  371. data/lib/metanorma/standard_document/annotation.rb +37 -0
  372. data/lib/metanorma/standard_document/block_attributes.rb +15 -2
  373. data/lib/metanorma/standard_document/blocks/block_source.rb +0 -23
  374. data/lib/metanorma/standard_document/blocks/source_origin_element.rb +23 -0
  375. data/lib/metanorma/standard_document/blocks.rb +1 -1
  376. data/lib/metanorma/standard_document/terms/term_expression.rb +0 -31
  377. data/lib/metanorma/standard_document/terms/term_name_element.rb +29 -0
  378. data/lib/metanorma/standard_document/terms.rb +1 -0
  379. data/script/render_both.rb +18 -0
  380. metadata +262 -13
  381. data/.github/workflows/rake.yml +0 -21
  382. data/.github/workflows/release.yml +0 -25
  383. data/.github/workflows/roundtrip-samples.yml +0 -132
  384. data/.gitignore +0 -19
  385. data/.rspec +0 -3
  386. data/.rubocop.yml +0 -22
  387. data/Gemfile +0 -28
  388. data/bin/console +0 -15
  389. data/bin/setup +0 -8
  390. data/metanorma-document.gemspec +0 -35
@@ -0,0 +1,172 @@
1
+ import { describe, it, expect } from 'vitest'
2
+ import {
3
+ MARK_TYPES,
4
+ SECTION_TYPES,
5
+ BLOCK_TYPES,
6
+ BLOCK_NODE_TYPES,
7
+ SECTION_NODE_TYPES,
8
+ ALL_NODE_TYPES,
9
+ } from '../rendering-contract'
10
+ import { getBlockComponent } from '../../components/blocks'
11
+ import { SECTION_TYPES as UI_SECTION_TYPES, SECTION_META } from '../../utils/typeMetadata'
12
+ import ParagraphBlock from '../../components/blocks/ParagraphBlock.vue'
13
+ import AdmonitionBlock from '../../components/blocks/AdmonitionBlock.vue'
14
+ import TableBlock from '../../components/blocks/TableBlock.vue'
15
+ import FigureBlock from '../../components/blocks/FigureBlock.vue'
16
+ import SourcecodeBlock from '../../components/blocks/SourcecodeBlock.vue'
17
+ import NoteBlock from '../../components/blocks/NoteBlock.vue'
18
+ import ExampleBlock from '../../components/blocks/ExampleBlock.vue'
19
+ import ListBlocks from '../../components/blocks/ListBlocks.vue'
20
+ import QuoteBlock from '../../components/blocks/QuoteBlock.vue'
21
+ import ReviewBlock from '../../components/blocks/ReviewBlock.vue'
22
+ import FootnotesBlock from '../../components/blocks/FootnotesBlock.vue'
23
+ import FallbackBlock from '../../components/blocks/FallbackBlock.vue'
24
+
25
+ describe('rendering-contract', () => {
26
+ describe('MARK_TYPES', () => {
27
+ it('covers all marks produced by Ruby Mirror::Mark subclasses', () => {
28
+ const expected = [
29
+ 'emphasis', 'strong', 'subscript', 'superscript',
30
+ 'code', 'underline', 'strike', 'smallcap',
31
+ 'link', 'xref', 'eref', 'footnote',
32
+ 'stem', 'concept', 'bcp14', 'span',
33
+ ]
34
+ for (const mark of expected) {
35
+ expect(MARK_TYPES).toContain(mark)
36
+ }
37
+ })
38
+
39
+ it('has no duplicates', () => {
40
+ expect(MARK_TYPES.length).toBe(new Set(MARK_TYPES).size)
41
+ })
42
+ })
43
+
44
+ describe('SECTION_TYPES', () => {
45
+ it('matches UI typeMetadata SECTION_TYPES set', () => {
46
+ for (const t of SECTION_TYPES) {
47
+ expect(UI_SECTION_TYPES.has(t), `contract section type "${t}" missing from UI SECTION_TYPES`).toBe(true)
48
+ }
49
+ })
50
+
51
+ it('has metadata for every section type', () => {
52
+ for (const t of SECTION_TYPES) {
53
+ expect(SECTION_META[t], `SECTION_META missing for "${t}"`).toBeDefined()
54
+ }
55
+ })
56
+
57
+ it('every section type has tag and headingTag', () => {
58
+ for (const t of SECTION_TYPES) {
59
+ const meta = SECTION_META[t]
60
+ expect(meta.tag, `${t} should have tag`).toMatch(/^(section|article)$/)
61
+ expect(meta.headingTag, `${t} should have headingTag`).toBeTruthy()
62
+ }
63
+ })
64
+ })
65
+
66
+ describe('BLOCK_TYPES', () => {
67
+ it('every block type has a registered Vue component', () => {
68
+ for (const spec of BLOCK_TYPES) {
69
+ const component = getBlockComponent(spec.nodeType)
70
+ expect(component).not.toBe(FallbackBlock)
71
+ expect(component, `block type "${spec.nodeType}" should have a component`).toBeDefined()
72
+ }
73
+ })
74
+
75
+ it('every block type spec has required fields', () => {
76
+ for (const spec of BLOCK_TYPES) {
77
+ expect(spec.nodeType, 'nodeType should be set').toBeTruthy()
78
+ expect(spec.rubyCssClass, `${spec.nodeType} should have rubyCssClass`).toBeTruthy()
79
+ expect(spec.children, `${spec.nodeType} should define children kind`).toMatch(/^(inline|block|mixed|none)$/)
80
+ expect(Array.isArray(spec.attrs), `${spec.nodeType} attrs should be array`).toBe(true)
81
+ }
82
+ })
83
+ })
84
+
85
+ describe('BLOCK_NODE_TYPES set', () => {
86
+ it('contains all node types from BLOCK_TYPES', () => {
87
+ for (const spec of BLOCK_TYPES) {
88
+ expect(BLOCK_NODE_TYPES.has(spec.nodeType)).toBe(true)
89
+ }
90
+ })
91
+
92
+ it('does not contain section types', () => {
93
+ for (const t of SECTION_TYPES) {
94
+ expect(BLOCK_NODE_TYPES.has(t), `section type "${t}" should not be in BLOCK_NODE_TYPES`).toBe(false)
95
+ }
96
+ })
97
+ })
98
+
99
+ describe('SECTION_NODE_TYPES set', () => {
100
+ it('contains all section types', () => {
101
+ for (const t of SECTION_TYPES) {
102
+ expect(SECTION_NODE_TYPES.has(t)).toBe(true)
103
+ }
104
+ })
105
+ })
106
+
107
+ describe('ALL_NODE_TYPES set', () => {
108
+ it('includes structural node types', () => {
109
+ expect(ALL_NODE_TYPES.has('doc')).toBe(true)
110
+ expect(ALL_NODE_TYPES.has('text')).toBe(true)
111
+ expect(ALL_NODE_TYPES.has('soft_break')).toBe(true)
112
+ expect(ALL_NODE_TYPES.has('footnote_marker')).toBe(true)
113
+ })
114
+
115
+ it('includes table structural types', () => {
116
+ expect(ALL_NODE_TYPES.has('table_head')).toBe(true)
117
+ expect(ALL_NODE_TYPES.has('table_body')).toBe(true)
118
+ expect(ALL_NODE_TYPES.has('table_row')).toBe(true)
119
+ expect(ALL_NODE_TYPES.has('table_cell')).toBe(true)
120
+ })
121
+
122
+ it('includes list structural types', () => {
123
+ expect(ALL_NODE_TYPES.has('list_item')).toBe(true)
124
+ expect(ALL_NODE_TYPES.has('dt')).toBe(true)
125
+ expect(ALL_NODE_TYPES.has('dd')).toBe(true)
126
+ })
127
+
128
+ it('covers all section and block types', () => {
129
+ for (const t of SECTION_TYPES) {
130
+ expect(ALL_NODE_TYPES.has(t), `missing section type ${t}`).toBe(true)
131
+ }
132
+ for (const spec of BLOCK_TYPES) {
133
+ expect(ALL_NODE_TYPES.has(spec.nodeType), `missing block type ${spec.nodeType}`).toBe(true)
134
+ }
135
+ })
136
+ })
137
+
138
+ describe('block component mapping coverage', () => {
139
+ const expectedMappings: Record<string, any> = {
140
+ paragraph: ParagraphBlock,
141
+ admonition: AdmonitionBlock,
142
+ note: NoteBlock,
143
+ example: ExampleBlock,
144
+ table: TableBlock,
145
+ figure: FigureBlock,
146
+ image: FigureBlock,
147
+ sourcecode: SourcecodeBlock,
148
+ formula: SourcecodeBlock,
149
+ bullet_list: ListBlocks,
150
+ ordered_list: ListBlocks,
151
+ dl: ListBlocks,
152
+ quote: QuoteBlock,
153
+ review: ReviewBlock,
154
+ footnotes: FootnotesBlock,
155
+ floating_title: ParagraphBlock,
156
+ }
157
+
158
+ for (const [type, expected] of Object.entries(expectedMappings)) {
159
+ it(`maps "${type}" to ${expected.__name || expected.name}`, () => {
160
+ expect(getBlockComponent(type)).toBe(expected)
161
+ })
162
+ }
163
+
164
+ it('returns FallbackBlock for unknown types', () => {
165
+ expect(getBlockComponent('unknown_block')).toBe(FallbackBlock)
166
+ })
167
+
168
+ it('returns FallbackBlock for empty string', () => {
169
+ expect(getBlockComponent('')).toBe(FallbackBlock)
170
+ })
171
+ })
172
+ })
@@ -0,0 +1,209 @@
1
+ /**
2
+ * Rendering contract between Ruby HtmlRenderer and Vue MirrorRenderer.
3
+ *
4
+ * Single source of truth for the mirror node format.
5
+ * Both renderers must handle every node type listed here.
6
+ *
7
+ * When adding a new block type:
8
+ * 1. Add it to BLOCK_TYPES below
9
+ * 2. Implement render_{type} in Ruby HtmlRenderer
10
+ * 3. Add a Vue block component and register it in blocks/index.ts
11
+ * 4. Update the cross-validation spec
12
+ */
13
+
14
+ // ── Inline mark types ──────────────────────────────────────────────
15
+
16
+ export const MARK_TYPES = [
17
+ 'emphasis',
18
+ 'strong',
19
+ 'subscript',
20
+ 'superscript',
21
+ 'code',
22
+ 'underline',
23
+ 'strike',
24
+ 'smallcap',
25
+ 'link',
26
+ 'xref',
27
+ 'eref',
28
+ 'footnote',
29
+ 'stem',
30
+ 'concept',
31
+ 'bcp14',
32
+ 'span',
33
+ ] as const
34
+
35
+ export type MarkType = (typeof MARK_TYPES)[number]
36
+
37
+ // ── Section types (rendered by ClauseBlock) ───────────────────────
38
+
39
+ export const SECTION_TYPES = [
40
+ 'clause',
41
+ 'annex',
42
+ 'content_section',
43
+ 'abstract',
44
+ 'foreword',
45
+ 'introduction',
46
+ 'acknowledgements',
47
+ 'terms',
48
+ 'definitions',
49
+ 'references',
50
+ 'bibliography',
51
+ 'preface',
52
+ 'sections',
53
+ ] as const
54
+
55
+ export type SectionType = (typeof SECTION_TYPES)[number]
56
+
57
+ // ── Block type specification ───────────────────────────────────────
58
+
59
+ export type ChildrenKind = 'inline' | 'block' | 'mixed' | 'none'
60
+
61
+ export interface BlockTypeSpec {
62
+ /** Mirror node type string */
63
+ nodeType: string
64
+ /** Primary CSS class used by Ruby HtmlRenderer */
65
+ rubyCssClass: string
66
+ /** Expected attrs keys (excluding id which is universal) */
67
+ attrs: string[]
68
+ /** What kind of children this node contains */
69
+ children: ChildrenKind
70
+ }
71
+
72
+ export const BLOCK_TYPES: BlockTypeSpec[] = [
73
+ // ── Prose ──
74
+ {
75
+ nodeType: 'paragraph',
76
+ rubyCssClass: 'mn-paragraph',
77
+ attrs: ['id'],
78
+ children: 'inline',
79
+ },
80
+ {
81
+ nodeType: 'floating_title',
82
+ rubyCssClass: 'mn-floating-title',
83
+ attrs: ['id', 'title', 'level'],
84
+ children: 'none',
85
+ },
86
+ {
87
+ nodeType: 'quote',
88
+ rubyCssClass: 'mn-quote',
89
+ attrs: ['id'],
90
+ children: 'block',
91
+ },
92
+ {
93
+ nodeType: 'review',
94
+ rubyCssClass: 'mn-review',
95
+ attrs: ['id', 'review_type', 'reviewer', 'date'],
96
+ children: 'block',
97
+ },
98
+
99
+ // ── Code ──
100
+ {
101
+ nodeType: 'sourcecode',
102
+ rubyCssClass: 'mn-sourcecode',
103
+ attrs: ['id', 'language', 'text', 'title'],
104
+ children: 'none',
105
+ },
106
+
107
+ // ── Admonition ──
108
+ {
109
+ nodeType: 'admonition',
110
+ rubyCssClass: 'mn-admonition',
111
+ attrs: ['id', 'type', 'title'],
112
+ children: 'block',
113
+ },
114
+ {
115
+ nodeType: 'note',
116
+ rubyCssClass: 'mn-note',
117
+ attrs: ['id', 'type', 'title'],
118
+ children: 'block',
119
+ },
120
+ {
121
+ nodeType: 'example',
122
+ rubyCssClass: 'mn-example',
123
+ attrs: ['id', 'type', 'title'],
124
+ children: 'block',
125
+ },
126
+
127
+ // ── Media ──
128
+ {
129
+ nodeType: 'figure',
130
+ rubyCssClass: 'mn-figure',
131
+ attrs: ['id', 'title'],
132
+ children: 'block',
133
+ },
134
+ {
135
+ nodeType: 'image',
136
+ rubyCssClass: 'mn-image',
137
+ attrs: ['id', 'src', 'alt', 'title'],
138
+ children: 'none',
139
+ },
140
+
141
+ // ── Table ──
142
+ {
143
+ nodeType: 'table',
144
+ rubyCssClass: 'mn-table',
145
+ attrs: ['id', 'title'],
146
+ children: 'block',
147
+ },
148
+
149
+ // ── Lists ──
150
+ {
151
+ nodeType: 'ordered_list',
152
+ rubyCssClass: 'mn-ordered-list',
153
+ attrs: ['id'],
154
+ children: 'block',
155
+ },
156
+ {
157
+ nodeType: 'bullet_list',
158
+ rubyCssClass: 'mn-bullet-list',
159
+ attrs: ['id'],
160
+ children: 'block',
161
+ },
162
+ {
163
+ nodeType: 'dl',
164
+ rubyCssClass: 'mn-definition-list',
165
+ attrs: ['id'],
166
+ children: 'block',
167
+ },
168
+
169
+ // ── Formula ──
170
+ {
171
+ nodeType: 'formula',
172
+ rubyCssClass: 'mn-formula',
173
+ attrs: ['id', 'text'],
174
+ children: 'none',
175
+ },
176
+
177
+ // ── Footnotes ──
178
+ {
179
+ nodeType: 'footnotes',
180
+ rubyCssClass: 'mn-footnotes',
181
+ attrs: [],
182
+ children: 'block',
183
+ },
184
+ ]
185
+
186
+ // ── Derived lookup maps ────────────────────────────────────────────
187
+
188
+ /** All block node types handled by the block component registry */
189
+ export const BLOCK_NODE_TYPES: Set<string> = new Set(BLOCK_TYPES.map((b) => b.nodeType))
190
+
191
+ /** All section node types handled by ClauseBlock */
192
+ export const SECTION_NODE_TYPES: Set<string> = new Set(SECTION_TYPES)
193
+
194
+ /** Complete set of all rendered node types */
195
+ export const ALL_NODE_TYPES: Set<string> = new Set([
196
+ ...SECTION_TYPES,
197
+ ...BLOCK_TYPES.map((b) => b.nodeType),
198
+ 'doc',
199
+ 'soft_break',
200
+ 'text',
201
+ 'footnote_marker',
202
+ 'list_item',
203
+ 'dt',
204
+ 'dd',
205
+ 'table_head',
206
+ 'table_body',
207
+ 'table_row',
208
+ 'table_cell',
209
+ ])
@@ -0,0 +1,102 @@
1
+ import { describe, it, expect } from 'vitest'
2
+ import { SECTION_TYPES, isSectionType, SECTION_META, getTypeLabel, getTypeBadgeClass } from '../typeMetadata'
3
+ import { SECTION_TYPES as CONTRACT_SECTIONS } from '../../types/rendering-contract'
4
+
5
+ describe('isSectionType', () => {
6
+ it('returns true for section-like types', () => {
7
+ const types = ['clause', 'annex', 'content_section', 'abstract', 'foreword',
8
+ 'introduction', 'acknowledgements', 'terms', 'definitions',
9
+ 'references', 'bibliography', 'preface', 'sections']
10
+
11
+ for (const t of types) {
12
+ expect(isSectionType(t)).toBe(true)
13
+ }
14
+ })
15
+
16
+ it('returns false for non-section types', () => {
17
+ expect(isSectionType('paragraph')).toBe(false)
18
+ expect(isSectionType('sourcecode')).toBe(false)
19
+ expect(isSectionType('figure')).toBe(false)
20
+ expect(isSectionType('table')).toBe(false)
21
+ expect(isSectionType('admonition')).toBe(false)
22
+ expect(isSectionType('bullet_list')).toBe(false)
23
+ })
24
+
25
+ it('matches rendering contract SECTION_TYPES', () => {
26
+ for (const t of CONTRACT_SECTIONS) {
27
+ expect(isSectionType(t), `contract type "${t}" not in UI SECTION_TYPES`).toBe(true)
28
+ }
29
+ })
30
+ })
31
+
32
+ describe('SECTION_META', () => {
33
+ it('defines metadata for all section types', () => {
34
+ for (const type of SECTION_TYPES) {
35
+ expect(SECTION_META[type], `${type} should have SECTION_META entry`).toBeDefined()
36
+ }
37
+ })
38
+
39
+ it('all entries have tag and headingTag', () => {
40
+ for (const [type, meta] of Object.entries(SECTION_META)) {
41
+ expect(meta.tag, `${type} should have tag`).toMatch(/^section$/)
42
+ expect(meta.headingTag, `${type} should have headingTag`).toBeTruthy()
43
+ expect(meta.headingClass, `${type} should have headingClass`).toBeTruthy()
44
+ }
45
+ })
46
+
47
+ it('clause uses h2', () => {
48
+ expect(SECTION_META.clause.headingTag).toBe('h2')
49
+ })
50
+
51
+ it('annex uses h2', () => {
52
+ expect(SECTION_META.annex.headingTag).toBe('h2')
53
+ })
54
+
55
+ it('preface uses h1', () => {
56
+ expect(SECTION_META.preface.headingTag).toBe('h1')
57
+ })
58
+
59
+ it('sections uses h1', () => {
60
+ expect(SECTION_META.sections.headingTag).toBe('h1')
61
+ })
62
+ })
63
+
64
+ describe('getTypeLabel', () => {
65
+ it('returns non-empty for major types', () => {
66
+ expect(getTypeLabel('clause')).toBeTruthy()
67
+ expect(getTypeLabel('annex')).toBeTruthy()
68
+ expect(getTypeLabel('terms')).toBeTruthy()
69
+ expect(getTypeLabel('references')).toBeTruthy()
70
+ })
71
+
72
+ it('returns empty for unknown', () => {
73
+ expect(getTypeLabel('foobar')).toBe('')
74
+ })
75
+ })
76
+
77
+ describe('getTypeBadgeClass', () => {
78
+ it('returns badge-neutral for unknown', () => {
79
+ expect(getTypeBadgeClass('foobar')).toBe('badge-neutral')
80
+ })
81
+
82
+ it('returns different classes for different types', () => {
83
+ const classes = new Set([
84
+ getTypeBadgeClass('clause'),
85
+ getTypeBadgeClass('annex'),
86
+ getTypeBadgeClass('terms'),
87
+ ])
88
+ expect(classes.size).toBeGreaterThan(1)
89
+ })
90
+
91
+ it('returns badge-accent for clause', () => {
92
+ expect(getTypeBadgeClass('clause')).toBe('badge-accent')
93
+ })
94
+
95
+ it('returns badge-info for terms', () => {
96
+ expect(getTypeBadgeClass('terms')).toBe('badge-info')
97
+ })
98
+
99
+ it('returns badge-reference for references', () => {
100
+ expect(getTypeBadgeClass('references')).toBe('badge-reference')
101
+ })
102
+ })
@@ -0,0 +1,121 @@
1
+ /**
2
+ * Canonical metadata for Metanorma section/block types.
3
+ */
4
+
5
+ export const SECTION_TYPES = new Set([
6
+ 'clause', 'annex', 'content_section', 'abstract', 'foreword',
7
+ 'introduction', 'acknowledgements', 'terms', 'definitions',
8
+ 'references', 'bibliography', 'preface', 'sections',
9
+ ])
10
+
11
+ export function isSectionType(type: string): boolean {
12
+ return SECTION_TYPES.has(type)
13
+ }
14
+
15
+ export interface SectionMeta {
16
+ tag: 'section' | 'article'
17
+ headingTag: string
18
+ headingClass: string
19
+ noAnchor?: boolean
20
+ noNumbering?: boolean
21
+ }
22
+
23
+ export const SECTION_META: Record<string, SectionMeta> = {
24
+ clause: {
25
+ tag: 'section',
26
+ headingTag: 'h2',
27
+ headingClass: 'text-xl font-semibold mb-3',
28
+ },
29
+ annex: {
30
+ tag: 'section',
31
+ headingTag: 'h2',
32
+ headingClass: 'text-xl font-semibold mb-3',
33
+ },
34
+ content_section: {
35
+ tag: 'section',
36
+ headingTag: 'h2',
37
+ headingClass: 'text-xl font-semibold mb-3',
38
+ },
39
+ abstract: {
40
+ tag: 'section',
41
+ headingTag: 'h2',
42
+ headingClass: 'text-lg font-semibold mb-3 italic',
43
+ },
44
+ foreword: {
45
+ tag: 'section',
46
+ headingTag: 'h2',
47
+ headingClass: 'text-xl font-semibold mb-3',
48
+ },
49
+ introduction: {
50
+ tag: 'section',
51
+ headingTag: 'h2',
52
+ headingClass: 'text-xl font-semibold mb-3',
53
+ },
54
+ acknowledgements: {
55
+ tag: 'section',
56
+ headingTag: 'h2',
57
+ headingClass: 'text-xl font-semibold mb-3',
58
+ },
59
+ terms: {
60
+ tag: 'section',
61
+ headingTag: 'h2',
62
+ headingClass: 'text-xl font-semibold mb-3',
63
+ },
64
+ definitions: {
65
+ tag: 'section',
66
+ headingTag: 'h2',
67
+ headingClass: 'text-xl font-semibold mb-3',
68
+ },
69
+ references: {
70
+ tag: 'section',
71
+ headingTag: 'h2',
72
+ headingClass: 'text-xl font-semibold mb-3',
73
+ },
74
+ bibliography: {
75
+ tag: 'section',
76
+ headingTag: 'h2',
77
+ headingClass: 'text-xl font-semibold mb-3',
78
+ },
79
+ preface: {
80
+ tag: 'section',
81
+ headingTag: 'h1',
82
+ headingClass: 'text-2xl font-bold mb-4',
83
+ },
84
+ sections: {
85
+ tag: 'section',
86
+ headingTag: 'h1',
87
+ headingClass: 'text-2xl font-bold mb-4',
88
+ },
89
+ }
90
+
91
+ export function getTypeBadgeClass(type: string): string {
92
+ switch (type) {
93
+ case 'clause': return 'badge-accent'
94
+ case 'annex': return 'badge-warning'
95
+ case 'terms': return 'badge-info'
96
+ case 'definitions': return 'badge-info'
97
+ case 'references': return 'badge-reference'
98
+ case 'bibliography': return 'badge-reference'
99
+ case 'abstract': return 'badge-neutral'
100
+ case 'foreword': return 'badge-neutral'
101
+ case 'introduction': return 'badge-neutral'
102
+ case 'acknowledgements': return 'badge-neutral'
103
+ default: return 'badge-neutral'
104
+ }
105
+ }
106
+
107
+ export function getTypeLabel(type: string): string {
108
+ switch (type) {
109
+ case 'clause': return '§'
110
+ case 'annex': return 'Annex'
111
+ case 'terms': return 'Terms'
112
+ case 'definitions': return 'Def'
113
+ case 'references': return 'Ref'
114
+ case 'bibliography': return 'Bib'
115
+ case 'abstract': return 'Abs'
116
+ case 'foreword': return 'Fwd'
117
+ case 'introduction': return 'Intro'
118
+ case 'acknowledgements': return 'Ack'
119
+ default: return ''
120
+ }
121
+ }
@@ -0,0 +1,18 @@
1
+ /** @type {import('tailwindcss').Config} */
2
+ export default {
3
+ content: [
4
+ './src/**/*.{vue,ts,html}',
5
+ ],
6
+ darkMode: 'class',
7
+ theme: {
8
+ extend: {
9
+ colors: {
10
+ cream: '#faf8f5',
11
+ charcoal: '#2d2d2d',
12
+ teal: '#0d9488',
13
+ navy: '#1e3a5f'
14
+ }
15
+ }
16
+ },
17
+ plugins: [],
18
+ }