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.
- checksums.yaml +7 -0
- data/CHANGELOG.md +5 -0
- data/CLAUDE.md +19 -0
- data/CODE_OF_CONDUCT.md +10 -0
- data/README.adoc +335 -0
- data/Rakefile +12 -0
- data/docs/.lycheeignore +33 -0
- data/docs/Gemfile +10 -0
- data/docs/INDEX.adoc +67 -0
- data/docs/_config.yml +186 -0
- data/docs/advanced/element-classes.adoc +185 -0
- data/docs/advanced/frontend-customization.adoc +193 -0
- data/docs/advanced/index.adoc +14 -0
- data/docs/advanced/templates.adoc +123 -0
- data/docs/features/element-coverage.adoc +373 -0
- data/docs/features/html-output/data-model.adoc +285 -0
- data/docs/features/html-output/directory-mode.adoc +180 -0
- data/docs/features/html-output/index.adoc +90 -0
- data/docs/features/html-output/single-file-mode.adoc +125 -0
- data/docs/features/index-generation.adoc +197 -0
- data/docs/features/index.adoc +63 -0
- data/docs/features/numbering.adoc +183 -0
- data/docs/features/toc-generation.adoc +150 -0
- data/docs/features/xinclude/fragid-schemes.adoc +287 -0
- data/docs/features/xinclude/index.adoc +119 -0
- data/docs/features/xinclude/text-includes.adoc +123 -0
- data/docs/features/xinclude/xml-includes.adoc +167 -0
- data/docs/getting-started/index.adoc +50 -0
- data/docs/getting-started/installation.adoc +113 -0
- data/docs/getting-started/quick-start.adoc +161 -0
- data/docs/guides/converting-article.adoc +188 -0
- data/docs/guides/converting-book.adoc +192 -0
- data/docs/guides/index.adoc +12 -0
- data/docs/guides/roundtrip-testing.adoc +129 -0
- data/docs/interfaces/cli/format-command.adoc +109 -0
- data/docs/interfaces/cli/index.adoc +73 -0
- data/docs/interfaces/cli/roundtrip-command.adoc +125 -0
- data/docs/interfaces/cli/to-html-command.adoc +178 -0
- data/docs/interfaces/cli/validate-command.adoc +104 -0
- data/docs/interfaces/index.adoc +101 -0
- data/docs/interfaces/ruby-api/html-output.adoc +186 -0
- data/docs/interfaces/ruby-api/index.adoc +111 -0
- data/docs/interfaces/ruby-api/parsing.adoc +202 -0
- data/docs/interfaces/ruby-api/xinclude.adoc +162 -0
- data/docs/interfaces/ruby-api/xref-resolution.adoc +156 -0
- data/docs/lychee.toml +42 -0
- data/docs/reference/cli-options.adoc +155 -0
- data/docs/reference/content-block-types.adoc +243 -0
- data/docs/reference/glossary.adoc +119 -0
- data/docs/reference/index.adoc +12 -0
- data/docs/reference/supported-elements.adoc +749 -0
- data/docs/understanding/architecture.adoc +145 -0
- data/docs/understanding/content-pipeline.adoc +102 -0
- data/docs/understanding/data-models.adoc +156 -0
- data/docs/understanding/index.adoc +34 -0
- data/exe/docbook +7 -0
- data/frontend/dist/app.css +1 -0
- data/frontend/dist/app.iife.js +24 -0
- data/frontend/package-lock.json +1445 -0
- data/frontend/package.json +22 -0
- data/frontend/src/App.vue +230 -0
- data/frontend/src/app.ts +8 -0
- data/frontend/src/components/AppSidebar.vue +116 -0
- data/frontend/src/components/AppendixSection.vue +39 -0
- data/frontend/src/components/BlockRenderer.vue +358 -0
- data/frontend/src/components/ChapterSection.vue +32 -0
- data/frontend/src/components/ContentRenderer.vue +13 -0
- data/frontend/src/components/EbookContainer.vue +147 -0
- data/frontend/src/components/EbookTopBar.vue +116 -0
- data/frontend/src/components/PartSection.vue +44 -0
- data/frontend/src/components/ReferenceEntry.vue +80 -0
- data/frontend/src/components/SearchModal.vue +286 -0
- data/frontend/src/components/SectionContent.vue +31 -0
- data/frontend/src/components/SettingsPanel.vue +236 -0
- data/frontend/src/components/TocTreeItem.vue +135 -0
- data/frontend/src/composables/useEbookStore.ts +191 -0
- data/frontend/src/composables/useSearch.ts +249 -0
- data/frontend/src/env.d.ts +7 -0
- data/frontend/src/stores/documentStore.ts +221 -0
- data/frontend/src/stores/uiStore.ts +98 -0
- data/frontend/src/styles.css +253 -0
- data/frontend/tsconfig.json +24 -0
- data/frontend/tsconfig.node.json +11 -0
- data/frontend/vite.config.ts +30 -0
- data/lib/docbook/cli.rb +123 -0
- data/lib/docbook/document.rb +67 -0
- data/lib/docbook/elements/abbrev.rb +16 -0
- data/lib/docbook/elements/acknowledgements.rb +22 -0
- data/lib/docbook/elements/address.rb +18 -0
- data/lib/docbook/elements/alt.rb +16 -0
- data/lib/docbook/elements/annotation.rb +18 -0
- data/lib/docbook/elements/appendix.rb +34 -0
- data/lib/docbook/elements/article.rb +31 -0
- data/lib/docbook/elements/att.rb +15 -0
- data/lib/docbook/elements/attribution.rb +20 -0
- data/lib/docbook/elements/audioobject.rb +18 -0
- data/lib/docbook/elements/author.rb +18 -0
- data/lib/docbook/elements/bibliography.rb +24 -0
- data/lib/docbook/elements/bibliomixed.rb +40 -0
- data/lib/docbook/elements/biblioref.rb +20 -0
- data/lib/docbook/elements/blockquote.rb +26 -0
- data/lib/docbook/elements/book.rb +36 -0
- data/lib/docbook/elements/buildtarget.rb +16 -0
- data/lib/docbook/elements/callout.rb +22 -0
- data/lib/docbook/elements/calloutlist.rb +22 -0
- data/lib/docbook/elements/caution.rb +30 -0
- data/lib/docbook/elements/chapter.rb +62 -0
- data/lib/docbook/elements/citation.rb +16 -0
- data/lib/docbook/elements/citerefentry.rb +26 -0
- data/lib/docbook/elements/citetitle.rb +20 -0
- data/lib/docbook/elements/classname.rb +16 -0
- data/lib/docbook/elements/code.rb +16 -0
- data/lib/docbook/elements/colophon.rb +22 -0
- data/lib/docbook/elements/computeroutput.rb +18 -0
- data/lib/docbook/elements/copyright.rb +17 -0
- data/lib/docbook/elements/danger.rb +28 -0
- data/lib/docbook/elements/date.rb +16 -0
- data/lib/docbook/elements/dedication.rb +22 -0
- data/lib/docbook/elements/dir.rb +16 -0
- data/lib/docbook/elements/emphasis.rb +18 -0
- data/lib/docbook/elements/entry.rb +30 -0
- data/lib/docbook/elements/entrytbl.rb +22 -0
- data/lib/docbook/elements/equation.rb +26 -0
- data/lib/docbook/elements/example.rb +30 -0
- data/lib/docbook/elements/fieldsynopsis.rb +21 -0
- data/lib/docbook/elements/figure.rb +28 -0
- data/lib/docbook/elements/filename.rb +16 -0
- data/lib/docbook/elements/firstname.rb +16 -0
- data/lib/docbook/elements/firstterm.rb +18 -0
- data/lib/docbook/elements/footnote.rb +22 -0
- data/lib/docbook/elements/footnoteref.rb +21 -0
- data/lib/docbook/elements/foreignphrase.rb +18 -0
- data/lib/docbook/elements/formalpara.rb +20 -0
- data/lib/docbook/elements/function.rb +16 -0
- data/lib/docbook/elements/glossary.rb +24 -0
- data/lib/docbook/elements/glossdef.rb +18 -0
- data/lib/docbook/elements/glossentry.rb +26 -0
- data/lib/docbook/elements/glosssee.rb +18 -0
- data/lib/docbook/elements/glossseealso.rb +18 -0
- data/lib/docbook/elements/glossterm.rb +18 -0
- data/lib/docbook/elements/holder.rb +16 -0
- data/lib/docbook/elements/honorific.rb +16 -0
- data/lib/docbook/elements/imagedata.rb +29 -0
- data/lib/docbook/elements/imageobject.rb +22 -0
- data/lib/docbook/elements/important.rb +30 -0
- data/lib/docbook/elements/index.rb +26 -0
- data/lib/docbook/elements/indexdiv.rb +22 -0
- data/lib/docbook/elements/indexentry.rb +22 -0
- data/lib/docbook/elements/indexterm.rb +34 -0
- data/lib/docbook/elements/info.rb +25 -0
- data/lib/docbook/elements/informalexample.rb +24 -0
- data/lib/docbook/elements/informalfigure.rb +20 -0
- data/lib/docbook/elements/inlinemediaobject.rb +22 -0
- data/lib/docbook/elements/itemizedlist.rb +21 -0
- data/lib/docbook/elements/legalnotice.rb +22 -0
- data/lib/docbook/elements/link.rb +26 -0
- data/lib/docbook/elements/listitem.rb +32 -0
- data/lib/docbook/elements/literal.rb +16 -0
- data/lib/docbook/elements/literallayout.rb +22 -0
- data/lib/docbook/elements/mediaobject.rb +26 -0
- data/lib/docbook/elements/msg.rb +20 -0
- data/lib/docbook/elements/msgexplan.rb +22 -0
- data/lib/docbook/elements/msgset.rb +22 -0
- data/lib/docbook/elements/note.rb +30 -0
- data/lib/docbook/elements/orderedlist.rb +23 -0
- data/lib/docbook/elements/orgname.rb +16 -0
- data/lib/docbook/elements/para.rb +61 -0
- data/lib/docbook/elements/paragraph_like.rb +18 -0
- data/lib/docbook/elements/parameter.rb +16 -0
- data/lib/docbook/elements/part.rb +38 -0
- data/lib/docbook/elements/personname.rb +22 -0
- data/lib/docbook/elements/phrase.rb +20 -0
- data/lib/docbook/elements/preface.rb +58 -0
- data/lib/docbook/elements/primary.rb +16 -0
- data/lib/docbook/elements/procedure.rb +24 -0
- data/lib/docbook/elements/productname.rb +18 -0
- data/lib/docbook/elements/productnumber.rb +16 -0
- data/lib/docbook/elements/programlisting.rb +28 -0
- data/lib/docbook/elements/property.rb +16 -0
- data/lib/docbook/elements/pubdate.rb +16 -0
- data/lib/docbook/elements/publishername.rb +16 -0
- data/lib/docbook/elements/quotation.rb +24 -0
- data/lib/docbook/elements/quote.rb +18 -0
- data/lib/docbook/elements/refentry.rb +32 -0
- data/lib/docbook/elements/refentrytitle.rb +16 -0
- data/lib/docbook/elements/reference.rb +26 -0
- data/lib/docbook/elements/refmeta.rb +29 -0
- data/lib/docbook/elements/refmiscinfo.rb +16 -0
- data/lib/docbook/elements/refname.rb +16 -0
- data/lib/docbook/elements/refnamediv.rb +22 -0
- data/lib/docbook/elements/refpurpose.rb +16 -0
- data/lib/docbook/elements/refsect1.rb +22 -0
- data/lib/docbook/elements/refsect2.rb +22 -0
- data/lib/docbook/elements/refsect3.rb +22 -0
- data/lib/docbook/elements/refsection.rb +32 -0
- data/lib/docbook/elements/releaseinfo.rb +16 -0
- data/lib/docbook/elements/remark.rb +20 -0
- data/lib/docbook/elements/replaceable.rb +16 -0
- data/lib/docbook/elements/row.rb +15 -0
- data/lib/docbook/elements/screen.rb +28 -0
- data/lib/docbook/elements/secondary.rb +16 -0
- data/lib/docbook/elements/sect1.rb +26 -0
- data/lib/docbook/elements/sect2.rb +24 -0
- data/lib/docbook/elements/sect3.rb +24 -0
- data/lib/docbook/elements/sect4.rb +24 -0
- data/lib/docbook/elements/sect5.rb +22 -0
- data/lib/docbook/elements/section.rb +66 -0
- data/lib/docbook/elements/see.rb +16 -0
- data/lib/docbook/elements/seealso.rb +18 -0
- data/lib/docbook/elements/set.rb +26 -0
- data/lib/docbook/elements/setindex.rb +24 -0
- data/lib/docbook/elements/sidebar.rb +22 -0
- data/lib/docbook/elements/simplesect.rb +32 -0
- data/lib/docbook/elements/step.rb +26 -0
- data/lib/docbook/elements/substeps.rb +18 -0
- data/lib/docbook/elements/subtitle.rb +16 -0
- data/lib/docbook/elements/surname.rb +16 -0
- data/lib/docbook/elements/table.rb +24 -0
- data/lib/docbook/elements/tag.rb +20 -0
- data/lib/docbook/elements/tbody.rb +15 -0
- data/lib/docbook/elements/term.rb +37 -0
- data/lib/docbook/elements/tertiary.rb +16 -0
- data/lib/docbook/elements/textobject.rb +18 -0
- data/lib/docbook/elements/tfoot.rb +15 -0
- data/lib/docbook/elements/tgroup.rb +21 -0
- data/lib/docbook/elements/thead.rb +15 -0
- data/lib/docbook/elements/tip.rb +30 -0
- data/lib/docbook/elements/title.rb +16 -0
- data/lib/docbook/elements/toc.rb +24 -0
- data/lib/docbook/elements/tocdiv.rb +22 -0
- data/lib/docbook/elements/tocentry.rb +20 -0
- data/lib/docbook/elements/topic.rb +26 -0
- data/lib/docbook/elements/type.rb +16 -0
- data/lib/docbook/elements/uri.rb +16 -0
- data/lib/docbook/elements/userinput.rb +18 -0
- data/lib/docbook/elements/variable.rb +16 -0
- data/lib/docbook/elements/variablelist.rb +19 -0
- data/lib/docbook/elements/varlistentry.rb +17 -0
- data/lib/docbook/elements/version.rb +16 -0
- data/lib/docbook/elements/videoobject.rb +18 -0
- data/lib/docbook/elements/warning.rb +30 -0
- data/lib/docbook/elements/xref.rb +18 -0
- data/lib/docbook/elements/year.rb +16 -0
- data/lib/docbook/elements.rb +204 -0
- data/lib/docbook/models/document_metadata.rb +30 -0
- data/lib/docbook/models/document_root.rb +33 -0
- data/lib/docbook/models/index_entry.rb +28 -0
- data/lib/docbook/models/reading_position.rb +22 -0
- data/lib/docbook/models/section_number.rb +18 -0
- data/lib/docbook/models/section_root.rb +29 -0
- data/lib/docbook/models/toc_node.rb +24 -0
- data/lib/docbook/models.rb +16 -0
- data/lib/docbook/output/data.rb +196 -0
- data/lib/docbook/output/html.rb +1450 -0
- data/lib/docbook/output/index_generator.rb +281 -0
- data/lib/docbook/output.rb +8 -0
- data/lib/docbook/services/document_builder.rb +258 -0
- data/lib/docbook/services/element_to_hash.rb +287 -0
- data/lib/docbook/services/index_generator.rb +134 -0
- data/lib/docbook/services/numbering_service.rb +186 -0
- data/lib/docbook/services/toc_generator.rb +138 -0
- data/lib/docbook/services.rb +14 -0
- data/lib/docbook/templates/document.html.liquid +20 -0
- data/lib/docbook/templates/partials/_head.liquid +39 -0
- data/lib/docbook/templates/partials/_scripts.liquid +10 -0
- data/lib/docbook/version.rb +5 -0
- data/lib/docbook/xinclude_resolver.rb +217 -0
- data/lib/docbook/xref_resolver.rb +78 -0
- data/lib/docbook.rb +17 -0
- data/sig/docbook.rbs +4 -0
- 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.
|