lhtml-site 1.0.0__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.
Files changed (421) hide show
  1. lhtml_site/__init__.py +0 -0
  2. lhtml_site/browser.py +59 -0
  3. lhtml_site/build_output.py +80 -0
  4. lhtml_site/configuration.py +354 -0
  5. lhtml_site/configure_example.yaml +113 -0
  6. lhtml_site/credits.py +198 -0
  7. lhtml_site/deck.py +423 -0
  8. lhtml_site/dependencies.py +358 -0
  9. lhtml_site/design.py +292 -0
  10. lhtml_site/design_checks.py +125 -0
  11. lhtml_site/development.py +210 -0
  12. lhtml_site/docs/agents.md +250 -0
  13. lhtml_site/docs/development.md +98 -0
  14. lhtml_site/docs/reference.md +1076 -0
  15. lhtml_site/doctor.py +191 -0
  16. lhtml_site/extensions.py +151 -0
  17. lhtml_site/feedback.js +151 -0
  18. lhtml_site/feedback.py +145 -0
  19. lhtml_site/figures.py +117 -0
  20. lhtml_site/filesystem.py +182 -0
  21. lhtml_site/front_matter.py +36 -0
  22. lhtml_site/generate.py +1012 -0
  23. lhtml_site/generator_tool.py +159 -0
  24. lhtml_site/headings.py +221 -0
  25. lhtml_site/index_page.py +39 -0
  26. lhtml_site/layout/__init__.py +12 -0
  27. lhtml_site/layout/analysis.py +785 -0
  28. lhtml_site/layout/build.py +318 -0
  29. lhtml_site/layout/findings.py +251 -0
  30. lhtml_site/layout/geometry.py +28 -0
  31. lhtml_site/layout/measure.py +367 -0
  32. lhtml_site/layout/page.js +1087 -0
  33. lhtml_site/layout/report.py +354 -0
  34. lhtml_site/layout_options.py +110 -0
  35. lhtml_site/lint.py +322 -0
  36. lhtml_site/logger.py +70 -0
  37. lhtml_site/markdown_page.py +110 -0
  38. lhtml_site/menu.py +64 -0
  39. lhtml_site/pages.py +276 -0
  40. lhtml_site/pdf_export.py +227 -0
  41. lhtml_site/plugins/code_include.py +197 -0
  42. lhtml_site/plugins/pre_include.py +20 -0
  43. lhtml_site/project.py +136 -0
  44. lhtml_site/report_lock.py +80 -0
  45. lhtml_site/source_map.py +369 -0
  46. lhtml_site/source_scan.py +202 -0
  47. lhtml_site/starters/site/01_welcome/assets/diagram.svg +7 -0
  48. lhtml_site/starters/site/01_welcome/index.html.j2 +18 -0
  49. lhtml_site/starters/site/02_writing/index.html.j2 +20 -0
  50. lhtml_site/starters/slides/01_title/index.html.j2 +10 -0
  51. lhtml_site/starters/slides/02_text/index.html.j2 +14 -0
  52. lhtml_site/starters/slides/03_two_columns/index.html.j2 +18 -0
  53. lhtml_site/starters/slides/04_image/assets/diagram.svg +7 -0
  54. lhtml_site/starters/slides/04_image/index.html.j2 +14 -0
  55. lhtml_site/structure.py +84 -0
  56. lhtml_site/theme.py +112 -0
  57. lhtml_site/themes/slides/css/classes.css +27 -0
  58. lhtml_site/themes/slides/css/code.css +71 -0
  59. lhtml_site/themes/slides/css/font.css +227 -0
  60. lhtml_site/themes/slides/css/icons.css +27 -0
  61. lhtml_site/themes/slides/css/main.css +141 -0
  62. lhtml_site/themes/slides/css/pdf_export.css +6 -0
  63. lhtml_site/themes/slides/design.yaml +335 -0
  64. lhtml_site/themes/slides/fonts/source_code_pro/LICENSE.md +93 -0
  65. lhtml_site/themes/slides/fonts/source_code_pro/README.md +18 -0
  66. lhtml_site/themes/slides/fonts/source_code_pro/WOFF2/TTF/SourceCodePro-Black.ttf.woff2 +0 -0
  67. lhtml_site/themes/slides/fonts/source_code_pro/WOFF2/TTF/SourceCodePro-BlackIt.ttf.woff2 +0 -0
  68. lhtml_site/themes/slides/fonts/source_code_pro/WOFF2/TTF/SourceCodePro-Bold.ttf.woff2 +0 -0
  69. lhtml_site/themes/slides/fonts/source_code_pro/WOFF2/TTF/SourceCodePro-BoldIt.ttf.woff2 +0 -0
  70. lhtml_site/themes/slides/fonts/source_code_pro/WOFF2/TTF/SourceCodePro-ExtraLight.ttf.woff2 +0 -0
  71. lhtml_site/themes/slides/fonts/source_code_pro/WOFF2/TTF/SourceCodePro-ExtraLightIt.ttf.woff2 +0 -0
  72. lhtml_site/themes/slides/fonts/source_code_pro/WOFF2/TTF/SourceCodePro-It.ttf.woff2 +0 -0
  73. lhtml_site/themes/slides/fonts/source_code_pro/WOFF2/TTF/SourceCodePro-Light.ttf.woff2 +0 -0
  74. lhtml_site/themes/slides/fonts/source_code_pro/WOFF2/TTF/SourceCodePro-LightIt.ttf.woff2 +0 -0
  75. lhtml_site/themes/slides/fonts/source_code_pro/WOFF2/TTF/SourceCodePro-Medium.ttf.woff2 +0 -0
  76. lhtml_site/themes/slides/fonts/source_code_pro/WOFF2/TTF/SourceCodePro-MediumIt.ttf.woff2 +0 -0
  77. lhtml_site/themes/slides/fonts/source_code_pro/WOFF2/TTF/SourceCodePro-Regular.ttf.woff2 +0 -0
  78. lhtml_site/themes/slides/fonts/source_code_pro/WOFF2/TTF/SourceCodePro-Semibold.ttf.woff2 +0 -0
  79. lhtml_site/themes/slides/fonts/source_code_pro/WOFF2/TTF/SourceCodePro-SemiboldIt.ttf.woff2 +0 -0
  80. lhtml_site/themes/slides/fonts/source_serif_pro/LICENSE.md +93 -0
  81. lhtml_site/themes/slides/fonts/source_serif_pro/README.md +18 -0
  82. lhtml_site/themes/slides/fonts/source_serif_pro/WOFF2/TTF/SourceSerifPro-Black.ttf.woff2 +0 -0
  83. lhtml_site/themes/slides/fonts/source_serif_pro/WOFF2/TTF/SourceSerifPro-BlackIt.ttf.woff2 +0 -0
  84. lhtml_site/themes/slides/fonts/source_serif_pro/WOFF2/TTF/SourceSerifPro-Bold.ttf.woff2 +0 -0
  85. lhtml_site/themes/slides/fonts/source_serif_pro/WOFF2/TTF/SourceSerifPro-BoldIt.ttf.woff2 +0 -0
  86. lhtml_site/themes/slides/fonts/source_serif_pro/WOFF2/TTF/SourceSerifPro-ExtraLight.ttf.woff2 +0 -0
  87. lhtml_site/themes/slides/fonts/source_serif_pro/WOFF2/TTF/SourceSerifPro-ExtraLightIt.ttf.woff2 +0 -0
  88. lhtml_site/themes/slides/fonts/source_serif_pro/WOFF2/TTF/SourceSerifPro-It.ttf.woff2 +0 -0
  89. lhtml_site/themes/slides/fonts/source_serif_pro/WOFF2/TTF/SourceSerifPro-Light.ttf.woff2 +0 -0
  90. lhtml_site/themes/slides/fonts/source_serif_pro/WOFF2/TTF/SourceSerifPro-LightIt.ttf.woff2 +0 -0
  91. lhtml_site/themes/slides/fonts/source_serif_pro/WOFF2/TTF/SourceSerifPro-Regular.ttf.woff2 +0 -0
  92. lhtml_site/themes/slides/fonts/source_serif_pro/WOFF2/TTF/SourceSerifPro-Semibold.ttf.woff2 +0 -0
  93. lhtml_site/themes/slides/fonts/source_serif_pro/WOFF2/TTF/SourceSerifPro-SemiboldIt.ttf.woff2 +0 -0
  94. lhtml_site/themes/slides/icons/left_disabled.svg +1 -0
  95. lhtml_site/themes/slides/icons/left_enabled.svg +1 -0
  96. lhtml_site/themes/slides/icons/left_hover.svg +1 -0
  97. lhtml_site/themes/slides/icons/menu.svg +1 -0
  98. lhtml_site/themes/slides/icons/menu_hover.svg +1 -0
  99. lhtml_site/themes/slides/icons/right_disabled.svg +1 -0
  100. lhtml_site/themes/slides/icons/right_enabled.svg +1 -0
  101. lhtml_site/themes/slides/icons/right_hover.svg +1 -0
  102. lhtml_site/themes/slides/js/menu.js +63 -0
  103. lhtml_site/themes/slides/js/navigation.js +84 -0
  104. lhtml_site/themes/slides/js/presentation_resize_page.js +40 -0
  105. lhtml_site/themes/slides/js/readiness.js +20 -0
  106. lhtml_site/themes/slides/libs/katex/contrib/auto-render.min.js +1 -0
  107. lhtml_site/themes/slides/libs/katex/contrib/copy-tex.min.css +1 -0
  108. lhtml_site/themes/slides/libs/katex/contrib/copy-tex.min.js +1 -0
  109. lhtml_site/themes/slides/libs/katex/contrib/mathtex-script-type.min.js +1 -0
  110. lhtml_site/themes/slides/libs/katex/contrib/mhchem.min.js +1 -0
  111. lhtml_site/themes/slides/libs/katex/contrib/render-a11y-string.min.js +1 -0
  112. lhtml_site/themes/slides/libs/katex/fonts/KaTeX_AMS-Regular.ttf +0 -0
  113. lhtml_site/themes/slides/libs/katex/fonts/KaTeX_AMS-Regular.woff +0 -0
  114. lhtml_site/themes/slides/libs/katex/fonts/KaTeX_AMS-Regular.woff2 +0 -0
  115. lhtml_site/themes/slides/libs/katex/fonts/KaTeX_Caligraphic-Bold.ttf +0 -0
  116. lhtml_site/themes/slides/libs/katex/fonts/KaTeX_Caligraphic-Bold.woff +0 -0
  117. lhtml_site/themes/slides/libs/katex/fonts/KaTeX_Caligraphic-Bold.woff2 +0 -0
  118. lhtml_site/themes/slides/libs/katex/fonts/KaTeX_Caligraphic-Regular.ttf +0 -0
  119. lhtml_site/themes/slides/libs/katex/fonts/KaTeX_Caligraphic-Regular.woff +0 -0
  120. lhtml_site/themes/slides/libs/katex/fonts/KaTeX_Caligraphic-Regular.woff2 +0 -0
  121. lhtml_site/themes/slides/libs/katex/fonts/KaTeX_Fraktur-Bold.ttf +0 -0
  122. lhtml_site/themes/slides/libs/katex/fonts/KaTeX_Fraktur-Bold.woff +0 -0
  123. lhtml_site/themes/slides/libs/katex/fonts/KaTeX_Fraktur-Bold.woff2 +0 -0
  124. lhtml_site/themes/slides/libs/katex/fonts/KaTeX_Fraktur-Regular.ttf +0 -0
  125. lhtml_site/themes/slides/libs/katex/fonts/KaTeX_Fraktur-Regular.woff +0 -0
  126. lhtml_site/themes/slides/libs/katex/fonts/KaTeX_Fraktur-Regular.woff2 +0 -0
  127. lhtml_site/themes/slides/libs/katex/fonts/KaTeX_Main-Bold.ttf +0 -0
  128. lhtml_site/themes/slides/libs/katex/fonts/KaTeX_Main-Bold.woff +0 -0
  129. lhtml_site/themes/slides/libs/katex/fonts/KaTeX_Main-Bold.woff2 +0 -0
  130. lhtml_site/themes/slides/libs/katex/fonts/KaTeX_Main-BoldItalic.ttf +0 -0
  131. lhtml_site/themes/slides/libs/katex/fonts/KaTeX_Main-BoldItalic.woff +0 -0
  132. lhtml_site/themes/slides/libs/katex/fonts/KaTeX_Main-BoldItalic.woff2 +0 -0
  133. lhtml_site/themes/slides/libs/katex/fonts/KaTeX_Main-Italic.ttf +0 -0
  134. lhtml_site/themes/slides/libs/katex/fonts/KaTeX_Main-Italic.woff +0 -0
  135. lhtml_site/themes/slides/libs/katex/fonts/KaTeX_Main-Italic.woff2 +0 -0
  136. lhtml_site/themes/slides/libs/katex/fonts/KaTeX_Main-Regular.ttf +0 -0
  137. lhtml_site/themes/slides/libs/katex/fonts/KaTeX_Main-Regular.woff +0 -0
  138. lhtml_site/themes/slides/libs/katex/fonts/KaTeX_Main-Regular.woff2 +0 -0
  139. lhtml_site/themes/slides/libs/katex/fonts/KaTeX_Math-BoldItalic.ttf +0 -0
  140. lhtml_site/themes/slides/libs/katex/fonts/KaTeX_Math-BoldItalic.woff +0 -0
  141. lhtml_site/themes/slides/libs/katex/fonts/KaTeX_Math-BoldItalic.woff2 +0 -0
  142. lhtml_site/themes/slides/libs/katex/fonts/KaTeX_Math-Italic.ttf +0 -0
  143. lhtml_site/themes/slides/libs/katex/fonts/KaTeX_Math-Italic.woff +0 -0
  144. lhtml_site/themes/slides/libs/katex/fonts/KaTeX_Math-Italic.woff2 +0 -0
  145. lhtml_site/themes/slides/libs/katex/fonts/KaTeX_SansSerif-Bold.ttf +0 -0
  146. lhtml_site/themes/slides/libs/katex/fonts/KaTeX_SansSerif-Bold.woff +0 -0
  147. lhtml_site/themes/slides/libs/katex/fonts/KaTeX_SansSerif-Bold.woff2 +0 -0
  148. lhtml_site/themes/slides/libs/katex/fonts/KaTeX_SansSerif-Italic.ttf +0 -0
  149. lhtml_site/themes/slides/libs/katex/fonts/KaTeX_SansSerif-Italic.woff +0 -0
  150. lhtml_site/themes/slides/libs/katex/fonts/KaTeX_SansSerif-Italic.woff2 +0 -0
  151. lhtml_site/themes/slides/libs/katex/fonts/KaTeX_SansSerif-Regular.ttf +0 -0
  152. lhtml_site/themes/slides/libs/katex/fonts/KaTeX_SansSerif-Regular.woff +0 -0
  153. lhtml_site/themes/slides/libs/katex/fonts/KaTeX_SansSerif-Regular.woff2 +0 -0
  154. lhtml_site/themes/slides/libs/katex/fonts/KaTeX_Script-Regular.ttf +0 -0
  155. lhtml_site/themes/slides/libs/katex/fonts/KaTeX_Script-Regular.woff +0 -0
  156. lhtml_site/themes/slides/libs/katex/fonts/KaTeX_Script-Regular.woff2 +0 -0
  157. lhtml_site/themes/slides/libs/katex/fonts/KaTeX_Size1-Regular.ttf +0 -0
  158. lhtml_site/themes/slides/libs/katex/fonts/KaTeX_Size1-Regular.woff +0 -0
  159. lhtml_site/themes/slides/libs/katex/fonts/KaTeX_Size1-Regular.woff2 +0 -0
  160. lhtml_site/themes/slides/libs/katex/fonts/KaTeX_Size2-Regular.ttf +0 -0
  161. lhtml_site/themes/slides/libs/katex/fonts/KaTeX_Size2-Regular.woff +0 -0
  162. lhtml_site/themes/slides/libs/katex/fonts/KaTeX_Size2-Regular.woff2 +0 -0
  163. lhtml_site/themes/slides/libs/katex/fonts/KaTeX_Size3-Regular.ttf +0 -0
  164. lhtml_site/themes/slides/libs/katex/fonts/KaTeX_Size3-Regular.woff +0 -0
  165. lhtml_site/themes/slides/libs/katex/fonts/KaTeX_Size3-Regular.woff2 +0 -0
  166. lhtml_site/themes/slides/libs/katex/fonts/KaTeX_Size4-Regular.ttf +0 -0
  167. lhtml_site/themes/slides/libs/katex/fonts/KaTeX_Size4-Regular.woff +0 -0
  168. lhtml_site/themes/slides/libs/katex/fonts/KaTeX_Size4-Regular.woff2 +0 -0
  169. lhtml_site/themes/slides/libs/katex/fonts/KaTeX_Typewriter-Regular.ttf +0 -0
  170. lhtml_site/themes/slides/libs/katex/fonts/KaTeX_Typewriter-Regular.woff +0 -0
  171. lhtml_site/themes/slides/libs/katex/fonts/KaTeX_Typewriter-Regular.woff2 +0 -0
  172. lhtml_site/themes/slides/libs/katex/katex.min.css +1 -0
  173. lhtml_site/themes/slides/libs/katex/katex.min.js +1 -0
  174. lhtml_site/themes/slides/template/base.html +80 -0
  175. lhtml_site/themes/slides/theme.yaml +11 -0
  176. lhtml_site/themes/slides-pdf/css/classes.css +27 -0
  177. lhtml_site/themes/slides-pdf/css/code.css +71 -0
  178. lhtml_site/themes/slides-pdf/css/font.css +227 -0
  179. lhtml_site/themes/slides-pdf/css/icons.css +27 -0
  180. lhtml_site/themes/slides-pdf/css/main.css +141 -0
  181. lhtml_site/themes/slides-pdf/css/pdf_export.css +6 -0
  182. lhtml_site/themes/slides-pdf/design.yaml +3 -0
  183. lhtml_site/themes/slides-pdf/fonts/source_code_pro/LICENSE.md +93 -0
  184. lhtml_site/themes/slides-pdf/fonts/source_code_pro/README.md +18 -0
  185. lhtml_site/themes/slides-pdf/fonts/source_code_pro/WOFF2/TTF/SourceCodePro-Black.ttf.woff2 +0 -0
  186. lhtml_site/themes/slides-pdf/fonts/source_code_pro/WOFF2/TTF/SourceCodePro-BlackIt.ttf.woff2 +0 -0
  187. lhtml_site/themes/slides-pdf/fonts/source_code_pro/WOFF2/TTF/SourceCodePro-Bold.ttf.woff2 +0 -0
  188. lhtml_site/themes/slides-pdf/fonts/source_code_pro/WOFF2/TTF/SourceCodePro-BoldIt.ttf.woff2 +0 -0
  189. lhtml_site/themes/slides-pdf/fonts/source_code_pro/WOFF2/TTF/SourceCodePro-ExtraLight.ttf.woff2 +0 -0
  190. lhtml_site/themes/slides-pdf/fonts/source_code_pro/WOFF2/TTF/SourceCodePro-ExtraLightIt.ttf.woff2 +0 -0
  191. lhtml_site/themes/slides-pdf/fonts/source_code_pro/WOFF2/TTF/SourceCodePro-It.ttf.woff2 +0 -0
  192. lhtml_site/themes/slides-pdf/fonts/source_code_pro/WOFF2/TTF/SourceCodePro-Light.ttf.woff2 +0 -0
  193. lhtml_site/themes/slides-pdf/fonts/source_code_pro/WOFF2/TTF/SourceCodePro-LightIt.ttf.woff2 +0 -0
  194. lhtml_site/themes/slides-pdf/fonts/source_code_pro/WOFF2/TTF/SourceCodePro-Medium.ttf.woff2 +0 -0
  195. lhtml_site/themes/slides-pdf/fonts/source_code_pro/WOFF2/TTF/SourceCodePro-MediumIt.ttf.woff2 +0 -0
  196. lhtml_site/themes/slides-pdf/fonts/source_code_pro/WOFF2/TTF/SourceCodePro-Regular.ttf.woff2 +0 -0
  197. lhtml_site/themes/slides-pdf/fonts/source_code_pro/WOFF2/TTF/SourceCodePro-Semibold.ttf.woff2 +0 -0
  198. lhtml_site/themes/slides-pdf/fonts/source_code_pro/WOFF2/TTF/SourceCodePro-SemiboldIt.ttf.woff2 +0 -0
  199. lhtml_site/themes/slides-pdf/fonts/source_serif_pro/LICENSE.md +93 -0
  200. lhtml_site/themes/slides-pdf/fonts/source_serif_pro/README.md +18 -0
  201. lhtml_site/themes/slides-pdf/fonts/source_serif_pro/WOFF2/TTF/SourceSerifPro-Black.ttf.woff2 +0 -0
  202. lhtml_site/themes/slides-pdf/fonts/source_serif_pro/WOFF2/TTF/SourceSerifPro-BlackIt.ttf.woff2 +0 -0
  203. lhtml_site/themes/slides-pdf/fonts/source_serif_pro/WOFF2/TTF/SourceSerifPro-Bold.ttf.woff2 +0 -0
  204. lhtml_site/themes/slides-pdf/fonts/source_serif_pro/WOFF2/TTF/SourceSerifPro-BoldIt.ttf.woff2 +0 -0
  205. lhtml_site/themes/slides-pdf/fonts/source_serif_pro/WOFF2/TTF/SourceSerifPro-ExtraLight.ttf.woff2 +0 -0
  206. lhtml_site/themes/slides-pdf/fonts/source_serif_pro/WOFF2/TTF/SourceSerifPro-ExtraLightIt.ttf.woff2 +0 -0
  207. lhtml_site/themes/slides-pdf/fonts/source_serif_pro/WOFF2/TTF/SourceSerifPro-It.ttf.woff2 +0 -0
  208. lhtml_site/themes/slides-pdf/fonts/source_serif_pro/WOFF2/TTF/SourceSerifPro-Light.ttf.woff2 +0 -0
  209. lhtml_site/themes/slides-pdf/fonts/source_serif_pro/WOFF2/TTF/SourceSerifPro-LightIt.ttf.woff2 +0 -0
  210. lhtml_site/themes/slides-pdf/fonts/source_serif_pro/WOFF2/TTF/SourceSerifPro-Regular.ttf.woff2 +0 -0
  211. lhtml_site/themes/slides-pdf/fonts/source_serif_pro/WOFF2/TTF/SourceSerifPro-Semibold.ttf.woff2 +0 -0
  212. lhtml_site/themes/slides-pdf/fonts/source_serif_pro/WOFF2/TTF/SourceSerifPro-SemiboldIt.ttf.woff2 +0 -0
  213. lhtml_site/themes/slides-pdf/icons/left_disabled.svg +1 -0
  214. lhtml_site/themes/slides-pdf/icons/left_enabled.svg +1 -0
  215. lhtml_site/themes/slides-pdf/icons/left_hover.svg +1 -0
  216. lhtml_site/themes/slides-pdf/icons/menu.svg +1 -0
  217. lhtml_site/themes/slides-pdf/icons/menu_hover.svg +1 -0
  218. lhtml_site/themes/slides-pdf/icons/right_disabled.svg +1 -0
  219. lhtml_site/themes/slides-pdf/icons/right_enabled.svg +1 -0
  220. lhtml_site/themes/slides-pdf/icons/right_hover.svg +1 -0
  221. lhtml_site/themes/slides-pdf/js/menu.js +62 -0
  222. lhtml_site/themes/slides-pdf/js/navigation.js +84 -0
  223. lhtml_site/themes/slides-pdf/js/presentation_resize_page.js +40 -0
  224. lhtml_site/themes/slides-pdf/libs/katex/contrib/auto-render.min.js +1 -0
  225. lhtml_site/themes/slides-pdf/libs/katex/contrib/copy-tex.min.css +1 -0
  226. lhtml_site/themes/slides-pdf/libs/katex/contrib/copy-tex.min.js +1 -0
  227. lhtml_site/themes/slides-pdf/libs/katex/contrib/mathtex-script-type.min.js +1 -0
  228. lhtml_site/themes/slides-pdf/libs/katex/contrib/mhchem.min.js +1 -0
  229. lhtml_site/themes/slides-pdf/libs/katex/contrib/render-a11y-string.min.js +1 -0
  230. lhtml_site/themes/slides-pdf/libs/katex/fonts/KaTeX_AMS-Regular.ttf +0 -0
  231. lhtml_site/themes/slides-pdf/libs/katex/fonts/KaTeX_AMS-Regular.woff +0 -0
  232. lhtml_site/themes/slides-pdf/libs/katex/fonts/KaTeX_AMS-Regular.woff2 +0 -0
  233. lhtml_site/themes/slides-pdf/libs/katex/fonts/KaTeX_Caligraphic-Bold.ttf +0 -0
  234. lhtml_site/themes/slides-pdf/libs/katex/fonts/KaTeX_Caligraphic-Bold.woff +0 -0
  235. lhtml_site/themes/slides-pdf/libs/katex/fonts/KaTeX_Caligraphic-Bold.woff2 +0 -0
  236. lhtml_site/themes/slides-pdf/libs/katex/fonts/KaTeX_Caligraphic-Regular.ttf +0 -0
  237. lhtml_site/themes/slides-pdf/libs/katex/fonts/KaTeX_Caligraphic-Regular.woff +0 -0
  238. lhtml_site/themes/slides-pdf/libs/katex/fonts/KaTeX_Caligraphic-Regular.woff2 +0 -0
  239. lhtml_site/themes/slides-pdf/libs/katex/fonts/KaTeX_Fraktur-Bold.ttf +0 -0
  240. lhtml_site/themes/slides-pdf/libs/katex/fonts/KaTeX_Fraktur-Bold.woff +0 -0
  241. lhtml_site/themes/slides-pdf/libs/katex/fonts/KaTeX_Fraktur-Bold.woff2 +0 -0
  242. lhtml_site/themes/slides-pdf/libs/katex/fonts/KaTeX_Fraktur-Regular.ttf +0 -0
  243. lhtml_site/themes/slides-pdf/libs/katex/fonts/KaTeX_Fraktur-Regular.woff +0 -0
  244. lhtml_site/themes/slides-pdf/libs/katex/fonts/KaTeX_Fraktur-Regular.woff2 +0 -0
  245. lhtml_site/themes/slides-pdf/libs/katex/fonts/KaTeX_Main-Bold.ttf +0 -0
  246. lhtml_site/themes/slides-pdf/libs/katex/fonts/KaTeX_Main-Bold.woff +0 -0
  247. lhtml_site/themes/slides-pdf/libs/katex/fonts/KaTeX_Main-Bold.woff2 +0 -0
  248. lhtml_site/themes/slides-pdf/libs/katex/fonts/KaTeX_Main-BoldItalic.ttf +0 -0
  249. lhtml_site/themes/slides-pdf/libs/katex/fonts/KaTeX_Main-BoldItalic.woff +0 -0
  250. lhtml_site/themes/slides-pdf/libs/katex/fonts/KaTeX_Main-BoldItalic.woff2 +0 -0
  251. lhtml_site/themes/slides-pdf/libs/katex/fonts/KaTeX_Main-Italic.ttf +0 -0
  252. lhtml_site/themes/slides-pdf/libs/katex/fonts/KaTeX_Main-Italic.woff +0 -0
  253. lhtml_site/themes/slides-pdf/libs/katex/fonts/KaTeX_Main-Italic.woff2 +0 -0
  254. lhtml_site/themes/slides-pdf/libs/katex/fonts/KaTeX_Main-Regular.ttf +0 -0
  255. lhtml_site/themes/slides-pdf/libs/katex/fonts/KaTeX_Main-Regular.woff +0 -0
  256. lhtml_site/themes/slides-pdf/libs/katex/fonts/KaTeX_Main-Regular.woff2 +0 -0
  257. lhtml_site/themes/slides-pdf/libs/katex/fonts/KaTeX_Math-BoldItalic.ttf +0 -0
  258. lhtml_site/themes/slides-pdf/libs/katex/fonts/KaTeX_Math-BoldItalic.woff +0 -0
  259. lhtml_site/themes/slides-pdf/libs/katex/fonts/KaTeX_Math-BoldItalic.woff2 +0 -0
  260. lhtml_site/themes/slides-pdf/libs/katex/fonts/KaTeX_Math-Italic.ttf +0 -0
  261. lhtml_site/themes/slides-pdf/libs/katex/fonts/KaTeX_Math-Italic.woff +0 -0
  262. lhtml_site/themes/slides-pdf/libs/katex/fonts/KaTeX_Math-Italic.woff2 +0 -0
  263. lhtml_site/themes/slides-pdf/libs/katex/fonts/KaTeX_SansSerif-Bold.ttf +0 -0
  264. lhtml_site/themes/slides-pdf/libs/katex/fonts/KaTeX_SansSerif-Bold.woff +0 -0
  265. lhtml_site/themes/slides-pdf/libs/katex/fonts/KaTeX_SansSerif-Bold.woff2 +0 -0
  266. lhtml_site/themes/slides-pdf/libs/katex/fonts/KaTeX_SansSerif-Italic.ttf +0 -0
  267. lhtml_site/themes/slides-pdf/libs/katex/fonts/KaTeX_SansSerif-Italic.woff +0 -0
  268. lhtml_site/themes/slides-pdf/libs/katex/fonts/KaTeX_SansSerif-Italic.woff2 +0 -0
  269. lhtml_site/themes/slides-pdf/libs/katex/fonts/KaTeX_SansSerif-Regular.ttf +0 -0
  270. lhtml_site/themes/slides-pdf/libs/katex/fonts/KaTeX_SansSerif-Regular.woff +0 -0
  271. lhtml_site/themes/slides-pdf/libs/katex/fonts/KaTeX_SansSerif-Regular.woff2 +0 -0
  272. lhtml_site/themes/slides-pdf/libs/katex/fonts/KaTeX_Script-Regular.ttf +0 -0
  273. lhtml_site/themes/slides-pdf/libs/katex/fonts/KaTeX_Script-Regular.woff +0 -0
  274. lhtml_site/themes/slides-pdf/libs/katex/fonts/KaTeX_Script-Regular.woff2 +0 -0
  275. lhtml_site/themes/slides-pdf/libs/katex/fonts/KaTeX_Size1-Regular.ttf +0 -0
  276. lhtml_site/themes/slides-pdf/libs/katex/fonts/KaTeX_Size1-Regular.woff +0 -0
  277. lhtml_site/themes/slides-pdf/libs/katex/fonts/KaTeX_Size1-Regular.woff2 +0 -0
  278. lhtml_site/themes/slides-pdf/libs/katex/fonts/KaTeX_Size2-Regular.ttf +0 -0
  279. lhtml_site/themes/slides-pdf/libs/katex/fonts/KaTeX_Size2-Regular.woff +0 -0
  280. lhtml_site/themes/slides-pdf/libs/katex/fonts/KaTeX_Size2-Regular.woff2 +0 -0
  281. lhtml_site/themes/slides-pdf/libs/katex/fonts/KaTeX_Size3-Regular.ttf +0 -0
  282. lhtml_site/themes/slides-pdf/libs/katex/fonts/KaTeX_Size3-Regular.woff +0 -0
  283. lhtml_site/themes/slides-pdf/libs/katex/fonts/KaTeX_Size3-Regular.woff2 +0 -0
  284. lhtml_site/themes/slides-pdf/libs/katex/fonts/KaTeX_Size4-Regular.ttf +0 -0
  285. lhtml_site/themes/slides-pdf/libs/katex/fonts/KaTeX_Size4-Regular.woff +0 -0
  286. lhtml_site/themes/slides-pdf/libs/katex/fonts/KaTeX_Size4-Regular.woff2 +0 -0
  287. lhtml_site/themes/slides-pdf/libs/katex/fonts/KaTeX_Typewriter-Regular.ttf +0 -0
  288. lhtml_site/themes/slides-pdf/libs/katex/fonts/KaTeX_Typewriter-Regular.woff +0 -0
  289. lhtml_site/themes/slides-pdf/libs/katex/fonts/KaTeX_Typewriter-Regular.woff2 +0 -0
  290. lhtml_site/themes/slides-pdf/libs/katex/katex.min.css +1 -0
  291. lhtml_site/themes/slides-pdf/libs/katex/katex.min.js +1 -0
  292. lhtml_site/themes/slides-pdf/template/base.html +76 -0
  293. lhtml_site/themes/slides-pdf/theme.yaml +13 -0
  294. lhtml_site/themes/webpage-frame/css/classes.css +50 -0
  295. lhtml_site/themes/webpage-frame/css/code.css +71 -0
  296. lhtml_site/themes/webpage-frame/css/font.css +227 -0
  297. lhtml_site/themes/webpage-frame/css/icons.css +27 -0
  298. lhtml_site/themes/webpage-frame/css/main.css +390 -0
  299. lhtml_site/themes/webpage-frame/fonts/source_code_pro/LICENSE.md +93 -0
  300. lhtml_site/themes/webpage-frame/fonts/source_code_pro/README.md +18 -0
  301. lhtml_site/themes/webpage-frame/fonts/source_code_pro/WOFF2/TTF/SourceCodePro-Black.ttf.woff2 +0 -0
  302. lhtml_site/themes/webpage-frame/fonts/source_code_pro/WOFF2/TTF/SourceCodePro-BlackIt.ttf.woff2 +0 -0
  303. lhtml_site/themes/webpage-frame/fonts/source_code_pro/WOFF2/TTF/SourceCodePro-Bold.ttf.woff2 +0 -0
  304. lhtml_site/themes/webpage-frame/fonts/source_code_pro/WOFF2/TTF/SourceCodePro-BoldIt.ttf.woff2 +0 -0
  305. lhtml_site/themes/webpage-frame/fonts/source_code_pro/WOFF2/TTF/SourceCodePro-ExtraLight.ttf.woff2 +0 -0
  306. lhtml_site/themes/webpage-frame/fonts/source_code_pro/WOFF2/TTF/SourceCodePro-ExtraLightIt.ttf.woff2 +0 -0
  307. lhtml_site/themes/webpage-frame/fonts/source_code_pro/WOFF2/TTF/SourceCodePro-It.ttf.woff2 +0 -0
  308. lhtml_site/themes/webpage-frame/fonts/source_code_pro/WOFF2/TTF/SourceCodePro-Light.ttf.woff2 +0 -0
  309. lhtml_site/themes/webpage-frame/fonts/source_code_pro/WOFF2/TTF/SourceCodePro-LightIt.ttf.woff2 +0 -0
  310. lhtml_site/themes/webpage-frame/fonts/source_code_pro/WOFF2/TTF/SourceCodePro-Medium.ttf.woff2 +0 -0
  311. lhtml_site/themes/webpage-frame/fonts/source_code_pro/WOFF2/TTF/SourceCodePro-MediumIt.ttf.woff2 +0 -0
  312. lhtml_site/themes/webpage-frame/fonts/source_code_pro/WOFF2/TTF/SourceCodePro-Regular.ttf.woff2 +0 -0
  313. lhtml_site/themes/webpage-frame/fonts/source_code_pro/WOFF2/TTF/SourceCodePro-Semibold.ttf.woff2 +0 -0
  314. lhtml_site/themes/webpage-frame/fonts/source_code_pro/WOFF2/TTF/SourceCodePro-SemiboldIt.ttf.woff2 +0 -0
  315. lhtml_site/themes/webpage-frame/fonts/source_serif_pro/LICENSE.md +93 -0
  316. lhtml_site/themes/webpage-frame/fonts/source_serif_pro/README.md +18 -0
  317. lhtml_site/themes/webpage-frame/fonts/source_serif_pro/WOFF2/TTF/SourceSerifPro-Black.ttf.woff2 +0 -0
  318. lhtml_site/themes/webpage-frame/fonts/source_serif_pro/WOFF2/TTF/SourceSerifPro-BlackIt.ttf.woff2 +0 -0
  319. lhtml_site/themes/webpage-frame/fonts/source_serif_pro/WOFF2/TTF/SourceSerifPro-Bold.ttf.woff2 +0 -0
  320. lhtml_site/themes/webpage-frame/fonts/source_serif_pro/WOFF2/TTF/SourceSerifPro-BoldIt.ttf.woff2 +0 -0
  321. lhtml_site/themes/webpage-frame/fonts/source_serif_pro/WOFF2/TTF/SourceSerifPro-ExtraLight.ttf.woff2 +0 -0
  322. lhtml_site/themes/webpage-frame/fonts/source_serif_pro/WOFF2/TTF/SourceSerifPro-ExtraLightIt.ttf.woff2 +0 -0
  323. lhtml_site/themes/webpage-frame/fonts/source_serif_pro/WOFF2/TTF/SourceSerifPro-It.ttf.woff2 +0 -0
  324. lhtml_site/themes/webpage-frame/fonts/source_serif_pro/WOFF2/TTF/SourceSerifPro-Light.ttf.woff2 +0 -0
  325. lhtml_site/themes/webpage-frame/fonts/source_serif_pro/WOFF2/TTF/SourceSerifPro-LightIt.ttf.woff2 +0 -0
  326. lhtml_site/themes/webpage-frame/fonts/source_serif_pro/WOFF2/TTF/SourceSerifPro-Regular.ttf.woff2 +0 -0
  327. lhtml_site/themes/webpage-frame/fonts/source_serif_pro/WOFF2/TTF/SourceSerifPro-Semibold.ttf.woff2 +0 -0
  328. lhtml_site/themes/webpage-frame/fonts/source_serif_pro/WOFF2/TTF/SourceSerifPro-SemiboldIt.ttf.woff2 +0 -0
  329. lhtml_site/themes/webpage-frame/icons/down_enabled.svg +44 -0
  330. lhtml_site/themes/webpage-frame/icons/left_disabled.svg +1 -0
  331. lhtml_site/themes/webpage-frame/icons/left_enabled.svg +1 -0
  332. lhtml_site/themes/webpage-frame/icons/left_hover.svg +1 -0
  333. lhtml_site/themes/webpage-frame/icons/menu.svg +1 -0
  334. lhtml_site/themes/webpage-frame/icons/menu_hover.svg +1 -0
  335. lhtml_site/themes/webpage-frame/icons/right_disabled.svg +1 -0
  336. lhtml_site/themes/webpage-frame/icons/right_enabled.svg +1 -0
  337. lhtml_site/themes/webpage-frame/icons/right_hover.svg +1 -0
  338. lhtml_site/themes/webpage-frame/icons/up_enabled.svg +44 -0
  339. lhtml_site/themes/webpage-frame/js/menu.js +270 -0
  340. lhtml_site/themes/webpage-frame/js/title_id.js +51 -0
  341. lhtml_site/themes/webpage-frame/libs/katex/contrib/auto-render.min.js +1 -0
  342. lhtml_site/themes/webpage-frame/libs/katex/contrib/copy-tex.min.css +1 -0
  343. lhtml_site/themes/webpage-frame/libs/katex/contrib/copy-tex.min.js +1 -0
  344. lhtml_site/themes/webpage-frame/libs/katex/contrib/mathtex-script-type.min.js +1 -0
  345. lhtml_site/themes/webpage-frame/libs/katex/contrib/mhchem.min.js +1 -0
  346. lhtml_site/themes/webpage-frame/libs/katex/contrib/render-a11y-string.min.js +1 -0
  347. lhtml_site/themes/webpage-frame/libs/katex/fonts/KaTeX_AMS-Regular.ttf +0 -0
  348. lhtml_site/themes/webpage-frame/libs/katex/fonts/KaTeX_AMS-Regular.woff +0 -0
  349. lhtml_site/themes/webpage-frame/libs/katex/fonts/KaTeX_AMS-Regular.woff2 +0 -0
  350. lhtml_site/themes/webpage-frame/libs/katex/fonts/KaTeX_Caligraphic-Bold.ttf +0 -0
  351. lhtml_site/themes/webpage-frame/libs/katex/fonts/KaTeX_Caligraphic-Bold.woff +0 -0
  352. lhtml_site/themes/webpage-frame/libs/katex/fonts/KaTeX_Caligraphic-Bold.woff2 +0 -0
  353. lhtml_site/themes/webpage-frame/libs/katex/fonts/KaTeX_Caligraphic-Regular.ttf +0 -0
  354. lhtml_site/themes/webpage-frame/libs/katex/fonts/KaTeX_Caligraphic-Regular.woff +0 -0
  355. lhtml_site/themes/webpage-frame/libs/katex/fonts/KaTeX_Caligraphic-Regular.woff2 +0 -0
  356. lhtml_site/themes/webpage-frame/libs/katex/fonts/KaTeX_Fraktur-Bold.ttf +0 -0
  357. lhtml_site/themes/webpage-frame/libs/katex/fonts/KaTeX_Fraktur-Bold.woff +0 -0
  358. lhtml_site/themes/webpage-frame/libs/katex/fonts/KaTeX_Fraktur-Bold.woff2 +0 -0
  359. lhtml_site/themes/webpage-frame/libs/katex/fonts/KaTeX_Fraktur-Regular.ttf +0 -0
  360. lhtml_site/themes/webpage-frame/libs/katex/fonts/KaTeX_Fraktur-Regular.woff +0 -0
  361. lhtml_site/themes/webpage-frame/libs/katex/fonts/KaTeX_Fraktur-Regular.woff2 +0 -0
  362. lhtml_site/themes/webpage-frame/libs/katex/fonts/KaTeX_Main-Bold.ttf +0 -0
  363. lhtml_site/themes/webpage-frame/libs/katex/fonts/KaTeX_Main-Bold.woff +0 -0
  364. lhtml_site/themes/webpage-frame/libs/katex/fonts/KaTeX_Main-Bold.woff2 +0 -0
  365. lhtml_site/themes/webpage-frame/libs/katex/fonts/KaTeX_Main-BoldItalic.ttf +0 -0
  366. lhtml_site/themes/webpage-frame/libs/katex/fonts/KaTeX_Main-BoldItalic.woff +0 -0
  367. lhtml_site/themes/webpage-frame/libs/katex/fonts/KaTeX_Main-BoldItalic.woff2 +0 -0
  368. lhtml_site/themes/webpage-frame/libs/katex/fonts/KaTeX_Main-Italic.ttf +0 -0
  369. lhtml_site/themes/webpage-frame/libs/katex/fonts/KaTeX_Main-Italic.woff +0 -0
  370. lhtml_site/themes/webpage-frame/libs/katex/fonts/KaTeX_Main-Italic.woff2 +0 -0
  371. lhtml_site/themes/webpage-frame/libs/katex/fonts/KaTeX_Main-Regular.ttf +0 -0
  372. lhtml_site/themes/webpage-frame/libs/katex/fonts/KaTeX_Main-Regular.woff +0 -0
  373. lhtml_site/themes/webpage-frame/libs/katex/fonts/KaTeX_Main-Regular.woff2 +0 -0
  374. lhtml_site/themes/webpage-frame/libs/katex/fonts/KaTeX_Math-BoldItalic.ttf +0 -0
  375. lhtml_site/themes/webpage-frame/libs/katex/fonts/KaTeX_Math-BoldItalic.woff +0 -0
  376. lhtml_site/themes/webpage-frame/libs/katex/fonts/KaTeX_Math-BoldItalic.woff2 +0 -0
  377. lhtml_site/themes/webpage-frame/libs/katex/fonts/KaTeX_Math-Italic.ttf +0 -0
  378. lhtml_site/themes/webpage-frame/libs/katex/fonts/KaTeX_Math-Italic.woff +0 -0
  379. lhtml_site/themes/webpage-frame/libs/katex/fonts/KaTeX_Math-Italic.woff2 +0 -0
  380. lhtml_site/themes/webpage-frame/libs/katex/fonts/KaTeX_SansSerif-Bold.ttf +0 -0
  381. lhtml_site/themes/webpage-frame/libs/katex/fonts/KaTeX_SansSerif-Bold.woff +0 -0
  382. lhtml_site/themes/webpage-frame/libs/katex/fonts/KaTeX_SansSerif-Bold.woff2 +0 -0
  383. lhtml_site/themes/webpage-frame/libs/katex/fonts/KaTeX_SansSerif-Italic.ttf +0 -0
  384. lhtml_site/themes/webpage-frame/libs/katex/fonts/KaTeX_SansSerif-Italic.woff +0 -0
  385. lhtml_site/themes/webpage-frame/libs/katex/fonts/KaTeX_SansSerif-Italic.woff2 +0 -0
  386. lhtml_site/themes/webpage-frame/libs/katex/fonts/KaTeX_SansSerif-Regular.ttf +0 -0
  387. lhtml_site/themes/webpage-frame/libs/katex/fonts/KaTeX_SansSerif-Regular.woff +0 -0
  388. lhtml_site/themes/webpage-frame/libs/katex/fonts/KaTeX_SansSerif-Regular.woff2 +0 -0
  389. lhtml_site/themes/webpage-frame/libs/katex/fonts/KaTeX_Script-Regular.ttf +0 -0
  390. lhtml_site/themes/webpage-frame/libs/katex/fonts/KaTeX_Script-Regular.woff +0 -0
  391. lhtml_site/themes/webpage-frame/libs/katex/fonts/KaTeX_Script-Regular.woff2 +0 -0
  392. lhtml_site/themes/webpage-frame/libs/katex/fonts/KaTeX_Size1-Regular.ttf +0 -0
  393. lhtml_site/themes/webpage-frame/libs/katex/fonts/KaTeX_Size1-Regular.woff +0 -0
  394. lhtml_site/themes/webpage-frame/libs/katex/fonts/KaTeX_Size1-Regular.woff2 +0 -0
  395. lhtml_site/themes/webpage-frame/libs/katex/fonts/KaTeX_Size2-Regular.ttf +0 -0
  396. lhtml_site/themes/webpage-frame/libs/katex/fonts/KaTeX_Size2-Regular.woff +0 -0
  397. lhtml_site/themes/webpage-frame/libs/katex/fonts/KaTeX_Size2-Regular.woff2 +0 -0
  398. lhtml_site/themes/webpage-frame/libs/katex/fonts/KaTeX_Size3-Regular.ttf +0 -0
  399. lhtml_site/themes/webpage-frame/libs/katex/fonts/KaTeX_Size3-Regular.woff +0 -0
  400. lhtml_site/themes/webpage-frame/libs/katex/fonts/KaTeX_Size3-Regular.woff2 +0 -0
  401. lhtml_site/themes/webpage-frame/libs/katex/fonts/KaTeX_Size4-Regular.ttf +0 -0
  402. lhtml_site/themes/webpage-frame/libs/katex/fonts/KaTeX_Size4-Regular.woff +0 -0
  403. lhtml_site/themes/webpage-frame/libs/katex/fonts/KaTeX_Size4-Regular.woff2 +0 -0
  404. lhtml_site/themes/webpage-frame/libs/katex/fonts/KaTeX_Typewriter-Regular.ttf +0 -0
  405. lhtml_site/themes/webpage-frame/libs/katex/fonts/KaTeX_Typewriter-Regular.woff +0 -0
  406. lhtml_site/themes/webpage-frame/libs/katex/fonts/KaTeX_Typewriter-Regular.woff2 +0 -0
  407. lhtml_site/themes/webpage-frame/libs/katex/katex.min.css +1 -0
  408. lhtml_site/themes/webpage-frame/libs/katex/katex.min.js +1 -0
  409. lhtml_site/themes/webpage-frame/template/base.html +74 -0
  410. lhtml_site/themes/webpage-frame/theme.yaml +11 -0
  411. lhtml_site/tracking.py +34 -0
  412. lhtml_site/video_cache.py +124 -0
  413. lhtml_site/video_convert/__init__.py +0 -0
  414. lhtml_site/video_convert/video_convert.py +151 -0
  415. lhtml_site/wrap.py +91 -0
  416. lhtml_site-1.0.0.dist-info/METADATA +384 -0
  417. lhtml_site-1.0.0.dist-info/RECORD +421 -0
  418. lhtml_site-1.0.0.dist-info/WHEEL +5 -0
  419. lhtml_site-1.0.0.dist-info/entry_points.txt +2 -0
  420. lhtml_site-1.0.0.dist-info/licenses/LICENSE.md +21 -0
  421. lhtml_site-1.0.0.dist-info/top_level.txt +1 -0
