docbook 0.1.0

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 (271) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +5 -0
  3. data/CLAUDE.md +19 -0
  4. data/CODE_OF_CONDUCT.md +10 -0
  5. data/README.adoc +335 -0
  6. data/Rakefile +12 -0
  7. data/docs/.lycheeignore +33 -0
  8. data/docs/Gemfile +10 -0
  9. data/docs/INDEX.adoc +67 -0
  10. data/docs/_config.yml +186 -0
  11. data/docs/advanced/element-classes.adoc +185 -0
  12. data/docs/advanced/frontend-customization.adoc +193 -0
  13. data/docs/advanced/index.adoc +14 -0
  14. data/docs/advanced/templates.adoc +123 -0
  15. data/docs/features/element-coverage.adoc +373 -0
  16. data/docs/features/html-output/data-model.adoc +285 -0
  17. data/docs/features/html-output/directory-mode.adoc +180 -0
  18. data/docs/features/html-output/index.adoc +90 -0
  19. data/docs/features/html-output/single-file-mode.adoc +125 -0
  20. data/docs/features/index-generation.adoc +197 -0
  21. data/docs/features/index.adoc +63 -0
  22. data/docs/features/numbering.adoc +183 -0
  23. data/docs/features/toc-generation.adoc +150 -0
  24. data/docs/features/xinclude/fragid-schemes.adoc +287 -0
  25. data/docs/features/xinclude/index.adoc +119 -0
  26. data/docs/features/xinclude/text-includes.adoc +123 -0
  27. data/docs/features/xinclude/xml-includes.adoc +167 -0
  28. data/docs/getting-started/index.adoc +50 -0
  29. data/docs/getting-started/installation.adoc +113 -0
  30. data/docs/getting-started/quick-start.adoc +161 -0
  31. data/docs/guides/converting-article.adoc +188 -0
  32. data/docs/guides/converting-book.adoc +192 -0
  33. data/docs/guides/index.adoc +12 -0
  34. data/docs/guides/roundtrip-testing.adoc +129 -0
  35. data/docs/interfaces/cli/format-command.adoc +109 -0
  36. data/docs/interfaces/cli/index.adoc +73 -0
  37. data/docs/interfaces/cli/roundtrip-command.adoc +125 -0
  38. data/docs/interfaces/cli/to-html-command.adoc +178 -0
  39. data/docs/interfaces/cli/validate-command.adoc +104 -0
  40. data/docs/interfaces/index.adoc +101 -0
  41. data/docs/interfaces/ruby-api/html-output.adoc +186 -0
  42. data/docs/interfaces/ruby-api/index.adoc +111 -0
  43. data/docs/interfaces/ruby-api/parsing.adoc +202 -0
  44. data/docs/interfaces/ruby-api/xinclude.adoc +162 -0
  45. data/docs/interfaces/ruby-api/xref-resolution.adoc +156 -0
  46. data/docs/lychee.toml +42 -0
  47. data/docs/reference/cli-options.adoc +155 -0
  48. data/docs/reference/content-block-types.adoc +243 -0
  49. data/docs/reference/glossary.adoc +119 -0
  50. data/docs/reference/index.adoc +12 -0
  51. data/docs/reference/supported-elements.adoc +749 -0
  52. data/docs/understanding/architecture.adoc +145 -0
  53. data/docs/understanding/content-pipeline.adoc +102 -0
  54. data/docs/understanding/data-models.adoc +156 -0
  55. data/docs/understanding/index.adoc +34 -0
  56. data/exe/docbook +7 -0
  57. data/frontend/dist/app.css +1 -0
  58. data/frontend/dist/app.iife.js +24 -0
  59. data/frontend/package-lock.json +1445 -0
  60. data/frontend/package.json +22 -0
  61. data/frontend/src/App.vue +230 -0
  62. data/frontend/src/app.ts +8 -0
  63. data/frontend/src/components/AppSidebar.vue +116 -0
  64. data/frontend/src/components/AppendixSection.vue +39 -0
  65. data/frontend/src/components/BlockRenderer.vue +358 -0
  66. data/frontend/src/components/ChapterSection.vue +32 -0
  67. data/frontend/src/components/ContentRenderer.vue +13 -0
  68. data/frontend/src/components/EbookContainer.vue +147 -0
  69. data/frontend/src/components/EbookTopBar.vue +116 -0
  70. data/frontend/src/components/PartSection.vue +44 -0
  71. data/frontend/src/components/ReferenceEntry.vue +80 -0
  72. data/frontend/src/components/SearchModal.vue +286 -0
  73. data/frontend/src/components/SectionContent.vue +31 -0
  74. data/frontend/src/components/SettingsPanel.vue +236 -0
  75. data/frontend/src/components/TocTreeItem.vue +135 -0
  76. data/frontend/src/composables/useEbookStore.ts +191 -0
  77. data/frontend/src/composables/useSearch.ts +249 -0
  78. data/frontend/src/env.d.ts +7 -0
  79. data/frontend/src/stores/documentStore.ts +221 -0
  80. data/frontend/src/stores/uiStore.ts +98 -0
  81. data/frontend/src/styles.css +253 -0
  82. data/frontend/tsconfig.json +24 -0
  83. data/frontend/tsconfig.node.json +11 -0
  84. data/frontend/vite.config.ts +30 -0
  85. data/lib/docbook/cli.rb +123 -0
  86. data/lib/docbook/document.rb +67 -0
  87. data/lib/docbook/elements/abbrev.rb +16 -0
  88. data/lib/docbook/elements/acknowledgements.rb +22 -0
  89. data/lib/docbook/elements/address.rb +18 -0
  90. data/lib/docbook/elements/alt.rb +16 -0
  91. data/lib/docbook/elements/annotation.rb +18 -0
  92. data/lib/docbook/elements/appendix.rb +34 -0
  93. data/lib/docbook/elements/article.rb +31 -0
  94. data/lib/docbook/elements/att.rb +15 -0
  95. data/lib/docbook/elements/attribution.rb +20 -0
  96. data/lib/docbook/elements/audioobject.rb +18 -0
  97. data/lib/docbook/elements/author.rb +18 -0
  98. data/lib/docbook/elements/bibliography.rb +24 -0
  99. data/lib/docbook/elements/bibliomixed.rb +40 -0
  100. data/lib/docbook/elements/biblioref.rb +20 -0
  101. data/lib/docbook/elements/blockquote.rb +26 -0
  102. data/lib/docbook/elements/book.rb +36 -0
  103. data/lib/docbook/elements/buildtarget.rb +16 -0
  104. data/lib/docbook/elements/callout.rb +22 -0
  105. data/lib/docbook/elements/calloutlist.rb +22 -0
  106. data/lib/docbook/elements/caution.rb +30 -0
  107. data/lib/docbook/elements/chapter.rb +62 -0
  108. data/lib/docbook/elements/citation.rb +16 -0
  109. data/lib/docbook/elements/citerefentry.rb +26 -0
  110. data/lib/docbook/elements/citetitle.rb +20 -0
  111. data/lib/docbook/elements/classname.rb +16 -0
  112. data/lib/docbook/elements/code.rb +16 -0
  113. data/lib/docbook/elements/colophon.rb +22 -0
  114. data/lib/docbook/elements/computeroutput.rb +18 -0
  115. data/lib/docbook/elements/copyright.rb +17 -0
  116. data/lib/docbook/elements/danger.rb +28 -0
  117. data/lib/docbook/elements/date.rb +16 -0
  118. data/lib/docbook/elements/dedication.rb +22 -0
  119. data/lib/docbook/elements/dir.rb +16 -0
  120. data/lib/docbook/elements/emphasis.rb +18 -0
  121. data/lib/docbook/elements/entry.rb +30 -0
  122. data/lib/docbook/elements/entrytbl.rb +22 -0
  123. data/lib/docbook/elements/equation.rb +26 -0
  124. data/lib/docbook/elements/example.rb +30 -0
  125. data/lib/docbook/elements/fieldsynopsis.rb +21 -0
  126. data/lib/docbook/elements/figure.rb +28 -0
  127. data/lib/docbook/elements/filename.rb +16 -0
  128. data/lib/docbook/elements/firstname.rb +16 -0
  129. data/lib/docbook/elements/firstterm.rb +18 -0
  130. data/lib/docbook/elements/footnote.rb +22 -0
  131. data/lib/docbook/elements/footnoteref.rb +21 -0
  132. data/lib/docbook/elements/foreignphrase.rb +18 -0
  133. data/lib/docbook/elements/formalpara.rb +20 -0
  134. data/lib/docbook/elements/function.rb +16 -0
  135. data/lib/docbook/elements/glossary.rb +24 -0
  136. data/lib/docbook/elements/glossdef.rb +18 -0
  137. data/lib/docbook/elements/glossentry.rb +26 -0
  138. data/lib/docbook/elements/glosssee.rb +18 -0
  139. data/lib/docbook/elements/glossseealso.rb +18 -0
  140. data/lib/docbook/elements/glossterm.rb +18 -0
  141. data/lib/docbook/elements/holder.rb +16 -0
  142. data/lib/docbook/elements/honorific.rb +16 -0
  143. data/lib/docbook/elements/imagedata.rb +29 -0
  144. data/lib/docbook/elements/imageobject.rb +22 -0
  145. data/lib/docbook/elements/important.rb +30 -0
  146. data/lib/docbook/elements/index.rb +26 -0
  147. data/lib/docbook/elements/indexdiv.rb +22 -0
  148. data/lib/docbook/elements/indexentry.rb +22 -0
  149. data/lib/docbook/elements/indexterm.rb +34 -0
  150. data/lib/docbook/elements/info.rb +25 -0
  151. data/lib/docbook/elements/informalexample.rb +24 -0
  152. data/lib/docbook/elements/informalfigure.rb +20 -0
  153. data/lib/docbook/elements/inlinemediaobject.rb +22 -0
  154. data/lib/docbook/elements/itemizedlist.rb +21 -0
  155. data/lib/docbook/elements/legalnotice.rb +22 -0
  156. data/lib/docbook/elements/link.rb +26 -0
  157. data/lib/docbook/elements/listitem.rb +32 -0
  158. data/lib/docbook/elements/literal.rb +16 -0
  159. data/lib/docbook/elements/literallayout.rb +22 -0
  160. data/lib/docbook/elements/mediaobject.rb +26 -0
  161. data/lib/docbook/elements/msg.rb +20 -0
  162. data/lib/docbook/elements/msgexplan.rb +22 -0
  163. data/lib/docbook/elements/msgset.rb +22 -0
  164. data/lib/docbook/elements/note.rb +30 -0
  165. data/lib/docbook/elements/orderedlist.rb +23 -0
  166. data/lib/docbook/elements/orgname.rb +16 -0
  167. data/lib/docbook/elements/para.rb +61 -0
  168. data/lib/docbook/elements/paragraph_like.rb +18 -0
  169. data/lib/docbook/elements/parameter.rb +16 -0
  170. data/lib/docbook/elements/part.rb +38 -0
  171. data/lib/docbook/elements/personname.rb +22 -0
  172. data/lib/docbook/elements/phrase.rb +20 -0
  173. data/lib/docbook/elements/preface.rb +58 -0
  174. data/lib/docbook/elements/primary.rb +16 -0
  175. data/lib/docbook/elements/procedure.rb +24 -0
  176. data/lib/docbook/elements/productname.rb +18 -0
  177. data/lib/docbook/elements/productnumber.rb +16 -0
  178. data/lib/docbook/elements/programlisting.rb +28 -0
  179. data/lib/docbook/elements/property.rb +16 -0
  180. data/lib/docbook/elements/pubdate.rb +16 -0
  181. data/lib/docbook/elements/publishername.rb +16 -0
  182. data/lib/docbook/elements/quotation.rb +24 -0
  183. data/lib/docbook/elements/quote.rb +18 -0
  184. data/lib/docbook/elements/refentry.rb +32 -0
  185. data/lib/docbook/elements/refentrytitle.rb +16 -0
  186. data/lib/docbook/elements/reference.rb +26 -0
  187. data/lib/docbook/elements/refmeta.rb +29 -0
  188. data/lib/docbook/elements/refmiscinfo.rb +16 -0
  189. data/lib/docbook/elements/refname.rb +16 -0
  190. data/lib/docbook/elements/refnamediv.rb +22 -0
  191. data/lib/docbook/elements/refpurpose.rb +16 -0
  192. data/lib/docbook/elements/refsect1.rb +22 -0
  193. data/lib/docbook/elements/refsect2.rb +22 -0
  194. data/lib/docbook/elements/refsect3.rb +22 -0
  195. data/lib/docbook/elements/refsection.rb +32 -0
  196. data/lib/docbook/elements/releaseinfo.rb +16 -0
  197. data/lib/docbook/elements/remark.rb +20 -0
  198. data/lib/docbook/elements/replaceable.rb +16 -0
  199. data/lib/docbook/elements/row.rb +15 -0
  200. data/lib/docbook/elements/screen.rb +28 -0
  201. data/lib/docbook/elements/secondary.rb +16 -0
  202. data/lib/docbook/elements/sect1.rb +26 -0
  203. data/lib/docbook/elements/sect2.rb +24 -0
  204. data/lib/docbook/elements/sect3.rb +24 -0
  205. data/lib/docbook/elements/sect4.rb +24 -0
  206. data/lib/docbook/elements/sect5.rb +22 -0
  207. data/lib/docbook/elements/section.rb +66 -0
  208. data/lib/docbook/elements/see.rb +16 -0
  209. data/lib/docbook/elements/seealso.rb +18 -0
  210. data/lib/docbook/elements/set.rb +26 -0
  211. data/lib/docbook/elements/setindex.rb +24 -0
  212. data/lib/docbook/elements/sidebar.rb +22 -0
  213. data/lib/docbook/elements/simplesect.rb +32 -0
  214. data/lib/docbook/elements/step.rb +26 -0
  215. data/lib/docbook/elements/substeps.rb +18 -0
  216. data/lib/docbook/elements/subtitle.rb +16 -0
  217. data/lib/docbook/elements/surname.rb +16 -0
  218. data/lib/docbook/elements/table.rb +24 -0
  219. data/lib/docbook/elements/tag.rb +20 -0
  220. data/lib/docbook/elements/tbody.rb +15 -0
  221. data/lib/docbook/elements/term.rb +37 -0
  222. data/lib/docbook/elements/tertiary.rb +16 -0
  223. data/lib/docbook/elements/textobject.rb +18 -0
  224. data/lib/docbook/elements/tfoot.rb +15 -0
  225. data/lib/docbook/elements/tgroup.rb +21 -0
  226. data/lib/docbook/elements/thead.rb +15 -0
  227. data/lib/docbook/elements/tip.rb +30 -0
  228. data/lib/docbook/elements/title.rb +16 -0
  229. data/lib/docbook/elements/toc.rb +24 -0
  230. data/lib/docbook/elements/tocdiv.rb +22 -0
  231. data/lib/docbook/elements/tocentry.rb +20 -0
  232. data/lib/docbook/elements/topic.rb +26 -0
  233. data/lib/docbook/elements/type.rb +16 -0
  234. data/lib/docbook/elements/uri.rb +16 -0
  235. data/lib/docbook/elements/userinput.rb +18 -0
  236. data/lib/docbook/elements/variable.rb +16 -0
  237. data/lib/docbook/elements/variablelist.rb +19 -0
  238. data/lib/docbook/elements/varlistentry.rb +17 -0
  239. data/lib/docbook/elements/version.rb +16 -0
  240. data/lib/docbook/elements/videoobject.rb +18 -0
  241. data/lib/docbook/elements/warning.rb +30 -0
  242. data/lib/docbook/elements/xref.rb +18 -0
  243. data/lib/docbook/elements/year.rb +16 -0
  244. data/lib/docbook/elements.rb +204 -0
  245. data/lib/docbook/models/document_metadata.rb +30 -0
  246. data/lib/docbook/models/document_root.rb +33 -0
  247. data/lib/docbook/models/index_entry.rb +28 -0
  248. data/lib/docbook/models/reading_position.rb +22 -0
  249. data/lib/docbook/models/section_number.rb +18 -0
  250. data/lib/docbook/models/section_root.rb +29 -0
  251. data/lib/docbook/models/toc_node.rb +24 -0
  252. data/lib/docbook/models.rb +16 -0
  253. data/lib/docbook/output/data.rb +196 -0
  254. data/lib/docbook/output/html.rb +1450 -0
  255. data/lib/docbook/output/index_generator.rb +281 -0
  256. data/lib/docbook/output.rb +8 -0
  257. data/lib/docbook/services/document_builder.rb +258 -0
  258. data/lib/docbook/services/element_to_hash.rb +287 -0
  259. data/lib/docbook/services/index_generator.rb +134 -0
  260. data/lib/docbook/services/numbering_service.rb +186 -0
  261. data/lib/docbook/services/toc_generator.rb +138 -0
  262. data/lib/docbook/services.rb +14 -0
  263. data/lib/docbook/templates/document.html.liquid +20 -0
  264. data/lib/docbook/templates/partials/_head.liquid +39 -0
  265. data/lib/docbook/templates/partials/_scripts.liquid +10 -0
  266. data/lib/docbook/version.rb +5 -0
  267. data/lib/docbook/xinclude_resolver.rb +217 -0
  268. data/lib/docbook/xref_resolver.rb +78 -0
  269. data/lib/docbook.rb +17 -0
  270. data/sig/docbook.rbs +4 -0
  271. metadata +385 -0
