epub-generator 0.1.2__py3-none-any.whl → 0.1.4__py3-none-any.whl
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.
- epub_generator/__init__.py +4 -2
- epub_generator/generation/gen_chapter.py +25 -6
- epub_generator/generation/gen_epub.py +7 -6
- epub_generator/html_tag.py +11 -0
- epub_generator/types.py +19 -4
- {epub_generator-0.1.2.dist-info → epub_generator-0.1.4.dist-info}/METADATA +78 -30
- {epub_generator-0.1.2.dist-info → epub_generator-0.1.4.dist-info}/RECORD +9 -8
- {epub_generator-0.1.2.dist-info → epub_generator-0.1.4.dist-info}/LICENSE +0 -0
- {epub_generator-0.1.2.dist-info → epub_generator-0.1.4.dist-info}/WHEEL +0 -0
epub_generator/__init__.py
CHANGED
|
@@ -8,10 +8,11 @@ from .types import (
|
|
|
8
8
|
EpubData,
|
|
9
9
|
Footnote,
|
|
10
10
|
Formula,
|
|
11
|
+
HTMLTag,
|
|
11
12
|
Image,
|
|
12
13
|
Mark,
|
|
13
14
|
Table,
|
|
14
|
-
|
|
15
|
+
TextBlock,
|
|
15
16
|
TextKind,
|
|
16
17
|
TocItem,
|
|
17
18
|
)
|
|
@@ -29,10 +30,11 @@ __all__ = [
|
|
|
29
30
|
"Chapter",
|
|
30
31
|
"ChapterGetter",
|
|
31
32
|
"ContentBlock",
|
|
32
|
-
"
|
|
33
|
+
"TextBlock",
|
|
33
34
|
"TextKind",
|
|
34
35
|
"Table",
|
|
35
36
|
"Formula",
|
|
37
|
+
"HTMLTag",
|
|
36
38
|
"Image",
|
|
37
39
|
"Footnote",
|
|
38
40
|
"Mark",
|
|
@@ -7,15 +7,18 @@ from ..types import (
|
|
|
7
7
|
Chapter,
|
|
8
8
|
ContentBlock,
|
|
9
9
|
Formula,
|
|
10
|
+
HTMLTag,
|
|
10
11
|
Image,
|
|
11
12
|
Mark,
|
|
12
13
|
Table,
|
|
13
|
-
|
|
14
|
+
TextBlock,
|
|
14
15
|
TextKind,
|
|
15
16
|
)
|
|
16
17
|
from .gen_asset import process_formula, process_image, process_table
|
|
17
18
|
from .xml_utils import serialize_element, set_epub_type
|
|
18
19
|
|
|
20
|
+
_MAX_HEADING_LEVEL = 6 # HTML standard defines heading levels from h1 to h6
|
|
21
|
+
|
|
19
22
|
|
|
20
23
|
def generate_chapter(
|
|
21
24
|
context: Context,
|
|
@@ -88,9 +91,10 @@ def _render_footnotes(
|
|
|
88
91
|
|
|
89
92
|
|
|
90
93
|
def _render_content_block(context: Context, block: ContentBlock) -> Element | None:
|
|
91
|
-
if isinstance(block,
|
|
94
|
+
if isinstance(block, TextBlock):
|
|
92
95
|
if block.kind == TextKind.HEADLINE:
|
|
93
|
-
|
|
96
|
+
heading_level = min(block.level + 1, _MAX_HEADING_LEVEL)
|
|
97
|
+
container = Element(f"h{heading_level}")
|
|
94
98
|
elif block.kind == TextKind.QUOTE:
|
|
95
99
|
container = Element("p")
|
|
96
100
|
elif block.kind == TextKind.BODY:
|
|
@@ -98,8 +102,11 @@ def _render_content_block(context: Context, block: ContentBlock) -> Element | No
|
|
|
98
102
|
else:
|
|
99
103
|
raise ValueError(f"Unknown TextKind: {block.kind}")
|
|
100
104
|
|
|
101
|
-
_render_text_content(
|
|
102
|
-
|
|
105
|
+
_render_text_content(
|
|
106
|
+
context=context,
|
|
107
|
+
parent=container,
|
|
108
|
+
content=block.content,
|
|
109
|
+
)
|
|
103
110
|
if block.kind == TextKind.QUOTE:
|
|
104
111
|
blockquote = Element("blockquote")
|
|
105
112
|
blockquote.append(container)
|
|
@@ -120,7 +127,7 @@ def _render_content_block(context: Context, block: ContentBlock) -> Element | No
|
|
|
120
127
|
return None
|
|
121
128
|
|
|
122
129
|
|
|
123
|
-
def _render_text_content(context: Context, parent: Element, content: list[str | Mark | Formula]) -> None:
|
|
130
|
+
def _render_text_content(context: Context, parent: Element, content: list[str | Mark | Formula | HTMLTag]) -> None:
|
|
124
131
|
"""Render text content with inline citation marks."""
|
|
125
132
|
current_element = parent
|
|
126
133
|
for item in content:
|
|
@@ -136,6 +143,18 @@ def _render_text_content(context: Context, parent: Element, content: list[str |
|
|
|
136
143
|
else:
|
|
137
144
|
current_element.tail += item
|
|
138
145
|
|
|
146
|
+
elif isinstance(item, HTMLTag):
|
|
147
|
+
tag_element = Element(item.name)
|
|
148
|
+
for attr, value in item.attributes:
|
|
149
|
+
tag_element.set(attr, value)
|
|
150
|
+
_render_text_content(
|
|
151
|
+
context=context,
|
|
152
|
+
parent=tag_element,
|
|
153
|
+
content=item.content,
|
|
154
|
+
)
|
|
155
|
+
parent.append(tag_element)
|
|
156
|
+
current_element = tag_element
|
|
157
|
+
|
|
139
158
|
elif isinstance(item, Formula):
|
|
140
159
|
formula_element = process_formula(
|
|
141
160
|
context=context,
|
|
@@ -6,9 +6,10 @@ from uuid import uuid4
|
|
|
6
6
|
from zipfile import ZipFile
|
|
7
7
|
|
|
8
8
|
from ..context import Context, Template
|
|
9
|
+
from ..html_tag import search_content
|
|
9
10
|
from ..i18n import I18N
|
|
10
11
|
from ..options import LaTeXRender, TableRender
|
|
11
|
-
from ..types import EpubData, Formula,
|
|
12
|
+
from ..types import Chapter, EpubData, Formula, TextBlock
|
|
12
13
|
from .gen_chapter import generate_chapter
|
|
13
14
|
from .gen_nav import gen_nav
|
|
14
15
|
from .gen_toc import NavPoint, gen_toc
|
|
@@ -135,21 +136,21 @@ def _write_chapters_from_data(
|
|
|
135
136
|
assert_not_aborted()
|
|
136
137
|
|
|
137
138
|
|
|
138
|
-
def _chapter_has_formula(chapter) -> bool:
|
|
139
|
+
def _chapter_has_formula(chapter: Chapter) -> bool:
|
|
139
140
|
"""Check if chapter contains any formulas (block-level or inline)."""
|
|
140
141
|
for element in chapter.elements:
|
|
141
142
|
if isinstance(element, Formula):
|
|
142
143
|
return True
|
|
143
|
-
if isinstance(element,
|
|
144
|
-
for item in element.content:
|
|
144
|
+
if isinstance(element, TextBlock):
|
|
145
|
+
for item in search_content(element.content):
|
|
145
146
|
if isinstance(item, Formula):
|
|
146
147
|
return True
|
|
147
148
|
for footnote in chapter.footnotes:
|
|
148
149
|
for content_block in footnote.contents:
|
|
149
150
|
if isinstance(content_block, Formula):
|
|
150
151
|
return True
|
|
151
|
-
if isinstance(content_block,
|
|
152
|
-
for item in content_block.content:
|
|
152
|
+
if isinstance(content_block, TextBlock):
|
|
153
|
+
for item in search_content(content_block.content):
|
|
153
154
|
if isinstance(item, Formula):
|
|
154
155
|
return True
|
|
155
156
|
return False
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
from typing import Generator
|
|
2
|
+
|
|
3
|
+
from .types import Formula, HTMLTag, Mark
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def search_content(content: list[str | Mark | Formula | HTMLTag]) -> Generator[str | Mark | Formula, None, None]:
|
|
7
|
+
for child in content:
|
|
8
|
+
if isinstance(child, HTMLTag):
|
|
9
|
+
yield from search_content(child.content)
|
|
10
|
+
else:
|
|
11
|
+
yield child
|
epub_generator/types.py
CHANGED
|
@@ -107,10 +107,12 @@ class Image:
|
|
|
107
107
|
"""Alt text (defaults to "image")"""
|
|
108
108
|
|
|
109
109
|
@dataclass
|
|
110
|
-
class
|
|
110
|
+
class TextBlock:
|
|
111
111
|
kind: TextKind
|
|
112
112
|
"""Kind of text block."""
|
|
113
|
-
|
|
113
|
+
level: int
|
|
114
|
+
"""Heading level starting from 0 (only for HEADLINE: level 0 → h1, level 1 → h2, max h6; ignored for BODY and QUOTE)."""
|
|
115
|
+
content: list["str | Mark | Formula | HTMLTag"]
|
|
114
116
|
"""Text content with optional citation marks."""
|
|
115
117
|
|
|
116
118
|
@dataclass
|
|
@@ -126,7 +128,7 @@ class Footnote:
|
|
|
126
128
|
"""Content blocks"""
|
|
127
129
|
|
|
128
130
|
|
|
129
|
-
ContentBlock =
|
|
131
|
+
ContentBlock = TextBlock | Table | Formula | Image
|
|
130
132
|
"""Union of all content blocks that appear in main chapter content."""
|
|
131
133
|
|
|
132
134
|
@dataclass
|
|
@@ -138,4 +140,17 @@ class Chapter:
|
|
|
138
140
|
footnotes: list[Footnote] = field(default_factory=list)
|
|
139
141
|
"""Footnotes"""
|
|
140
142
|
|
|
141
|
-
ChapterGetter = Callable[[], Chapter]
|
|
143
|
+
ChapterGetter = Callable[[], Chapter]
|
|
144
|
+
|
|
145
|
+
@dataclass
|
|
146
|
+
class HTMLTag:
|
|
147
|
+
"""Generic HTML tag representation."""
|
|
148
|
+
|
|
149
|
+
name: str
|
|
150
|
+
"""Tag name"""
|
|
151
|
+
|
|
152
|
+
attributes: list[tuple[str, str]] = field(default_factory=list)
|
|
153
|
+
"""List of (attribute, value) pairs"""
|
|
154
|
+
|
|
155
|
+
content: list["str | Mark | Formula | HTMLTag"] = field(default_factory=list)
|
|
156
|
+
"""Inner HTML content"""
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: epub-generator
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.4
|
|
4
4
|
Summary: A simple Python EPUB 3.0 generator with a single API call
|
|
5
5
|
License: MIT
|
|
6
6
|
Keywords: epub,epub3,ebook,generator,publishing
|
|
@@ -48,7 +48,7 @@ pip install epub-generator
|
|
|
48
48
|
### Generate Your First Book in 5 Minutes
|
|
49
49
|
|
|
50
50
|
```python
|
|
51
|
-
from epub_generator import generate_epub, EpubData, BookMeta, TocItem, Chapter,
|
|
51
|
+
from epub_generator import generate_epub, EpubData, BookMeta, TocItem, Chapter, TextBlock, TextKind
|
|
52
52
|
|
|
53
53
|
# Prepare book data
|
|
54
54
|
epub_data = EpubData(
|
|
@@ -61,9 +61,9 @@ epub_data = EpubData(
|
|
|
61
61
|
title="Chapter 1",
|
|
62
62
|
get_chapter=lambda: Chapter(
|
|
63
63
|
elements=[
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
64
|
+
TextBlock(kind=TextKind.HEADLINE, level=0, content=["Chapter 1"]),
|
|
65
|
+
TextBlock(kind=TextKind.BODY, level=0, content=["This is the first paragraph."]),
|
|
66
|
+
TextBlock(kind=TextKind.BODY, level=0, content=["This is the second paragraph."]),
|
|
67
67
|
]
|
|
68
68
|
),
|
|
69
69
|
),
|
|
@@ -80,7 +80,7 @@ That's it! You now have a valid EPUB 3.0 ebook file.
|
|
|
80
80
|
|
|
81
81
|
- **Minimal API**: Just one function call `generate_epub()`
|
|
82
82
|
- **EPUB 3.0**: Generates standards-compliant EPUB 3.0 format
|
|
83
|
-
- **Rich Content**: Supports text, images, tables, math formulas (block-level and inline), footnotes
|
|
83
|
+
- **Rich Content**: Supports text, images, tables, math formulas (block-level and inline), footnotes, custom HTML tags
|
|
84
84
|
- **Flexible Structure**: Nested chapters, prefaces, cover images
|
|
85
85
|
- **Math Support**: LaTeX to MathML/SVG conversion with inline formula support
|
|
86
86
|
- **Type Safe**: Full type annotations included
|
|
@@ -92,7 +92,7 @@ That's it! You now have a valid EPUB 3.0 ebook file.
|
|
|
92
92
|
```python
|
|
93
93
|
from datetime import datetime, timezone
|
|
94
94
|
from pathlib import Path
|
|
95
|
-
from epub_generator import generate_epub, EpubData, BookMeta, TocItem, Chapter,
|
|
95
|
+
from epub_generator import generate_epub, EpubData, BookMeta, TocItem, Chapter, TextBlock, TextKind
|
|
96
96
|
|
|
97
97
|
epub_data = EpubData(
|
|
98
98
|
meta=BookMeta(
|
|
@@ -111,8 +111,8 @@ epub_data = EpubData(
|
|
|
111
111
|
title="Chapter 1",
|
|
112
112
|
get_chapter=lambda: Chapter(
|
|
113
113
|
elements=[
|
|
114
|
-
|
|
115
|
-
|
|
114
|
+
TextBlock(kind=TextKind.HEADLINE, level=0, content=["Chapter 1"]),
|
|
115
|
+
TextBlock(kind=TextKind.BODY, level=0, content=["Main content..."]),
|
|
116
116
|
]
|
|
117
117
|
),
|
|
118
118
|
),
|
|
@@ -125,7 +125,7 @@ generate_epub(epub_data, "book_with_cover.epub")
|
|
|
125
125
|
### Nested Chapter Structure
|
|
126
126
|
|
|
127
127
|
```python
|
|
128
|
-
from epub_generator import generate_epub, EpubData, TocItem, Chapter,
|
|
128
|
+
from epub_generator import generate_epub, EpubData, TocItem, Chapter, TextBlock, TextKind
|
|
129
129
|
|
|
130
130
|
epub_data = EpubData(
|
|
131
131
|
chapters=[
|
|
@@ -136,7 +136,7 @@ epub_data = EpubData(
|
|
|
136
136
|
title="Chapter 1.1",
|
|
137
137
|
get_chapter=lambda: Chapter(
|
|
138
138
|
elements=[
|
|
139
|
-
|
|
139
|
+
TextBlock(kind=TextKind.BODY, level=0, content=["Content 1.1..."]),
|
|
140
140
|
]
|
|
141
141
|
),
|
|
142
142
|
),
|
|
@@ -144,7 +144,7 @@ epub_data = EpubData(
|
|
|
144
144
|
title="Chapter 1.2",
|
|
145
145
|
get_chapter=lambda: Chapter(
|
|
146
146
|
elements=[
|
|
147
|
-
|
|
147
|
+
TextBlock(kind=TextKind.BODY, level=0, content=["Content 1.2..."]),
|
|
148
148
|
]
|
|
149
149
|
),
|
|
150
150
|
),
|
|
@@ -160,7 +160,7 @@ generate_epub(epub_data, "book_with_nested_chapters.epub")
|
|
|
160
160
|
|
|
161
161
|
```python
|
|
162
162
|
from pathlib import Path
|
|
163
|
-
from epub_generator import generate_epub, EpubData, TocItem, Chapter,
|
|
163
|
+
from epub_generator import generate_epub, EpubData, TocItem, Chapter, TextBlock, TextKind, Image
|
|
164
164
|
|
|
165
165
|
epub_data = EpubData(
|
|
166
166
|
chapters=[
|
|
@@ -168,7 +168,7 @@ epub_data = EpubData(
|
|
|
168
168
|
title="Chapter 1",
|
|
169
169
|
get_chapter=lambda: Chapter(
|
|
170
170
|
elements=[
|
|
171
|
-
|
|
171
|
+
TextBlock(kind=TextKind.BODY, level=0, content=["Here's an image:"]),
|
|
172
172
|
Image(
|
|
173
173
|
path=Path("image.png"), # Image path
|
|
174
174
|
alt_text="Image description",
|
|
@@ -185,7 +185,7 @@ generate_epub(epub_data, "book_with_images.epub")
|
|
|
185
185
|
### Add Footnotes
|
|
186
186
|
|
|
187
187
|
```python
|
|
188
|
-
from epub_generator import generate_epub, EpubData, TocItem, Chapter,
|
|
188
|
+
from epub_generator import generate_epub, EpubData, TocItem, Chapter, TextBlock, TextKind, Mark, Footnote
|
|
189
189
|
|
|
190
190
|
epub_data = EpubData(
|
|
191
191
|
chapters=[
|
|
@@ -193,8 +193,9 @@ epub_data = EpubData(
|
|
|
193
193
|
title="Chapter 1",
|
|
194
194
|
get_chapter=lambda: Chapter(
|
|
195
195
|
elements=[
|
|
196
|
-
|
|
196
|
+
TextBlock(
|
|
197
197
|
kind=TextKind.BODY,
|
|
198
|
+
level=0,
|
|
198
199
|
content=[
|
|
199
200
|
"This is text with a footnote",
|
|
200
201
|
Mark(id=1), # Footnote marker
|
|
@@ -206,7 +207,7 @@ epub_data = EpubData(
|
|
|
206
207
|
Footnote(
|
|
207
208
|
id=1,
|
|
208
209
|
contents=[
|
|
209
|
-
|
|
210
|
+
TextBlock(kind=TextKind.BODY, level=0, content=["This is the footnote content."]),
|
|
210
211
|
],
|
|
211
212
|
),
|
|
212
213
|
],
|
|
@@ -221,7 +222,7 @@ generate_epub(epub_data, "book_with_footnotes.epub")
|
|
|
221
222
|
### Add Tables
|
|
222
223
|
|
|
223
224
|
```python
|
|
224
|
-
from epub_generator import generate_epub, EpubData, TocItem, Chapter,
|
|
225
|
+
from epub_generator import generate_epub, EpubData, TocItem, Chapter, TextBlock, TextKind, Table
|
|
225
226
|
|
|
226
227
|
epub_data = EpubData(
|
|
227
228
|
chapters=[
|
|
@@ -229,7 +230,7 @@ epub_data = EpubData(
|
|
|
229
230
|
title="Chapter 1",
|
|
230
231
|
get_chapter=lambda: Chapter(
|
|
231
232
|
elements=[
|
|
232
|
-
|
|
233
|
+
TextBlock(kind=TextKind.BODY, level=0, content=["Here's a table:"]),
|
|
233
234
|
Table(
|
|
234
235
|
html_content="""
|
|
235
236
|
<table>
|
|
@@ -253,7 +254,7 @@ generate_epub(epub_data, "book_with_tables.epub")
|
|
|
253
254
|
Block-level formulas:
|
|
254
255
|
|
|
255
256
|
```python
|
|
256
|
-
from epub_generator import generate_epub, EpubData, TocItem, Chapter,
|
|
257
|
+
from epub_generator import generate_epub, EpubData, TocItem, Chapter, TextBlock, TextKind, Formula, LaTeXRender
|
|
257
258
|
|
|
258
259
|
epub_data = EpubData(
|
|
259
260
|
chapters=[
|
|
@@ -261,7 +262,7 @@ epub_data = EpubData(
|
|
|
261
262
|
title="Chapter 1",
|
|
262
263
|
get_chapter=lambda: Chapter(
|
|
263
264
|
elements=[
|
|
264
|
-
|
|
265
|
+
TextBlock(kind=TextKind.BODY, level=0, content=["Pythagorean theorem:"]),
|
|
265
266
|
Formula(latex_expression="x^2 + y^2 = z^2"), # Block-level formula
|
|
266
267
|
]
|
|
267
268
|
),
|
|
@@ -282,8 +283,9 @@ epub_data = EpubData(
|
|
|
282
283
|
title="Chapter 1",
|
|
283
284
|
get_chapter=lambda: Chapter(
|
|
284
285
|
elements=[
|
|
285
|
-
|
|
286
|
+
TextBlock(
|
|
286
287
|
kind=TextKind.BODY,
|
|
288
|
+
level=0,
|
|
287
289
|
content=[
|
|
288
290
|
"The Pythagorean theorem ",
|
|
289
291
|
Formula(latex_expression="a^2 + b^2 = c^2"), # Inline formula
|
|
@@ -301,10 +303,46 @@ epub_data = EpubData(
|
|
|
301
303
|
generate_epub(epub_data, "book_with_inline_math.epub", latex_render=LaTeXRender.MATHML)
|
|
302
304
|
```
|
|
303
305
|
|
|
306
|
+
### Add Custom HTML Tags
|
|
307
|
+
|
|
308
|
+
You can embed custom HTML tags within text content:
|
|
309
|
+
|
|
310
|
+
```python
|
|
311
|
+
from epub_generator import generate_epub, EpubData, TocItem, Chapter, TextBlock, TextKind, HTMLTag
|
|
312
|
+
|
|
313
|
+
epub_data = EpubData(
|
|
314
|
+
chapters=[
|
|
315
|
+
TocItem(
|
|
316
|
+
title="Chapter 1",
|
|
317
|
+
get_chapter=lambda: Chapter(elements=[TextBlock(
|
|
318
|
+
kind=TextKind.BODY,
|
|
319
|
+
level=0,
|
|
320
|
+
content=[
|
|
321
|
+
"This is normal text with ",
|
|
322
|
+
HTMLTag(
|
|
323
|
+
name="span",
|
|
324
|
+
attributes=[("class", "highlight"), ("style", "color: red;")],
|
|
325
|
+
content=["highlighted content"],
|
|
326
|
+
),
|
|
327
|
+
" and more text with ",
|
|
328
|
+
HTMLTag(
|
|
329
|
+
name="strong",
|
|
330
|
+
content=["bold text"],
|
|
331
|
+
),
|
|
332
|
+
".",
|
|
333
|
+
],
|
|
334
|
+
)]),
|
|
335
|
+
),
|
|
336
|
+
],
|
|
337
|
+
)
|
|
338
|
+
|
|
339
|
+
generate_epub(epub_data, "book_with_html_tags.epub")
|
|
340
|
+
```
|
|
341
|
+
|
|
304
342
|
### Add Prefaces
|
|
305
343
|
|
|
306
344
|
```python
|
|
307
|
-
from epub_generator import generate_epub, EpubData, BookMeta, TocItem, Chapter,
|
|
345
|
+
from epub_generator import generate_epub, EpubData, BookMeta, TocItem, Chapter, TextBlock, TextKind
|
|
308
346
|
|
|
309
347
|
epub_data = EpubData(
|
|
310
348
|
meta=BookMeta(title="Book with Prefaces"),
|
|
@@ -313,8 +351,8 @@ epub_data = EpubData(
|
|
|
313
351
|
title="Preface",
|
|
314
352
|
get_chapter=lambda: Chapter(
|
|
315
353
|
elements=[
|
|
316
|
-
|
|
317
|
-
|
|
354
|
+
TextBlock(kind=TextKind.HEADLINE, level=0, content=["Preface"]),
|
|
355
|
+
TextBlock(kind=TextKind.BODY, level=0, content=["This is the preface content..."]),
|
|
318
356
|
]
|
|
319
357
|
),
|
|
320
358
|
),
|
|
@@ -324,7 +362,7 @@ epub_data = EpubData(
|
|
|
324
362
|
title="Chapter 1",
|
|
325
363
|
get_chapter=lambda: Chapter(
|
|
326
364
|
elements=[
|
|
327
|
-
|
|
365
|
+
TextBlock(kind=TextKind.BODY, level=0, content=["Main content..."]),
|
|
328
366
|
]
|
|
329
367
|
),
|
|
330
368
|
),
|
|
@@ -417,12 +455,13 @@ class Chapter:
|
|
|
417
455
|
|
|
418
456
|
`ContentBlock` is a union of:
|
|
419
457
|
|
|
420
|
-
- **`
|
|
458
|
+
- **`TextBlock`**: Text paragraph
|
|
421
459
|
```python
|
|
422
460
|
@dataclass
|
|
423
|
-
class
|
|
424
|
-
kind: TextKind
|
|
425
|
-
|
|
461
|
+
class TextBlock:
|
|
462
|
+
kind: TextKind # BODY | HEADLINE | QUOTE
|
|
463
|
+
level: int # Heading level (0→h1, 1→h2, max h6; only for HEADLINE)
|
|
464
|
+
content: list[str | Mark | Formula | HTMLTag] # Text with optional marks, inline formulas, and HTML tags
|
|
426
465
|
```
|
|
427
466
|
|
|
428
467
|
- **`Image`**: Image reference
|
|
@@ -447,6 +486,15 @@ class Chapter:
|
|
|
447
486
|
latex_expression: str # LaTeX expression
|
|
448
487
|
```
|
|
449
488
|
|
|
489
|
+
- **`HTMLTag`**: HTML tag
|
|
490
|
+
```python
|
|
491
|
+
@dataclass
|
|
492
|
+
class HTMLTag:
|
|
493
|
+
name: str # Tag name (e.g., "span", "div")
|
|
494
|
+
attributes: list[tuple[str, str]] = [] # List of (attribute, value) pairs
|
|
495
|
+
content: list[str | Mark | Formula | HTMLTag] = [] # Inner HTML content
|
|
496
|
+
```
|
|
497
|
+
|
|
450
498
|
#### `Footnote`
|
|
451
499
|
|
|
452
500
|
Footnote/citation.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
epub_generator/__init__.py,sha256=
|
|
1
|
+
epub_generator/__init__.py,sha256=CRtP7zjqNPxOA_m4S8Jgavuw_KgaKpoBW5kdgqUivLQ,648
|
|
2
2
|
epub_generator/context.py,sha256=AggXhRiOg70WZTLXF78LHA4coo3fa77OvKVe5wtgP6A,4495
|
|
3
3
|
epub_generator/data/container.xml.jinja,sha256=SkACyZgsAVUS5lmiCEhq3SpbFspYdyCnRNjWnLztLt0,252
|
|
4
4
|
epub_generator/data/content.opf.jinja,sha256=DDaR9GZnSBcpNk2BWUu56Uo_248TA91AxE4tKsBuKnQ,2839
|
|
@@ -9,16 +9,17 @@ epub_generator/data/part.xhtml.jinja,sha256=FEQaUjHfCy7EJyyvYZj-6T-lkDcsmz1wvsk0
|
|
|
9
9
|
epub_generator/data/style.css.jinja,sha256=HyGWoevaZD9xPDJeMQY_1xmM0f6aK0prmqoW3mhTGp0,1072
|
|
10
10
|
epub_generator/generation/__init__.py,sha256=UIscwHa8ocr2D1mk1KaP-zi3P1x9eYJzxTo0RJ2dnks,35
|
|
11
11
|
epub_generator/generation/gen_asset.py,sha256=0muwCvAohODC76F9G9_UBibRPQSpmMJkgQxlCsM7QcQ,4480
|
|
12
|
-
epub_generator/generation/gen_chapter.py,sha256=
|
|
13
|
-
epub_generator/generation/gen_epub.py,sha256=
|
|
12
|
+
epub_generator/generation/gen_chapter.py,sha256=Irb0uJjK8Q5PnHoK4PFP7CIKKzbfhIK_4thvin6hg6g,5505
|
|
13
|
+
epub_generator/generation/gen_epub.py,sha256=zkG0U5_g3FY-D6zkYGqp844IgWYJhbAqf6CnX2Do71Y,6412
|
|
14
14
|
epub_generator/generation/gen_nav.py,sha256=D-ZNsbm26AEAovbXtx1wSwTfH4Q8H2WYfoYeQ1Sb9bk,2813
|
|
15
15
|
epub_generator/generation/gen_toc.py,sha256=yt7GYu8Rfz9aw_GPZFUl9H3BKd1za1hSm2hhp8wyI68,2488
|
|
16
16
|
epub_generator/generation/xml_utils.py,sha256=xMcNZl8CaV21XYx2yeykkHhvnq5N7yRHfIFu5KRlRHc,1261
|
|
17
|
+
epub_generator/html_tag.py,sha256=P_Y0uRStCEEh7cCtpvK4t432NEcY9OLntAznvdxUF5k,343
|
|
17
18
|
epub_generator/i18n.py,sha256=GQjpHO7t8_0rXNuoYmO-G7_9nCF7S5kluBG0ip_2jIA,622
|
|
18
19
|
epub_generator/options.py,sha256=Er1dnaNvzDSnZRSRJGSqhkJsv1XtsCW2Ym_hUc8o_QI,181
|
|
19
20
|
epub_generator/template.py,sha256=RdN2QRICIrYMzpxCU_x4m4V9WWZEP9VvT6QLp2YCm90,1556
|
|
20
|
-
epub_generator/types.py,sha256=
|
|
21
|
-
epub_generator-0.1.
|
|
22
|
-
epub_generator-0.1.
|
|
23
|
-
epub_generator-0.1.
|
|
24
|
-
epub_generator-0.1.
|
|
21
|
+
epub_generator/types.py,sha256=Raz6MT-aIkMp6Yw9hTu4HP_ySg4kMC-YJ_o0cjYzu_A,4059
|
|
22
|
+
epub_generator-0.1.4.dist-info/LICENSE,sha256=9Zt_a4mrzkvR2rc0UbqTgbboIjWuumDFgeQyKos0H2E,1066
|
|
23
|
+
epub_generator-0.1.4.dist-info/METADATA,sha256=cpydosW4bVyknIbCxKP4DAhl-M8NSct7-9jX9M4BISw,16555
|
|
24
|
+
epub_generator-0.1.4.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
|
|
25
|
+
epub_generator-0.1.4.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|