lhtml_site/__init__.py ADDED
File without changes
lhtml_site/browser.py ADDED
@@ -0,0 +1,59 @@
1
+ """The headless browser of the generator: the Chromium of Playwright for
2
+ Python, run by the PDF export (lhtml_site/pdf_export.py), the layout report
3
+ and --render (lhtml_site/layout/measure.py).
4
+
5
+ Playwright comes with the extra `lhtml-site[pdf]`, its browser from
6
+ `python -m playwright install --only-shell chromium`; the configuration key
7
+ 'chrome' runs another Chrome instead.
8
+ """
9
+ import importlib.util
10
+ from contextlib import asynccontextmanager
11
+
12
+ from lhtml_site.doctor import playwright_browser_command, playwright_install_command
13
+
14
+ PLAYWRIGHT_MISSING = '{feature} needs {modules}: {install}, then {browser}'
15
+ CHROMIUM_MISSING = ('The Chromium of Playwright is not installed: {browser} '
16
+ '(or the configuration key chrome)')
17
+
18
+
19
+ def installed(modules=('playwright',)):
20
+ return all(importlib.util.find_spec(module) for module in modules)
21
+
22
+
23
+ def require(feature, modules=('playwright',)):
24
+ """Raise a RuntimeError saying how to install `modules` when one of them
25
+ is missing (`feature`: 'The layout report', ...)."""
26
+ if installed(modules):
27
+ return
28
+ raise RuntimeError(missing(feature, modules))
29
+
30
+
31
+ def missing(feature, modules=('playwright',)):
32
+ """What to install for `feature`, for the way lhtml-site is installed
33
+ (the extra lhtml-site[pdf]: playwright and pypdf, then the browser)."""
34
+ return PLAYWRIGHT_MISSING.format(feature=feature, modules=' and '.join(modules),
35
+ install=playwright_install_command(), browser=playwright_browser_command())
36
+
37
+
38
+ @asynccontextmanager
39
+ async def chromium(chrome_path=None, args=()):
40
+ """A headless Chromium: the one of Playwright, or the executable
41
+ `chrome_path` (the configuration key 'chrome')."""
42
+ from playwright.async_api import Error, async_playwright
43
+
44
+ async with async_playwright() as playwright:
45
+ try:
46
+ browser = await playwright.chromium.launch(executable_path=chrome_path or None, args=list(args))
47
+ except Error as error:
48
+ if "Executable doesn't exist" in str(error):
49
+ raise RuntimeError(CHROMIUM_MISSING.format(browser=playwright_browser_command())) from None
50
+ raise
51
+ try:
52
+ yield browser
53
+ finally:
54
+ await browser.close()
55
+
56
+
57
+ def first_line(error):
58
+ """The first line of what a Playwright error says (the rest is its call log)."""
59
+ return (str(error).strip().splitlines() or [type(error).__name__])[0]
@@ -0,0 +1,80 @@
1
+ """Publish a completed build while keeping the previous output on failure."""
2
+ from contextlib import contextmanager
3
+ from pathlib import Path
4
+ import os
5
+ import shutil
6
+ import tempfile
7
+ import uuid
8
+
9
+
10
+ def links_out_of(site):
11
+ """The links of a site a build that writes in it (--only) would write
12
+ through: a symbolic link leading out of it, a file with another hard
13
+ link (a file of the sources, `cp -al`, `rsync -H`). As (path, what it
14
+ reaches)."""
15
+ site = Path(site)
16
+ if not site.is_dir():
17
+ return []
18
+ real = site.resolve()
19
+ found = []
20
+ for directory, dirs, files in os.walk(site):
21
+ for name in dirs + files:
22
+ path = Path(directory) / name
23
+ if path.is_symlink():
24
+ target = path.resolve()
25
+ if target != real and real not in target.parents:
26
+ found.append((path, target))
27
+ elif name in files and os.lstat(path).st_nlink > 1:
28
+ found.append((path, 'another hard link to the same file'))
29
+ return found
30
+
31
+
32
+ @contextmanager
33
+ def staged_site(meta, copy=False):
34
+ """The build in a staging directory, published when it completes.
35
+ `copy`: the staging directory starts as a copy of the site (a partial
36
+ build that must publish nothing if it is refused: --only --strict)."""
37
+ target = Path(meta['site_directory']).resolve()
38
+ target.parent.mkdir(parents=True, exist_ok=True)
39
+ staging = Path(tempfile.mkdtemp(prefix='.site-build-', dir=target.parent))
40
+ if copy and target.is_dir():
41
+ shutil.copytree(target, staging, symlinks=True, dirs_exist_ok=True)
42
+ original = meta['site_directory']
43
+ meta['published_site_directory'] = target
44
+ meta['site_directory'] = staging
45
+ try:
46
+ yield
47
+ # A target may publish something else than the site it rendered: the
48
+ # PDF export keeps <deck>.pdf and images/, and asks for the HTML it
49
+ # used as an intermediate not to be published. It says so rather
50
+ # than deleting the directory under whatever runs next. In a project
51
+ # of decks or targets, the directory of the target is its own: a site
52
+ # published there before (--debug keeps it) goes too, it would be
53
+ # stale. A project of one site may have published something else
54
+ # there, which is kept.
55
+ if not meta.get('publish_site', True):
56
+ shutil.rmtree(staging, ignore_errors=True)
57
+ if meta.get('build_scope'):
58
+ shutil.rmtree(target, ignore_errors=True)
59
+ if staging.is_dir():
60
+ backup = target.with_name('.site-backup-' + uuid.uuid4().hex)
61
+ had_target = target.exists()
62
+ if had_target:
63
+ target.rename(backup)
64
+ try:
65
+ staging.rename(target)
66
+ except BaseException:
67
+ if had_target:
68
+ backup.rename(target)
69
+ raise
70
+ if had_target:
71
+ shutil.rmtree(backup)
72
+ except BaseException:
73
+ if meta['debug'] and staging.exists():
74
+ meta['log'].warning(f'Failed build kept for inspection: {staging}')
75
+ else:
76
+ shutil.rmtree(staging, ignore_errors=True)
77
+ raise
78
+ finally:
79
+ meta['site_directory'] = original
80
+ meta.pop('published_site_directory', None)
@@ -0,0 +1,354 @@
1
+ """User configuration, its validation, and the meta of a build."""
2
+ from __future__ import annotations
3
+
4
+ from dataclasses import asdict, dataclass, field
5
+ from pathlib import Path
6
+ from typing import Any
7
+ import difflib
8
+ import os
9
+ import re
10
+
11
+ from lhtml_site.filesystem import read_yaml
12
+ from lhtml_site.structure import PRIVATE_KEYS
13
+
14
+ GENERATOR_DIRECTORY = Path(__file__).resolve().parent # the package: its code, themes/, plugins/, example/
15
+ RENAMED_DIRECTORIES = {'theme_templates': 'themes', 'src_site_example': 'example'} # in 3.0
16
+
17
+
18
+ # Keys of meta set by the generator during a build (never by the configuration)
19
+ # Plugins of the previous version that the build now runs itself: the name of
20
+ # the file, and what it became.
21
+ CORE_STAGES = {
22
+ 'menu.py': "the theme's menu",
23
+ 'title_submenu.py': 'the heading ids (configuration key title_id:)',
24
+ 'auto_wrap.py': 'the wrapping of a page in the template of its theme',
25
+ 'auto-wrap.py': 'the wrapping of a page in the template of its theme',
26
+ 'redirection_first_page.py': 'the index of a site that has none',
27
+ 'cache_video.py': "the transcoded videos (set 'cache_video_directory:' to ask for them)",
28
+ 'generate_pdf.py': "the PDF export, a target now (targets: pdf: {theme: slides-pdf})",
29
+ }
30
+
31
+ RUNTIME_KEYS = frozenset((
32
+ 'args', 'log', 'plugin_paths', 'config_file', 'config_directory', 'lib_directory',
33
+ 'published_site_directory', # the site, while the build is made in a staging directory
34
+ 'exported', # the file an export wrote (lhtml_site/pdf_export.py)
35
+ 'only', # --only: the build is made in the site, for some pages
36
+ 'structure', 'built', # all the pages of the site / those generated (lhtml_site/structure.py)
37
+ 'previous_pages', # --only: HTML of the pages before the build (restored if they fail)
38
+ 'strict', # --strict: the check of the warnings, before the pages are kept
39
+ 'loaded_design', 'macros', # the design (lhtml_site/design.py) and its macros for LHTML
40
+ 'heading_ids', 'heading_summary', # the ids of each page / its headings (lhtml_site/headings.py)
41
+ 'lint_findings', # {source path: [finding]} of the generated pages (lhtml_site/lint.py)
42
+ 'measure', # --only: the pages the layout report measures again
43
+ 'source_roots', # the sources read by each page (lhtml_site/tracking.py)
44
+ 'dependency_contexts', 'dependency_store', 'dependency_measure',
45
+ 'template_dependencies', # what each page depends on (lhtml_site/dependencies.py)
46
+ '_dependency_engine', '_dependency_theme_scopes', # the same for all its pages: read once
47
+ 'analyse_layout', # --layout: the build runs the layout analysis (lhtml_site/layout/build.py)
48
+ 'publish_site', # a target asks for its intermediate site not to be published
49
+ 'source_map', 'feedback', # builds for development (lhtml_site/source_map.py, lhtml_site/feedback.py)
50
+ 'planned_slides', # entries of the deck without a source yet
51
+ 'export_name', # the name of the PDF of a deck (lhtml_site/pdf_export.py)
52
+ 'build_scope', # <deck>/<target>: where its state is kept (lhtml_site/project.py)
53
+ ))
54
+
55
+
56
+ class ConfigError(ValueError):
57
+ """An actionable configuration error, displayed without a traceback."""
58
+
59
+
60
+ @dataclass(frozen=True)
61
+ class Config:
62
+ # Directories: as written in the YAML, absolute Paths once load_config resolved them
63
+ source_directory: Path | str = 'src_site'
64
+ site_directory: Path | str = '.site'
65
+ theme: Path | str = str(GENERATOR_DIRECTORY / 'themes/webpage-frame')
66
+ # Extensions, and nothing else: everything a bundled theme needs to
67
+ # render a project written in LHTML is a stage of the build now
68
+ # (lhtml_site/wrap.py, lhtml_site/headings.py, lhtml_site/menu.py, lhtml_site/index_page.py), so the
69
+ # default is empty and a project lists only what is its own.
70
+ plugin: list[str] = field(default_factory=list)
71
+ debug: bool = False
72
+ title_id: bool = True
73
+ keywords: dict = field(default_factory=dict)
74
+ use_tidy: bool = False
75
+ line_breaks: bool = False # 'line-breaks:' in the YAML, as LHTML spells it
76
+ # Page settings a custom theme needs in the site, beyond the ones the
77
+ # bundled themes display (lhtml_site/structure.py, PUBLIC_KEYS). Everything else
78
+ # an author writes in a config.yaml or a deck entry stays out of the site.
79
+ public_page_keys: list[str] = field(default_factory=list)
80
+ plugin_arg: dict = field(default_factory=dict)
81
+ layout: dict = field(default_factory=dict) # options of the layout analysis (--layout)
82
+ cache_video_directory: Path | str | None = None
83
+ chrome: str | None = None
84
+ design: dict | str | None = None
85
+ deck: list | dict | str | None = None
86
+ # A project of several decks, each built to several targets (lhtml_site/project.py):
87
+ # 'directories' (each directory of the sources is a deck), and
88
+ # {name: {theme: directory}}, the themes resolved to Paths by load_config
89
+ decks: str | None = None
90
+ targets: dict | None = None
91
+
92
+ def to_meta(self):
93
+ values = asdict(self)
94
+ for key in ('cache_video_directory', 'chrome', 'design', 'deck', 'decks', 'targets'):
95
+ if values[key] is None:
96
+ del values[key]
97
+ return values
98
+
99
+
100
+ @dataclass
101
+ class BuildContext:
102
+ config: Config
103
+ config_file: Path
104
+ args: Any
105
+ log: Any
106
+ plugin_paths: list[str] = field(default_factory=list)
107
+ meta: dict = field(init=False)
108
+
109
+ def __post_init__(self):
110
+ # The state of a build: a copy, which never changes the configuration
111
+ self.meta = self.config.to_meta()
112
+ self.meta.update(config_file=str(self.config_file),
113
+ config_directory=self.config_file.parent,
114
+ lib_directory=GENERATOR_DIRECTORY,
115
+ args=self.args, log=self.log,
116
+ plugin_paths=self.plugin_paths)
117
+
118
+
119
+ def _file_or_inline(values, key, inline_types, inline_text, config_directory):
120
+ """A key given as the path of a YAML file (resolved from the configuration
121
+ directory, must exist) or inline (mapping with string keys / list)."""
122
+ value = values.get(key)
123
+ if value is None:
124
+ return
125
+ if isinstance(value, str) and value.strip():
126
+ file = Path(value).expanduser()
127
+ if not file.is_absolute():
128
+ file = config_directory / file
129
+ if not file.is_file():
130
+ raise ConfigError(f"'{key}' file not found: '{file}'")
131
+ values[key] = str(file.resolve())
132
+ elif not isinstance(value, inline_types) or (isinstance(value, dict)
133
+ and any(not isinstance(k, str) for k in value)):
134
+ raise ConfigError(f"'{key}' must be {inline_text} or the path of a YAML file")
135
+
136
+
137
+ def _chrome_executable(values, config_directory):
138
+ """'chrome': the Chrome executable the browser runs (layout report,
139
+ PDF export, --render), instead of the Chromium of Playwright. A
140
+ relative path is resolved from the configuration directory; a macOS
141
+ bundle ('.app') is resolved to the executable it contains."""
142
+ value = values.get('chrome')
143
+ if value is None:
144
+ return
145
+ if not isinstance(value, str) or not value.strip():
146
+ raise ConfigError("'chrome' must be the path of the Chrome executable")
147
+ file = Path(value.strip()).expanduser()
148
+ if not file.is_absolute():
149
+ file = config_directory / file
150
+ if file.suffix == '.app' and file.is_dir(): # macOS bundle
151
+ inside = file / 'Contents/MacOS' / file.stem
152
+ if not inside.is_file():
153
+ candidates = sorted(p for p in (file / 'Contents/MacOS').glob('*') if p.is_file())
154
+ if not candidates:
155
+ raise ConfigError(f"'chrome': no executable in the bundle '{file}'")
156
+ inside = candidates[0]
157
+ file = inside
158
+ if not file.is_file():
159
+ raise ConfigError(f"'chrome' executable not found: '{file}'")
160
+ if not os.access(file, os.X_OK):
161
+ raise ConfigError(f"'chrome' is not executable: '{file}'")
162
+ values['chrome'] = str(file.resolve())
163
+
164
+
165
+ TARGET_NAME = re.compile(r'[A-Za-z][A-Za-z0-9_-]*$')
166
+
167
+
168
+ def in_package(path):
169
+ """A path into a checkout of the generator as the projects write it
170
+ (a submodule): its themes/, plugins/ and example/ were at the root of the
171
+ repository, and are in its package now (src/lhtml_site/). The same path
172
+ in the package when it exists there, else the path unchanged."""
173
+ path = Path(path)
174
+ if path.exists():
175
+ return path
176
+ for i, part in enumerate(path.parts):
177
+ if part in ('themes', 'plugins', 'example'):
178
+ moved = Path(*path.parts[:i], 'src', 'lhtml_site', *path.parts[i:])
179
+ if moved.exists():
180
+ return moved
181
+ return path
182
+
183
+
184
+ def theme_directory(value, config_directory):
185
+ """A theme given as a directory (relative to the configuration) or as the
186
+ name of a theme of the generator ('slides')."""
187
+ directory = Path(value).expanduser()
188
+ if not directory.is_absolute():
189
+ directory = config_directory / directory
190
+ if not directory.is_dir() and (GENERATOR_DIRECTORY / 'themes' / value).is_dir():
191
+ directory = GENERATOR_DIRECTORY / 'themes' / value
192
+ return in_package(directory).resolve()
193
+
194
+
195
+ def _decks_and_targets(values, data, config_directory):
196
+ """'decks' and 'targets' (lhtml_site/project.py), checked, the themes resolved."""
197
+ if values.get('decks') is not None and values['decks'] != 'directories':
198
+ raise ConfigError("'decks' must be 'directories' (each directory of the sources is a deck)")
199
+ targets = values.get('targets')
200
+ if targets is None:
201
+ return
202
+ if not isinstance(targets, dict) or not targets:
203
+ raise ConfigError("'targets' must map a name to its settings, e.g. html: {theme: slides}")
204
+ if 'theme' in data:
205
+ raise ConfigError("'theme' and 'targets' together: give the theme of each target")
206
+ resolved = {}
207
+ for name, spec in targets.items():
208
+ if not isinstance(name, str) or not TARGET_NAME.match(name):
209
+ raise ConfigError(f"'targets': invalid name {name!r} (letters, digits, - and _)")
210
+ if name == 'images':
211
+ raise ConfigError("'targets': 'images' is where the PDF export writes the slide images; "
212
+ "choose another name")
213
+ if not isinstance(spec, dict) or set(spec) != {'theme'} or not isinstance(spec['theme'], str):
214
+ raise ConfigError(f"'targets': {name}: expected {{theme: <theme>}}")
215
+ # its existence is checked by validate_paths, as the one of the
216
+ # sources: --clean needs neither
217
+ resolved[name] = {'theme': theme_directory(spec['theme'], config_directory)}
218
+ values['targets'] = resolved
219
+
220
+
221
+ def load_config(filename, debug_override=None):
222
+ path = Path(filename).expanduser().resolve()
223
+ warnings = []
224
+ if not path.exists() and path.name == 'configure_default.yaml':
225
+ raise ConfigError("'configure_default.yaml' was renamed 'configure_example.yaml' (lhtml-site 1.0): "
226
+ "update your command")
227
+ if not path.exists():
228
+ raise ConfigError(f"Configuration not found: '{path}' (run lhtml-site in the "
229
+ f"directory of a project; lhtml-site init creates one)")
230
+ try:
231
+ data = read_yaml(path)
232
+ except ValueError as exc: # the message names the file
233
+ raise ConfigError(str(exc)) from None
234
+ if data is None:
235
+ data = {}
236
+ if not isinstance(data, dict) or any(not isinstance(k, str) for k in data):
237
+ raise ConfigError('Configuration must contain named key: value pairs')
238
+
239
+ if 'line-breaks' in data: # the spelling of LHTML
240
+ data['line_breaks'] = data.pop('line-breaks')
241
+ if 'plugin_post' in data:
242
+ raise ConfigError("'plugin_post' was removed (lhtml-site 1.0): list its plugins under 'plugin' "
243
+ "(all their hooks are run)")
244
+ if 'level_print' in data:
245
+ raise ConfigError("'level_print' was removed (lhtml-site 1.0): the build prints no indented log "
246
+ "(-v shows its stages)")
247
+ if 'include_head' in data:
248
+ raise ConfigError("'include_head' was removed (lhtml-site 1.0): it was read nowhere; a theme "
249
+ "places what goes in <head>")
250
+
251
+ defaults = Config().to_meta()
252
+ known = set(defaults) | {'cache_video_directory', 'chrome', 'design', 'deck', 'decks', 'targets'}
253
+ for key in sorted(set(data) - known):
254
+ if key in RUNTIME_KEYS:
255
+ raise ConfigError(f"'{key}' is runtime state and cannot be set in YAML")
256
+ suggestion = difflib.get_close_matches(key, sorted(known), n=1)
257
+ hint = f" Did you mean '{suggestion[0]}'?" if suggestion else ''
258
+ warnings.append(f"Unknown configuration key '{key}', ignored.{hint} "
259
+ f"(A plugin reads its options in 'plugin_arg'.)")
260
+ values = {**defaults, **{k: v for k, v in data.items() if k in known}}
261
+ for key in ('debug', 'title_id', 'use_tidy', 'line_breaks'):
262
+ if type(values[key]) is not bool:
263
+ raise ConfigError(f"'{key}' must be a boolean (true or false)")
264
+ for key in ('keywords', 'plugin_arg', 'layout'):
265
+ if not isinstance(values[key], dict) or any(not isinstance(k, str) for k in values[key]):
266
+ raise ConfigError(f"'{key}' must be a mapping with string keys")
267
+ for name in sorted({'params', 'page', 'credit', 'credits'} & set(values['keywords'])):
268
+ raise ConfigError(f"'keywords': '{name}' is reserved (Jinja variable of the generator: "
269
+ f"params, the deck parameters of a page; page, its metadata; credit, credits)")
270
+ plugins = values['plugin']
271
+ if isinstance(plugins, str):
272
+ plugins = [plugins]
273
+ elif plugins is None:
274
+ plugins = []
275
+ values['plugin'] = plugins
276
+ for key in ('plugin', 'public_page_keys'):
277
+ if not isinstance(values[key], list) or any(not isinstance(v, str) or not v.strip() for v in values[key]):
278
+ raise ConfigError(f"'{key}' must be a list of non-empty strings")
279
+ for name in sorted(set(values['public_page_keys']) & set(PRIVATE_KEYS)):
280
+ raise ConfigError(f"'public_page_keys': '{name}' is never written into the site "
281
+ f"(it is the path of the source on this machine)")
282
+ # The layout analysis is part of the generator, not a plugin: it is
283
+ # selected by --layout and configured by 'layout:'. A configuration of
284
+ # the previous version says so here, before the build, naming the fix.
285
+ for entry in plugins:
286
+ if entry.endswith('layout_report.py'):
287
+ raise ConfigError("'plugin': the layout report is no longer a plugin. Remove "
288
+ f"'{entry}' from 'plugin:' and run the build with --layout")
289
+ if isinstance(values['plugin_arg'], dict) and 'layout_report' in values['plugin_arg']:
290
+ raise ConfigError("'plugin_arg': the options of the layout report moved to the "
291
+ "configuration key 'layout:'. Move the content of "
292
+ "'plugin_arg: layout_report:' under 'layout:'")
293
+ # Stages the build always runs: a project does not list them, and cannot
294
+ # know whether its theme has a menu - the theme declares that (theme.yaml).
295
+ for entry in plugins:
296
+ name = entry.rsplit('/', 1)[-1]
297
+ if name in CORE_STAGES:
298
+ raise ConfigError(f"'plugin': {CORE_STAGES[name]} is a stage of the build, not a "
299
+ f"plugin. Remove '{entry}' from 'plugin:'")
300
+ if isinstance(values['plugin_arg'], dict) and 'menu' in values['plugin_arg']:
301
+ raise ConfigError("'plugin_arg': the extra page settings of the menu are declared by "
302
+ "the theme. Move the content of 'plugin_arg: menu: keys:' to "
303
+ "'toc: keys:' in the theme.yaml of your theme")
304
+
305
+ _chrome_executable(values, path.parent)
306
+ _decks_and_targets(values, data, path.parent)
307
+
308
+ _file_or_inline(values, 'design', dict, 'a mapping (tokens, macros)', path.parent)
309
+ _file_or_inline(values, 'deck', (list, dict), 'a list of slides', path.parent)
310
+
311
+ for key in ('source_directory', 'site_directory', 'theme', 'cache_video_directory'):
312
+ if key not in values:
313
+ continue
314
+ value = values[key]
315
+ if not isinstance(value, str) or not value.strip():
316
+ raise ConfigError(f"'{key}' must be a non-empty directory path")
317
+ directory = Path(value).expanduser()
318
+ if not directory.is_absolute():
319
+ directory = path.parent / directory
320
+ if key == 'theme': # a directory, or the name of a theme of the generator
321
+ directory = theme_directory(value, path.parent)
322
+ elif key == 'source_directory':
323
+ directory = in_package(directory)
324
+ if key in ('source_directory', 'theme') and not directory.is_dir():
325
+ # the new name as the configuration writes it (a checkout: found in its package)
326
+ renamed = Path(*[RENAMED_DIRECTORIES.get(part, part) for part in directory.parts])
327
+ if in_package(renamed).is_dir():
328
+ raise ConfigError(f"'{key}': '{directory.as_posix()}' was renamed "
329
+ f"'{renamed.as_posix()}' (lhtml-site 1.0): update '{key}'")
330
+ values[key] = directory.resolve()
331
+ if debug_override is not None:
332
+ values['debug'] = debug_override
333
+ return Config(**values), path, warnings
334
+
335
+
336
+ def validate_paths(config, config_file, require_inputs=True):
337
+ output = Path(config.site_directory).resolve()
338
+ inputs = [('source_directory', config.source_directory)]
339
+ inputs += [(f'targets: {name}: theme', spec['theme']) for name, spec in (config.targets or {}).items()] \
340
+ or [('theme', config.theme)]
341
+ for key, directory in inputs:
342
+ directory = Path(directory).resolve()
343
+ if output == directory or output in directory.parents or directory in output.parents:
344
+ raise ConfigError(f"Unsafe 'site_directory': output and '{key}' must not overlap ({output}, {directory})")
345
+ if require_inputs and not directory.is_dir():
346
+ raise ConfigError(f"'{key}' directory not found: {directory}")
347
+ protected = [config_file.resolve(), GENERATOR_DIRECTORY.resolve()]
348
+ if config.cache_video_directory:
349
+ protected.append(Path(config.cache_video_directory).resolve())
350
+ for path in protected:
351
+ if output == path or output in path.parents:
352
+ raise ConfigError(f"Unsafe 'site_directory': deleting '{output}' would remove '{path}'")
353
+ if output.exists() and not output.is_dir():
354
+ raise ConfigError(f"'site_directory' is not a directory: {output}")
@@ -0,0 +1,113 @@
1
+ # configure.yaml: the configuration of a site built by lhtml-site.
2
+ #
3
+ # Run from this directory:
4
+ # lhtml-site build into .site/ (open .site/index.html in a browser)
5
+ # lhtml-site --watch build, and rebuild on each save
6
+ # lhtml-site --serve --watch the same, and a preview on http://127.0.0.1:8000/
7
+ # lhtml-site --check-config check this file, without building
8
+ #
9
+ # Relative paths are read from this directory. A line starting with # is a
10
+ # comment: remove the # in front of an option to use it. The options of the
11
+ # command line (--debug, ...) take precedence over this file. Every option is
12
+ # described in the section Configuration of the reference of lhtml-site:
13
+ # https://github.com/drohmer/lhtml-site/blob/main/src/lhtml_site/docs/reference.md
14
+
15
+ # ---------------------------------------------------------------------------
16
+ # Essentials
17
+ # ---------------------------------------------------------------------------
18
+
19
+ # Where the pages are. A page is a file .html.j2 (LHTML) or .md.j2 (Markdown),
20
+ # usually <name>/index.html.j2 with its images and videos next to it; the
21
+ # pages follow the order of their paths (01_..., 02_...) unless a deck says.
22
+ source_directory: 'src/'
23
+
24
+ # Where the site is written. It is replaced at each build: never edit it.
25
+ site_directory: '.site/'
26
+
27
+ # The look of the site: a theme of the generator, or the directory of yours.
28
+ # webpage-frame web pages with a navigation menu
29
+ # slides slides shown in the browser (1920x1080)
30
+ # slides-pdf the same slides, exported to a PDF (needs Playwright, lhtml-site[pdf]: lhtml-site doctor)
31
+ theme: 'webpage-frame'
32
+
33
+ # ---------------------------------------------------------------------------
34
+ # Common options
35
+ # ---------------------------------------------------------------------------
36
+
37
+ # The order of the pages (of the slides of a talk): a file listing them, see
38
+ # the section Deck of the reference. Without it, the order of their paths.
39
+ # deck: 'deck.yaml'
40
+
41
+ # Values every page can show, as Jinja variables: {{ author }}, {{ year }}.
42
+ # keywords:
43
+ # author: 'Your Name'
44
+ # year: 2026
45
+
46
+ # Your own macros and design tokens, added to those of the theme (the slides
47
+ # themes have a design: .structure/design.md lists it after a build).
48
+ # design:
49
+ # tokens:
50
+ # font: {small: 80%}
51
+ # macros:
52
+ # note:
53
+ # class: note
54
+ # doc: 'A remark in gray: note:: ... ::'
55
+ # css: '.note { color: gray; }'
56
+
57
+ # The videos of the pages, converted to the formats every browser reads
58
+ # (needs ffmpeg, and ffpb: pip install ffpb). The converted files are kept
59
+ # in this directory.
60
+ # cache_video_directory: 'cache_video/'
61
+
62
+ # The headings get an id, so that a section can be linked, and the theme
63
+ # lists them. Default: true.
64
+ # title_id: true
65
+
66
+ # A line break in a source is a line break in the page. Default: false (the
67
+ # lines of a paragraph are joined).
68
+ # line-breaks: false
69
+
70
+ # ---------------------------------------------------------------------------
71
+ # Several decks, in the browser and as a PDF
72
+ # ---------------------------------------------------------------------------
73
+
74
+ # Each directory of source_directory is a deck, built once for each target,
75
+ # into <site_directory>/<deck>/<target>/. Takes the place of 'theme:' above
76
+ # (remove that line).
77
+ # decks: directories
78
+ # targets:
79
+ # html: {theme: slides}
80
+ # pdf: {theme: slides-pdf}
81
+
82
+ # ---------------------------------------------------------------------------
83
+ # Extensions
84
+ # ---------------------------------------------------------------------------
85
+
86
+ # Transformations of the pages, in the order they run. The menu, the heading
87
+ # ids and the template of the theme are part of the build: list only your
88
+ # own here. Paths are relative to this file, then to the generator, which
89
+ # comes with two:
90
+ # plugins/pre_include.py text at the top of every page (shared Jinja macros)
91
+ # plugins/code_include.py code of a git repository inserted in the pages
92
+ # plugin: ['plugins/pre_include.py']
93
+ # plugin_arg: # the options of each extension, by its name
94
+ # pre_include: ['macros.html']
95
+
96
+ # ---------------------------------------------------------------------------
97
+ # Tools
98
+ # ---------------------------------------------------------------------------
99
+
100
+ # The layout report (lhtml-site --layout, needs Playwright, lhtml-site[pdf]): where it is
101
+ # written. The theme says which part of the page it measures.
102
+ # layout:
103
+ # output: '.layout/'
104
+
105
+ # The Chrome run by the PDF export, the layout report and --render, instead of
106
+ # the Chromium of Playwright (a macOS .app is accepted).
107
+ # chrome: '/Applications/Google Chrome.app'
108
+
109
+ # Keep the intermediate files and show the tracebacks (as --debug).
110
+ # debug: false
111
+
112
+ # Clean the HTML of the pages with tidy (needs the tidy library).
113
+ # use_tidy: false