@@ -0,0 +1,185 @@
1
+ ---
2
+ layout: default
3
+ title: Element Class Design
4
+ parent: Advanced
5
+ nav_order: 3
6
+ ---
7
+
8
+ # Element Class Design
9
+
10
+ Every supported DocBook XML element is represented by a Ruby class in
11
+ the `Docbook::Elements` namespace. This page explains the design
12
+ patterns and how to add new element types.
13
+
14
+ == Base class
15
+
16
+ All element classes inherit from `Lutaml::Model::Serializable`, which
17
+ provides:
18
+
19
+ * Automatic XML parsing and serialization via `from_xml` / `to_xml`
20
+ * JSON serialization via `to_json`
21
+ * Attribute declaration with type checking
22
+ * Mixed content handling
23
+
24
+ == DSL methods
25
+
26
+ The lutaml-model DSL provides several methods for declaring how an
27
+ element maps to Ruby attributes:
28
+
29
+ === attribute
30
+
31
+ Declares a typed attribute on the class. Basic types include `:string`,
32
+ `:integer`, and `:float`. Complex types reference other element classes.
33
+
34
+ [source,ruby]
35
+ ----
36
+ attribute :content, :string
37
+ attribute :role, :string
38
+ attribute :xml_id, Lutaml::Xml::W3c::XmlIdType
39
+ attribute :title, Title
40
+ attribute :section, Section, collection: true
41
+ ----
42
+
43
+ The `collection: true` option indicates that the attribute holds an
44
+ array of values rather than a single value.
45
+
46
+ === mixed_content
47
+
48
+ Declares that the element can contain a mix of text and child elements.
49
+ This is essential for elements like `<para>` that contain both raw text
50
+ and inline markup (`<emphasis>`, `<code>`, `<link>`, etc.).
51
+
52
+ [source,ruby]
53
+ ----
54
+ xml do
55
+ element "para"
56
+ mixed_content
57
+ end
58
+ ----
59
+
60
+ === map_content
61
+
62
+ Maps the element's text content (the text between tags) to an attribute.
63
+
64
+ [source,ruby]
65
+ ----
66
+ xml do
67
+ map_content to: :content
68
+ end
69
+ ----
70
+
71
+ === map_element
72
+
73
+ Maps a child XML element to a Ruby attribute. The first argument is the
74
+ XML element name; the `to:` option specifies the Ruby attribute.
75
+
76
+ [source,ruby]
77
+ ----
78
+ xml do
79
+ map_element "title", to: :title
80
+ map_element "para", to: :para
81
+ map_element "section", to: :section
82
+ end
83
+ ----
84
+
85
+ === map_attribute
86
+
87
+ Maps an XML attribute to a Ruby attribute.
88
+
89
+ [source,ruby]
90
+ ----
91
+ xml do
92
+ map_attribute "role", to: :role
93
+ map_attribute "xml:id", to: :xml_id
94
+ map_attribute "xlink:href", to: :xlink_href
95
+ end
96
+ ----
97
+
98
+ == Mixed content traversal
99
+
100
+ Elements that declare `mixed_content` support the `each_mixed_content`
101
+ method. This method yields each child node in document order, as either
102
+ a `String` (for text nodes) or a typed element object.
103
+
104
+ [source,ruby]
105
+ ----
106
+ element.each_mixed_content do |node|
107
+ case node
108
+ when String
109
+ # Handle text content
110
+ when Docbook::Elements::Emphasis
111
+ # Handle <emphasis> inline element
112
+ when Docbook::Elements::Link
113
+ # Handle <link> inline element
114
+ end
115
+ end
116
+ ----
117
+
118
+ This pattern is the foundation of the HTML generator's content
119
+ rendering. The `build_inline_content` and `build_element_content`
120
+ methods in `Output::Html` use `each_mixed_content` exclusively to
121
+ process element children.
122
+
123
+ == Adding a new element
124
+
125
+ To add support for a new DocBook element:
126
+
127
+ . **Create the element class** in `lib/docbook/elements/`. The file
128
+ name should match the element name (for example, `acknowledgements.rb`
129
+ for `<acknowledgements>`). Declare attributes and XML mappings.
130
+
131
+ . **Add an autoload entry** in `lib/docbook/elements.rb`:
132
+ +
133
+ [source,ruby]
134
+ ----
135
+ autoload :NewElement, "#{__dir__}/elements/new_element"
136
+ ----
137
+
138
+ . **Add the attribute to the parent element**. If `<newelement>` can
139
+ appear inside `<chapter>`, add it to the `Chapter` class:
140
+ +
141
+ [source,ruby]
142
+ ----
143
+ attribute :newelement, NewElement, collection: true
144
+ # and in the xml block:
145
+ map_element "newelement", to: :newelement
146
+ ----
147
+
148
+ . **Add a case in the HTML generator**. In `lib/docbook/output/html.rb`,
149
+ add a `when` branch in the appropriate `case` statement (either
150
+ `build_element_content` or `build_inline_content`) to handle the new
151
+ element type and produce the corresponding `ContentBlock`.
152
+
153
+ . **Add to ROOT_ELEMENT_MAP** if the element can be a document root.
154
+ In `lib/docbook/document.rb`, add an entry like:
155
+ +
156
+ [source,ruby]
157
+ ----
158
+ "newelement" => Elements::NewElement,
159
+ ----
160
+
161
+ == ROOT_ELEMENT_MAP
162
+
163
+ The `Document::ROOT_ELEMENT_MAP` constant maps XML root element names
164
+ to their Ruby classes. This map is used by `Document.from_xml` to
165
+ dispatch parsing. The map currently supports 37 root element types
166
+ including `article`, `book`, `chapter`, `section`, `appendix`,
167
+ `refentry`, `bibliography`, `glossary`, `set`, `reference`, `topic`,
168
+ and all numbered section variants (`sect1` through `sect5`,
169
+ `refsect1` through `refsect3`).
170
+
171
+ == Collections
172
+
173
+ Many attributes use `collection: true` because DocBook elements can
174
+ appear multiple times within their parent. For example, a `<book>`
175
+ can contain multiple `<chapter>` elements:
176
+
177
+ [source,ruby]
178
+ ----
179
+ attribute :chapter, Chapter, collection: true
180
+ ----
181
+
182
+ The lutaml-model library automatically accumulates multiple XML
183
+ elements into the array. In code, always use `Array(value)` when
184
+ iterating over collection attributes, since they may be `nil` when
185
+ no child elements are present.
@@ -0,0 +1,193 @@
1
+ ---
2
+ layout: default
3
+ title: Frontend Customization
4
+ parent: Advanced
5
+ nav_order: 2
6
+ ---
7
+
8
+ # Frontend Customization
9
+
10
+ The HTML output includes a Vue 3 single-page application that provides
11
+ an interactive ebook reader experience. This page describes the
12
+ frontend architecture and how to customize it.
13
+
14
+ == Build toolchain
15
+
16
+ The frontend lives in the `frontend/` directory at the project root.
17
+ It uses the following toolchain:
18
+
19
+ * **Vue 3** (v3.4+) with the Composition API
20
+ * **TypeScript** for type safety
21
+ * **Vite** (v5.2+) for building
22
+ * **Pinia** for state management
23
+ * **FlexSearch** for client-side full-text search
24
+
25
+ Build the frontend with:
26
+
27
+ ....
28
+ cd frontend
29
+ npm install
30
+ npm run build
31
+ ....
32
+
33
+ This produces two files in `frontend/dist/`:
34
+
35
+ * `app.css` -- The compiled stylesheet
36
+ * `app.iife.js` -- The bundled JavaScript (IIFE format)
37
+
38
+ These files are copied into the HTML output by the Ruby generator.
39
+
40
+ == Components
41
+
42
+ The Vue application consists of the following components:
43
+
44
+ === EbookContainer
45
+
46
+ The top-level layout component. It renders the sidebar, content area,
47
+ and settings panel. It manages the overall layout state and applies
48
+ theme CSS classes to the root container.
49
+
50
+ === AppSidebar
51
+
52
+ The left sidebar containing the table of contents tree. It uses
53
+ `TocTreeItem` components recursively to render the nested section
54
+ hierarchy. Clicking a TOC entry navigates to the corresponding section.
55
+
56
+ === ContentRenderer
57
+
58
+ Responsible for rendering the main document content. It looks up the
59
+ active section's content blocks from the `documentStore` and delegates
60
+ to `BlockRenderer` for each block.
61
+
62
+ === BlockRenderer
63
+
64
+ A recursive component that renders a single `ContentBlock`. It
65
+ switches on the block's `type` to produce the appropriate HTML:
66
+ paragraphs, code blocks, images, lists, admonitions, and so on.
67
+
68
+ === SearchModal
69
+
70
+ A full-screen search overlay powered by FlexSearch. It indexes TOC
71
+ titles and provides instant search-as-you-type results. The search
72
+ index is persisted in IndexedDB to avoid rebuilding on each page load.
73
+
74
+ === SettingsPanel
75
+
76
+ A slide-out panel for reading preferences: theme selection, font size,
77
+ line height, margin width, and reading mode. Settings are persisted
78
+ in localStorage via the `useEbookStore` composable.
79
+
80
+ === TocTreeItem
81
+
82
+ Renders a single entry in the table of contents tree, including its
83
+ section number and expand/collapse toggle for nested children.
84
+
85
+ === ReferenceEntry
86
+
87
+ A specialized component for rendering `<refentry>` elements (man-page
88
+ style reference entries) with their badge, name, definition, and
89
+ description sections.
90
+
91
+ == State management
92
+
93
+ === documentStore (Pinia)
94
+
95
+ The central data store. It loads document data from
96
+ `window.DOCBOOK_DATA` (single-file mode) or fetches
97
+ `docbook.data.json` (directory mode). It exposes computed properties
98
+ for `title`, `sections`, `numbering`, `content`, and `index`, plus a
99
+ `getSectionContent(id)` lookup method.
100
+
101
+ === uiStore (Pinia)
102
+
103
+ Manages UI state: theme (light/dark/system), font family
104
+ (sans/serif), sidebar visibility, search visibility, and the active
105
+ section ID. Theme and font preferences are persisted in localStorage.
106
+
107
+ == Composables
108
+
109
+ === useSearch
110
+
111
+ Provides full-text search over TOC entries using FlexSearch. The
112
+ composable builds a `Document` index with forward tokenization and
113
+ persists the serialized index in IndexedDB. On subsequent loads, it
114
+ attempts to restore the index from IndexedDB before rebuilding.
115
+
116
+ === useEbookStore
117
+
118
+ A global singleton (not Pinia-based) that manages reading preferences:
119
+ reading mode, font size, font weight, line height, margin, and theme.
120
+ It uses a reactive state object with `watch`-based auto-persistence
121
+ to localStorage. Available themes are:
122
+
123
+ [cols="1,1,3"]
124
+ |===
125
+ | Theme | Description | Background
126
+
127
+ | `day`
128
+ | Light theme
129
+ | White background
130
+
131
+ | `sepia`
132
+ | Warm reading theme
133
+ | Cream/parchment background
134
+
135
+ | `night`
136
+ | Dark theme
137
+ | Dark gray background
138
+
139
+ | `oled`
140
+ | Pure black theme
141
+ | Black background (for OLED screens)
142
+ |===
143
+
144
+ Reading modes:
145
+
146
+ [cols="1,3"]
147
+ |===
148
+ | Mode | Description
149
+
150
+ | `scroll`
151
+ | Continuous scrolling through all content
152
+
153
+ | `page`
154
+ | Paginated view with page-turn navigation
155
+
156
+ | `chapter`
157
+ | One chapter at a time with next/previous navigation
158
+
159
+ | `reference`
160
+ | Compact layout for reference entry pages
161
+ |===
162
+
163
+ == Fonts
164
+
165
+ The frontend loads three font families from Google Fonts:
166
+
167
+ [cols="1,1,2"]
168
+ |===
169
+ | Font | CSS family | Usage
170
+
171
+ | Inter
172
+ | `font-sans`
173
+ | Body text, UI elements
174
+
175
+ | Merriweather
176
+ | `font-serif`
177
+ | Reading mode serif option
178
+
179
+ | JetBrains Mono
180
+ | `font-mono`
181
+ | Code blocks, inline code
182
+ |===
183
+
184
+ == Customizing the frontend
185
+
186
+ To modify the reader's appearance or behavior:
187
+
188
+ . Edit the Vue components in `frontend/src/`.
189
+ . Run `npm run build` in the `frontend/` directory.
190
+ . Regenerate the HTML output using the `docbook to-html` command.
191
+
192
+ The Ruby generator always uses the latest built assets from
193
+ `frontend/dist/`, so changes take effect immediately after rebuilding.
@@ -0,0 +1,14 @@
1
+ ---
2
+ layout: default
3
+ title: Advanced
4
+ nav_order: 6
5
+ has_children: true
6
+ ---
7
+
8
+ # Advanced
9
+
10
+ This section covers advanced topics for developers who want to customize
11
+ or extend the Metanorma DocBook gem beyond its default behavior.
12
+
13
+ Topics include the Liquid template system, frontend customization, and
14
+ the design patterns behind element classes.
@@ -0,0 +1,123 @@
1
+ ---
2
+ layout: default
3
+ title: Liquid Templates
4
+ parent: Advanced
5
+ nav_order: 1
6
+ ---
7
+
8
+ # Liquid Templates
9
+
10
+ The HTML output is generated using the Liquid template engine. Templates
11
+ are located in `lib/docbook/templates/`. The system uses Liquid's
12
+ `LocalFileSystem` for partial resolution, so `{% include 'partials/head' %}`
13
+ resolves to `templates/partials/_head.liquid`.
14
+
15
+ == Template files
16
+
17
+ === document.html.liquid
18
+
19
+ The main template. It produces a complete HTML5 document with:
20
+
21
+ * A `<head>` section that includes the `_head` partial (fonts, Tailwind
22
+ CSS, Prism.js styles, and the app CSS).
23
+ * A `<div id="docbook-app">` mount point for the Vue SPA.
24
+ * An inline `<script>` block that defines `window.DOCBOOK_DATA` with
25
+ placeholder tokens for JSON data.
26
+ * The `_scripts` partial (Prism.js and the app JavaScript).
27
+
28
+ === partials/_head.liquid
29
+
30
+ Provides the document head content:
31
+
32
+ * **Prism.js CSS** -- Syntax highlighting theme loaded from cdnjs.
33
+ * **Google Fonts** -- Inter (sans-serif), Merriweather (serif), and
34
+ JetBrains Mono (monospace) loaded from Google Fonts CDN.
35
+ * **Tailwind CSS** -- The Tailwind CDN script with a custom
36
+ configuration that sets `darkMode: 'class'` and registers the three
37
+ font families.
38
+ * **Custom styles** -- Inline `<style>` block with TOC active states,
39
+ bibliography entry indentation, and appendix border styling.
40
+ * **App CSS** -- Conditionally inlined or linked. When `assets_inline`
41
+ is true (single-file mode), the CSS is embedded in a `<style>` tag.
42
+ In directory mode, it is loaded from `assets/app.css`.
43
+
44
+ === partials/_scripts.liquid
45
+
46
+ Provides the document scripts:
47
+
48
+ * **Prism.js** -- Core library and autoloader plugin from cdnjs for
49
+ syntax highlighting of code blocks.
50
+ * **App JS** -- Conditionally inlined or linked. When `assets_inline`
51
+ is true, the JavaScript is embedded in a `<script>` tag. In directory
52
+ mode, it is loaded from `assets/app.iife.js`.
53
+
54
+ == Template variables
55
+
56
+ The following variables are passed to the Liquid template by the Ruby
57
+ HTML generator:
58
+
59
+ [cols="1,1,4"]
60
+ |===
61
+ | Variable | Type | Description
62
+
63
+ | `docbook_title`
64
+ | String
65
+ | The document title, extracted from the root element.
66
+
67
+ | `base_url`
68
+ | String
69
+ | The base URL for asset references. `"."` in directory mode, `""`
70
+ in single-file mode.
71
+
72
+ | `assets_inline`
73
+ | Boolean
74
+ | When true, CSS and JS are inlined. When false, they are linked.
75
+
76
+ | `app_css`
77
+ | String
78
+ | The contents of `frontend/dist/app.css`.
79
+
80
+ | `app_js`
81
+ | String
82
+ | The contents of `frontend/dist/app.iife.js`.
83
+ |===
84
+
85
+ == Placeholder tokens
86
+
87
+ The main template uses four placeholder tokens that are replaced via
88
+ Ruby string substitution (`gsub`) after Liquid rendering:
89
+
90
+ `[[DOCBOOK_DATA]]`::
91
+ Replaced with the `DocumentData` JSON (title only) in single-file mode,
92
+ or `null /* loaded from docbook.data.json */` in directory mode.
93
+
94
+ `[[DOCBOOK_TOC]]`::
95
+ Replaced with the full TOC JSON (sections tree + numbering) in
96
+ single-file mode, or `null` in directory mode.
97
+
98
+ `[[DOCBOOK_CONTENT]]`::
99
+ Replaced with the content data JSON (keyed by section ID) in
100
+ single-file mode, or `null` in directory mode.
101
+
102
+ `[[DOCBOOK_INDEX]]`::
103
+ Replaced with the index data JSON (grouped by letter) in single-file
104
+ mode, or `null` in directory mode.
105
+
106
+ The use of string substitution rather than Liquid variables is
107
+ intentional: the JSON payloads are large and may contain characters
108
+ (like `{%`) that would conflict with Liquid's template syntax.
109
+
110
+ == Output modes
111
+
112
+ === Single-file mode
113
+
114
+ All data is embedded inline. The resulting HTML file is self-contained
115
+ and can be opened directly in a browser without a web server. The
116
+ JSON is injected into `window.DOCBOOK_DATA` using `Object.assign()`.
117
+
118
+ === Directory mode
119
+
120
+ The JSON is written to `docbook.data.json`. The template placeholders
121
+ are set to `null`, and the Vue SPA's `documentStore.loadFromWindow()`
122
+ detects that inline data is absent and fetches the external JSON file
123
+ instead. CSS and JS assets are linked from the `assets/` subdirectory.