abqari 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (1509) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +889 -0
  3. data/LICENSE +21 -0
  4. data/README.md +2739 -0
  5. data/SECURITY.md +73 -0
  6. data/THIRD_PARTY_NOTICES.md +46 -0
  7. data/app/assets/css/_common.css +3125 -0
  8. data/app/assets/js/carousel.js +39 -0
  9. data/app/assets/js/contact-button.js +28 -0
  10. data/app/assets/js/random-pool.js +44 -0
  11. data/app/assets/js/search-init.js +11 -0
  12. data/app/assets/js/theme-toggle.js +39 -0
  13. data/app/assets/js/viz-tag-bubble.js +108 -0
  14. data/app/assets/js/viz-tag-cooccurrence.js +125 -0
  15. data/app/assets/js/viz-topic-constellation.js +142 -0
  16. data/app/icons/bluesky.svg +3 -0
  17. data/app/icons/github.svg +3 -0
  18. data/app/icons/linkedin.svg +3 -0
  19. data/app/icons/mail.svg +4 -0
  20. data/app/icons/mastodon.svg +3 -0
  21. data/app/icons/moon.svg +3 -0
  22. data/app/icons/rss.svg +3 -0
  23. data/app/icons/sun.svg +4 -0
  24. data/app/icons/x.svg +3 -0
  25. data/app/views/layouts/about.html.erb +70 -0
  26. data/app/views/layouts/application.html.erb +65 -0
  27. data/app/views/layouts/book_series_index.html.erb +43 -0
  28. data/app/views/layouts/bundle.html.erb +111 -0
  29. data/app/views/layouts/bundles_index.html.erb +46 -0
  30. data/app/views/layouts/country_index.html.erb +59 -0
  31. data/app/views/layouts/gallery_index.html.erb +126 -0
  32. data/app/views/layouts/home.html.erb +107 -0
  33. data/app/views/layouts/photo.html.erb +100 -0
  34. data/app/views/layouts/photos_archive.html.erb +101 -0
  35. data/app/views/layouts/photos_index.html.erb +204 -0
  36. data/app/views/layouts/post.html.erb +153 -0
  37. data/app/views/layouts/posts_archive.html.erb +98 -0
  38. data/app/views/layouts/posts_index.html.erb +80 -0
  39. data/app/views/layouts/publication.html.erb +116 -0
  40. data/app/views/layouts/publications_archive.html.erb +89 -0
  41. data/app/views/layouts/publications_index.html.erb +246 -0
  42. data/app/views/layouts/related_index.html.erb +48 -0
  43. data/app/views/layouts/series.html.erb +110 -0
  44. data/app/views/layouts/series_index.html.erb +202 -0
  45. data/app/views/layouts/tag.html.erb +16 -0
  46. data/app/views/layouts/visualization.html.erb +32 -0
  47. data/app/views/layouts/workshop.html.erb +163 -0
  48. data/app/views/layouts/workshops_index.html.erb +209 -0
  49. data/app/views/partials/_back_link.html.erb +27 -0
  50. data/app/views/partials/_back_to_index.html.erb +25 -0
  51. data/app/views/partials/_book_grid.html.erb +76 -0
  52. data/app/views/partials/_book_jsonld.html.erb +72 -0
  53. data/app/views/partials/_book_related.html.erb +87 -0
  54. data/app/views/partials/_breadcrumb_jsonld.html.erb +60 -0
  55. data/app/views/partials/_bundle_cta.html.erb +26 -0
  56. data/app/views/partials/_carousel.html.erb +64 -0
  57. data/app/views/partials/_collection_page_jsonld.html.erb +81 -0
  58. data/app/views/partials/_contact_button.html.erb +42 -0
  59. data/app/views/partials/_course_jsonld.html.erb +95 -0
  60. data/app/views/partials/_draft_banner.html.erb +20 -0
  61. data/app/views/partials/_event_jsonld.html.erb +122 -0
  62. data/app/views/partials/_footer.html.erb +88 -0
  63. data/app/views/partials/_future_banner.html.erb +25 -0
  64. data/app/views/partials/_head.html.erb +440 -0
  65. data/app/views/partials/_image_gallery.html.erb +64 -0
  66. data/app/views/partials/_image_object_jsonld.html.erb +61 -0
  67. data/app/views/partials/_nav.html.erb +63 -0
  68. data/app/views/partials/_newsletter_subscribe.html.erb +85 -0
  69. data/app/views/partials/_next_in_series.html.erb +27 -0
  70. data/app/views/partials/_next_item.html.erb +38 -0
  71. data/app/views/partials/_pagination.html.erb +15 -0
  72. data/app/views/partials/_person_jsonld.html.erb +46 -0
  73. data/app/views/partials/_plausible.html.erb +24 -0
  74. data/app/views/partials/_post_list.html.erb +101 -0
  75. data/app/views/partials/_post_series_previews.html.erb +92 -0
  76. data/app/views/partials/_publication_card.html.erb +75 -0
  77. data/app/views/partials/_publication_header.html.erb +61 -0
  78. data/app/views/partials/_related_item.html.erb +68 -0
  79. data/app/views/partials/_related_items.html.erb +105 -0
  80. data/app/views/partials/_search.html.erb +26 -0
  81. data/app/views/partials/_series_pager.html.erb +48 -0
  82. data/app/views/partials/_skip_link.html.erb +12 -0
  83. data/app/views/partials/_taxonomy_row.html.erb +62 -0
  84. data/app/views/partials/_testimonials.html.erb +149 -0
  85. data/app/views/partials/_theme_toggle.html.erb +19 -0
  86. data/app/views/partials/_toc.html.erb +136 -0
  87. data/app/views/partials/_webmentions.html.erb +131 -0
  88. data/app/views/partials/_website_jsonld.html.erb +39 -0
  89. data/app/views/partials/home/_contact.html.erb +19 -0
  90. data/app/views/partials/home/_featured_publication.html.erb +107 -0
  91. data/app/views/partials/home/_latest_photo.html.erb +95 -0
  92. data/app/views/partials/home/_latest_post.html.erb +48 -0
  93. data/app/views/partials/home/_latest_publication.html.erb +89 -0
  94. data/app/views/partials/home/_next_workshop.html.erb +119 -0
  95. data/app/views/partials/home/_photo_gallery.html.erb +71 -0
  96. data/app/views/partials/home/_random_photo.html.erb +106 -0
  97. data/app/views/partials/home/_random_post.html.erb +64 -0
  98. data/exe/abqari +37 -0
  99. data/lib/abqari/artifact_writer.rb +196 -0
  100. data/lib/abqari/asset_pipeline.rb +235 -0
  101. data/lib/abqari/audit/a11y.rb +80 -0
  102. data/lib/abqari/audit/content.rb +154 -0
  103. data/lib/abqari/audit/dependencies.rb +127 -0
  104. data/lib/abqari/audit/links.rb +120 -0
  105. data/lib/abqari/audit/performance.rb +120 -0
  106. data/lib/abqari/audit/privacy.rb +42 -0
  107. data/lib/abqari/audit/rule.rb +56 -0
  108. data/lib/abqari/audit/seo.rb +105 -0
  109. data/lib/abqari/audit.rb +149 -0
  110. data/lib/abqari/bundle_assets.rb +127 -0
  111. data/lib/abqari/cli/new.rb +541 -0
  112. data/lib/abqari/cli/theme.rb +181 -0
  113. data/lib/abqari/cli.rb +130 -0
  114. data/lib/abqari/erbi_template.rb +72 -0
  115. data/lib/abqari/feed.rb +159 -0
  116. data/lib/abqari/folio.rb +195 -0
  117. data/lib/abqari/font_pipeline.rb +104 -0
  118. data/lib/abqari/headers_file.rb +324 -0
  119. data/lib/abqari/helpers.rb +308 -0
  120. data/lib/abqari/hooks.rb +136 -0
  121. data/lib/abqari/http_safe.rb +222 -0
  122. data/lib/abqari/image_pipeline.rb +800 -0
  123. data/lib/abqari/importers/base.rb +351 -0
  124. data/lib/abqari/importers/cli.rb +169 -0
  125. data/lib/abqari/importers/ghost.rb +113 -0
  126. data/lib/abqari/importers/jekyll.rb +256 -0
  127. data/lib/abqari/importers/substack.rb +204 -0
  128. data/lib/abqari/importers/support/html_to_markdown.rb +126 -0
  129. data/lib/abqari/importers/support/image_downloader.rb +170 -0
  130. data/lib/abqari/importers/support/report.rb +87 -0
  131. data/lib/abqari/importers/support/slug_normalizer.rb +53 -0
  132. data/lib/abqari/importers.rb +64 -0
  133. data/lib/abqari/indieweb.rb +551 -0
  134. data/lib/abqari/llms_txt.rb +110 -0
  135. data/lib/abqari/log.rb +61 -0
  136. data/lib/abqari/manifest.rb +58 -0
  137. data/lib/abqari/minifier.rb +108 -0
  138. data/lib/abqari/og_image_generator.rb +223 -0
  139. data/lib/abqari/page/bundle.rb +152 -0
  140. data/lib/abqari/page/incremental.rb +74 -0
  141. data/lib/abqari/page/parser.rb +129 -0
  142. data/lib/abqari/page/path.rb +153 -0
  143. data/lib/abqari/page.rb +424 -0
  144. data/lib/abqari/paginated_shard.rb +109 -0
  145. data/lib/abqari/paginator.rb +35 -0
  146. data/lib/abqari/path_safe.rb +62 -0
  147. data/lib/abqari/plausible_script.rb +20 -0
  148. data/lib/abqari/publication_normaliser.rb +111 -0
  149. data/lib/abqari/publisher_pages.rb +342 -0
  150. data/lib/abqari/redirects.rb +134 -0
  151. data/lib/abqari/related_index_page.rb +79 -0
  152. data/lib/abqari/render_context/cover_helpers.rb +338 -0
  153. data/lib/abqari/render_context/picture_helpers.rb +178 -0
  154. data/lib/abqari/render_context/publication_helpers.rb +120 -0
  155. data/lib/abqari/render_context.rb +251 -0
  156. data/lib/abqari/renderer.rb +788 -0
  157. data/lib/abqari/robots.rb +93 -0
  158. data/lib/abqari/search.rb +68 -0
  159. data/lib/abqari/security_txt.rb +44 -0
  160. data/lib/abqari/server.rb +508 -0
  161. data/lib/abqari/site.rb +952 -0
  162. data/lib/abqari/site_config.rb +212 -0
  163. data/lib/abqari/site_loader.rb +265 -0
  164. data/lib/abqari/sitemap.rb +87 -0
  165. data/lib/abqari/speculation_rules_guard.rb +26 -0
  166. data/lib/abqari/syndication.rb +466 -0
  167. data/lib/abqari/syntax_highlighter.rb +146 -0
  168. data/lib/abqari/taxonomy_page.rb +129 -0
  169. data/lib/abqari/templates/site_skeleton/.github/dependabot.yml +53 -0
  170. data/lib/abqari/templates/site_skeleton/.github/workflows/deploy-cloudflare.yml +107 -0
  171. data/lib/abqari/templates/site_skeleton/.github/workflows/deploy-github-pages.yml +107 -0
  172. data/lib/abqari/templates/site_skeleton/.github/workflows/deploy-render.yml +87 -0
  173. data/lib/abqari/templates/site_skeleton/.gitignore +24 -0
  174. data/lib/abqari/templates/site_skeleton/.ruby-version.tt +1 -0
  175. data/lib/abqari/templates/site_skeleton/Gemfile.tt +20 -0
  176. data/lib/abqari/templates/site_skeleton/README.md.tt +60 -0
  177. data/lib/abqari/templates/site_skeleton/app/assets/css/site.css +9 -0
  178. data/lib/abqari/templates/site_skeleton/bin/audit +46 -0
  179. data/lib/abqari/templates/site_skeleton/bin/build +32 -0
  180. data/lib/abqari/templates/site_skeleton/bin/fetch-folio +32 -0
  181. data/lib/abqari/templates/site_skeleton/bin/fetch-fonts +20 -0
  182. data/lib/abqari/templates/site_skeleton/bin/import +31 -0
  183. data/lib/abqari/templates/site_skeleton/bin/index +30 -0
  184. data/lib/abqari/templates/site_skeleton/bin/new +235 -0
  185. data/lib/abqari/templates/site_skeleton/bin/serve +30 -0
  186. data/lib/abqari/templates/site_skeleton/config/site.blank.yml.tt +65 -0
  187. data/lib/abqari/templates/site_skeleton/config/site.yml.tt +266 -0
  188. data/lib/abqari/templates/site_skeleton/content/404.md +17 -0
  189. data/lib/abqari/templates/site_skeleton/content/about.blank.md.tt +12 -0
  190. data/lib/abqari/templates/site_skeleton/content/about.md.tt +18 -0
  191. data/lib/abqari/templates/site_skeleton/content/index.blank.md.tt +11 -0
  192. data/lib/abqari/templates/site_skeleton/content/index.md.tt +34 -0
  193. data/lib/abqari/templates/site_skeleton/content/photos/index.md.tt +12 -0
  194. data/lib/abqari/templates/site_skeleton/content/posts/index.md +12 -0
  195. data/lib/abqari/templates/site_skeleton/content/posts/welcome/index.md.tt +50 -0
  196. data/lib/abqari/templates/site_skeleton/content/publications/index.md.tt +13 -0
  197. data/lib/abqari/templates/site_skeleton/content/workshops/index.md.tt +13 -0
  198. data/lib/abqari/templates/site_skeleton/public/robots.txt +6 -0
  199. data/lib/abqari/templates/site_skeleton/themes/.gitkeep +0 -0
  200. data/lib/abqari/templates/site_skeleton/vendor/folio/.gitkeep +0 -0
  201. data/lib/abqari/templates/site_skeleton/vendor/fonts/.gitkeep +0 -0
  202. data/lib/abqari/theme_bootstrap.rb +19 -0
  203. data/lib/abqari/theme_fonts.rb +51 -0
  204. data/lib/abqari/version.rb +18 -0
  205. data/lib/abqari/visualizations.rb +215 -0
  206. data/lib/abqari.rb +154 -0
  207. data/themes/bootstrap/css/app.css +97 -0
  208. data/themes/bootstrap/public/LICENSE +21 -0
  209. data/themes/bootstrap/public/css/bootstrap.min.css +6 -0
  210. data/themes/bootstrap/public/css/bootstrap.min.css.map +1 -0
  211. data/themes/bootstrap/public/js/bootstrap.bundle.min.js +7 -0
  212. data/themes/bootstrap/public/js/bootstrap.bundle.min.js.map +1 -0
  213. data/themes/custom/css/app.css +176 -0
  214. data/themes/magazine/css/app.css +242 -0
  215. data/themes/minimal/css/app.css +151 -0
  216. data/themes/notebook/css/app.css +205 -0
  217. data/themes/sand/css/app.css +179 -0
  218. data/vendor/d3/d3.v7.min.js +2 -0
  219. data/vendor/heroicons/16/solid/academic-cap.svg +4 -0
  220. data/vendor/heroicons/16/solid/adjustments-horizontal.svg +3 -0
  221. data/vendor/heroicons/16/solid/adjustments-vertical.svg +3 -0
  222. data/vendor/heroicons/16/solid/archive-box-arrow-down.svg +4 -0
  223. data/vendor/heroicons/16/solid/archive-box-x-mark.svg +4 -0
  224. data/vendor/heroicons/16/solid/archive-box.svg +4 -0
  225. data/vendor/heroicons/16/solid/arrow-down-circle.svg +3 -0
  226. data/vendor/heroicons/16/solid/arrow-down-left.svg +3 -0
  227. data/vendor/heroicons/16/solid/arrow-down-on-square-stack.svg +4 -0
  228. data/vendor/heroicons/16/solid/arrow-down-on-square.svg +3 -0
  229. data/vendor/heroicons/16/solid/arrow-down-right.svg +3 -0
  230. data/vendor/heroicons/16/solid/arrow-down-tray.svg +4 -0
  231. data/vendor/heroicons/16/solid/arrow-down.svg +3 -0
  232. data/vendor/heroicons/16/solid/arrow-left-circle.svg +3 -0
  233. data/vendor/heroicons/16/solid/arrow-left-end-on-rectangle.svg +4 -0
  234. data/vendor/heroicons/16/solid/arrow-left-start-on-rectangle.svg +3 -0
  235. data/vendor/heroicons/16/solid/arrow-left.svg +3 -0
  236. data/vendor/heroicons/16/solid/arrow-long-down.svg +3 -0
  237. data/vendor/heroicons/16/solid/arrow-long-left.svg +3 -0
  238. data/vendor/heroicons/16/solid/arrow-long-right.svg +3 -0
  239. data/vendor/heroicons/16/solid/arrow-long-up.svg +3 -0
  240. data/vendor/heroicons/16/solid/arrow-path-rounded-square.svg +3 -0
  241. data/vendor/heroicons/16/solid/arrow-path.svg +3 -0
  242. data/vendor/heroicons/16/solid/arrow-right-circle.svg +3 -0
  243. data/vendor/heroicons/16/solid/arrow-right-end-on-rectangle.svg +4 -0
  244. data/vendor/heroicons/16/solid/arrow-right-start-on-rectangle.svg +3 -0
  245. data/vendor/heroicons/16/solid/arrow-right.svg +3 -0
  246. data/vendor/heroicons/16/solid/arrow-top-right-on-square.svg +4 -0
  247. data/vendor/heroicons/16/solid/arrow-trending-down.svg +3 -0
  248. data/vendor/heroicons/16/solid/arrow-trending-up.svg +3 -0
  249. data/vendor/heroicons/16/solid/arrow-turn-down-left.svg +3 -0
  250. data/vendor/heroicons/16/solid/arrow-turn-down-right.svg +3 -0
  251. data/vendor/heroicons/16/solid/arrow-turn-left-down.svg +3 -0
  252. data/vendor/heroicons/16/solid/arrow-turn-left-up.svg +3 -0
  253. data/vendor/heroicons/16/solid/arrow-turn-right-down.svg +3 -0
  254. data/vendor/heroicons/16/solid/arrow-turn-right-up.svg +3 -0
  255. data/vendor/heroicons/16/solid/arrow-turn-up-left.svg +3 -0
  256. data/vendor/heroicons/16/solid/arrow-turn-up-right.svg +3 -0
  257. data/vendor/heroicons/16/solid/arrow-up-circle.svg +3 -0
  258. data/vendor/heroicons/16/solid/arrow-up-left.svg +3 -0
  259. data/vendor/heroicons/16/solid/arrow-up-on-square-stack.svg +4 -0
  260. data/vendor/heroicons/16/solid/arrow-up-on-square.svg +3 -0
  261. data/vendor/heroicons/16/solid/arrow-up-right.svg +3 -0
  262. data/vendor/heroicons/16/solid/arrow-up-tray.svg +4 -0
  263. data/vendor/heroicons/16/solid/arrow-up.svg +3 -0
  264. data/vendor/heroicons/16/solid/arrow-uturn-down.svg +3 -0
  265. data/vendor/heroicons/16/solid/arrow-uturn-left.svg +3 -0
  266. data/vendor/heroicons/16/solid/arrow-uturn-right.svg +3 -0
  267. data/vendor/heroicons/16/solid/arrow-uturn-up.svg +3 -0
  268. data/vendor/heroicons/16/solid/arrows-pointing-in.svg +3 -0
  269. data/vendor/heroicons/16/solid/arrows-pointing-out.svg +3 -0
  270. data/vendor/heroicons/16/solid/arrows-right-left.svg +3 -0
  271. data/vendor/heroicons/16/solid/arrows-up-down.svg +3 -0
  272. data/vendor/heroicons/16/solid/at-symbol.svg +3 -0
  273. data/vendor/heroicons/16/solid/backspace.svg +3 -0
  274. data/vendor/heroicons/16/solid/backward.svg +3 -0
  275. data/vendor/heroicons/16/solid/banknotes.svg +4 -0
  276. data/vendor/heroicons/16/solid/bars-2.svg +3 -0
  277. data/vendor/heroicons/16/solid/bars-3-bottom-left.svg +3 -0
  278. data/vendor/heroicons/16/solid/bars-3-bottom-right.svg +3 -0
  279. data/vendor/heroicons/16/solid/bars-3-center-left.svg +3 -0
  280. data/vendor/heroicons/16/solid/bars-3.svg +3 -0
  281. data/vendor/heroicons/16/solid/bars-4.svg +3 -0
  282. data/vendor/heroicons/16/solid/bars-arrow-down.svg +3 -0
  283. data/vendor/heroicons/16/solid/bars-arrow-up.svg +3 -0
  284. data/vendor/heroicons/16/solid/battery-0.svg +3 -0
  285. data/vendor/heroicons/16/solid/battery-100.svg +4 -0
  286. data/vendor/heroicons/16/solid/battery-50.svg +4 -0
  287. data/vendor/heroicons/16/solid/beaker.svg +3 -0
  288. data/vendor/heroicons/16/solid/bell-alert.svg +4 -0
  289. data/vendor/heroicons/16/solid/bell-slash.svg +4 -0
  290. data/vendor/heroicons/16/solid/bell-snooze.svg +3 -0
  291. data/vendor/heroicons/16/solid/bell.svg +3 -0
  292. data/vendor/heroicons/16/solid/bold.svg +3 -0
  293. data/vendor/heroicons/16/solid/bolt-slash.svg +3 -0
  294. data/vendor/heroicons/16/solid/bolt.svg +3 -0
  295. data/vendor/heroicons/16/solid/book-open.svg +3 -0
  296. data/vendor/heroicons/16/solid/bookmark-slash.svg +3 -0
  297. data/vendor/heroicons/16/solid/bookmark-square.svg +3 -0
  298. data/vendor/heroicons/16/solid/bookmark.svg +3 -0
  299. data/vendor/heroicons/16/solid/briefcase.svg +4 -0
  300. data/vendor/heroicons/16/solid/bug-ant.svg +3 -0
  301. data/vendor/heroicons/16/solid/building-library.svg +3 -0
  302. data/vendor/heroicons/16/solid/building-office-2.svg +3 -0
  303. data/vendor/heroicons/16/solid/building-office.svg +3 -0
  304. data/vendor/heroicons/16/solid/building-storefront.svg +3 -0
  305. data/vendor/heroicons/16/solid/cake.svg +3 -0
  306. data/vendor/heroicons/16/solid/calculator.svg +3 -0
  307. data/vendor/heroicons/16/solid/calendar-date-range.svg +4 -0
  308. data/vendor/heroicons/16/solid/calendar-days.svg +4 -0
  309. data/vendor/heroicons/16/solid/calendar.svg +3 -0
  310. data/vendor/heroicons/16/solid/camera.svg +4 -0
  311. data/vendor/heroicons/16/solid/chart-bar-square.svg +3 -0
  312. data/vendor/heroicons/16/solid/chart-bar.svg +3 -0
  313. data/vendor/heroicons/16/solid/chart-pie.svg +4 -0
  314. data/vendor/heroicons/16/solid/chat-bubble-bottom-center-text.svg +3 -0
  315. data/vendor/heroicons/16/solid/chat-bubble-bottom-center.svg +3 -0
  316. data/vendor/heroicons/16/solid/chat-bubble-left-ellipsis.svg +3 -0
  317. data/vendor/heroicons/16/solid/chat-bubble-left-right.svg +4 -0
  318. data/vendor/heroicons/16/solid/chat-bubble-left.svg +3 -0
  319. data/vendor/heroicons/16/solid/chat-bubble-oval-left-ellipsis.svg +3 -0
  320. data/vendor/heroicons/16/solid/chat-bubble-oval-left.svg +3 -0
  321. data/vendor/heroicons/16/solid/check-badge.svg +3 -0
  322. data/vendor/heroicons/16/solid/check-circle.svg +3 -0
  323. data/vendor/heroicons/16/solid/check.svg +3 -0
  324. data/vendor/heroicons/16/solid/chevron-double-down.svg +3 -0
  325. data/vendor/heroicons/16/solid/chevron-double-left.svg +3 -0
  326. data/vendor/heroicons/16/solid/chevron-double-right.svg +3 -0
  327. data/vendor/heroicons/16/solid/chevron-double-up.svg +3 -0
  328. data/vendor/heroicons/16/solid/chevron-down.svg +3 -0
  329. data/vendor/heroicons/16/solid/chevron-left.svg +3 -0
  330. data/vendor/heroicons/16/solid/chevron-right.svg +3 -0
  331. data/vendor/heroicons/16/solid/chevron-up-down.svg +3 -0
  332. data/vendor/heroicons/16/solid/chevron-up.svg +3 -0
  333. data/vendor/heroicons/16/solid/circle-stack.svg +5 -0
  334. data/vendor/heroicons/16/solid/clipboard-document-check.svg +4 -0
  335. data/vendor/heroicons/16/solid/clipboard-document-list.svg +4 -0
  336. data/vendor/heroicons/16/solid/clipboard-document.svg +4 -0
  337. data/vendor/heroicons/16/solid/clipboard.svg +3 -0
  338. data/vendor/heroicons/16/solid/clock.svg +3 -0
  339. data/vendor/heroicons/16/solid/cloud-arrow-down.svg +3 -0
  340. data/vendor/heroicons/16/solid/cloud-arrow-up.svg +3 -0
  341. data/vendor/heroicons/16/solid/cloud.svg +3 -0
  342. data/vendor/heroicons/16/solid/code-bracket-square.svg +3 -0
  343. data/vendor/heroicons/16/solid/code-bracket.svg +3 -0
  344. data/vendor/heroicons/16/solid/cog-6-tooth.svg +3 -0
  345. data/vendor/heroicons/16/solid/cog-8-tooth.svg +3 -0
  346. data/vendor/heroicons/16/solid/cog.svg +3 -0
  347. data/vendor/heroicons/16/solid/command-line.svg +3 -0
  348. data/vendor/heroicons/16/solid/computer-desktop.svg +3 -0
  349. data/vendor/heroicons/16/solid/cpu-chip.svg +4 -0
  350. data/vendor/heroicons/16/solid/credit-card.svg +4 -0
  351. data/vendor/heroicons/16/solid/cube-transparent.svg +3 -0
  352. data/vendor/heroicons/16/solid/cube.svg +3 -0
  353. data/vendor/heroicons/16/solid/currency-bangladeshi.svg +3 -0
  354. data/vendor/heroicons/16/solid/currency-dollar.svg +4 -0
  355. data/vendor/heroicons/16/solid/currency-euro.svg +3 -0
  356. data/vendor/heroicons/16/solid/currency-pound.svg +3 -0
  357. data/vendor/heroicons/16/solid/currency-rupee.svg +3 -0
  358. data/vendor/heroicons/16/solid/currency-yen.svg +3 -0
  359. data/vendor/heroicons/16/solid/cursor-arrow-rays.svg +3 -0
  360. data/vendor/heroicons/16/solid/cursor-arrow-ripple.svg +5 -0
  361. data/vendor/heroicons/16/solid/device-phone-mobile.svg +4 -0
  362. data/vendor/heroicons/16/solid/device-tablet.svg +4 -0
  363. data/vendor/heroicons/16/solid/divide.svg +4 -0
  364. data/vendor/heroicons/16/solid/document-arrow-down.svg +3 -0
  365. data/vendor/heroicons/16/solid/document-arrow-up.svg +3 -0
  366. data/vendor/heroicons/16/solid/document-chart-bar.svg +3 -0
  367. data/vendor/heroicons/16/solid/document-check.svg +3 -0
  368. data/vendor/heroicons/16/solid/document-currency-bangladeshi.svg +3 -0
  369. data/vendor/heroicons/16/solid/document-currency-dollar.svg +4 -0
  370. data/vendor/heroicons/16/solid/document-currency-euro.svg +3 -0
  371. data/vendor/heroicons/16/solid/document-currency-pound.svg +3 -0
  372. data/vendor/heroicons/16/solid/document-currency-rupee.svg +3 -0
  373. data/vendor/heroicons/16/solid/document-currency-yen.svg +3 -0
  374. data/vendor/heroicons/16/solid/document-duplicate.svg +4 -0
  375. data/vendor/heroicons/16/solid/document-magnifying-glass.svg +4 -0
  376. data/vendor/heroicons/16/solid/document-minus.svg +3 -0
  377. data/vendor/heroicons/16/solid/document-plus.svg +3 -0
  378. data/vendor/heroicons/16/solid/document-text.svg +3 -0
  379. data/vendor/heroicons/16/solid/document.svg +3 -0
  380. data/vendor/heroicons/16/solid/ellipsis-horizontal-circle.svg +3 -0
  381. data/vendor/heroicons/16/solid/ellipsis-horizontal.svg +3 -0
  382. data/vendor/heroicons/16/solid/ellipsis-vertical.svg +3 -0
  383. data/vendor/heroicons/16/solid/envelope-open.svg +3 -0
  384. data/vendor/heroicons/16/solid/envelope.svg +4 -0
  385. data/vendor/heroicons/16/solid/equals.svg +3 -0
  386. data/vendor/heroicons/16/solid/exclamation-circle.svg +3 -0
  387. data/vendor/heroicons/16/solid/exclamation-triangle.svg +3 -0
  388. data/vendor/heroicons/16/solid/eye-dropper.svg +3 -0
  389. data/vendor/heroicons/16/solid/eye-slash.svg +4 -0
  390. data/vendor/heroicons/16/solid/eye.svg +4 -0
  391. data/vendor/heroicons/16/solid/face-frown.svg +3 -0
  392. data/vendor/heroicons/16/solid/face-smile.svg +3 -0
  393. data/vendor/heroicons/16/solid/film.svg +3 -0
  394. data/vendor/heroicons/16/solid/finger-print.svg +3 -0
  395. data/vendor/heroicons/16/solid/fire.svg +3 -0
  396. data/vendor/heroicons/16/solid/flag.svg +3 -0
  397. data/vendor/heroicons/16/solid/folder-arrow-down.svg +3 -0
  398. data/vendor/heroicons/16/solid/folder-minus.svg +3 -0
  399. data/vendor/heroicons/16/solid/folder-open.svg +3 -0
  400. data/vendor/heroicons/16/solid/folder-plus.svg +3 -0
  401. data/vendor/heroicons/16/solid/folder.svg +3 -0
  402. data/vendor/heroicons/16/solid/forward.svg +3 -0
  403. data/vendor/heroicons/16/solid/funnel.svg +3 -0
  404. data/vendor/heroicons/16/solid/gif.svg +3 -0
  405. data/vendor/heroicons/16/solid/gift-top.svg +4 -0
  406. data/vendor/heroicons/16/solid/gift.svg +4 -0
  407. data/vendor/heroicons/16/solid/globe-alt.svg +3 -0
  408. data/vendor/heroicons/16/solid/globe-americas.svg +3 -0
  409. data/vendor/heroicons/16/solid/globe-asia-australia.svg +3 -0
  410. data/vendor/heroicons/16/solid/globe-europe-africa.svg +3 -0
  411. data/vendor/heroicons/16/solid/h1.svg +3 -0
  412. data/vendor/heroicons/16/solid/h2.svg +3 -0
  413. data/vendor/heroicons/16/solid/h3.svg +3 -0
  414. data/vendor/heroicons/16/solid/hand-raised.svg +3 -0
  415. data/vendor/heroicons/16/solid/hand-thumb-down.svg +3 -0
  416. data/vendor/heroicons/16/solid/hand-thumb-up.svg +3 -0
  417. data/vendor/heroicons/16/solid/hashtag.svg +3 -0
  418. data/vendor/heroicons/16/solid/heart.svg +3 -0
  419. data/vendor/heroicons/16/solid/home-modern.svg +3 -0
  420. data/vendor/heroicons/16/solid/home.svg +3 -0
  421. data/vendor/heroicons/16/solid/identification.svg +3 -0
  422. data/vendor/heroicons/16/solid/inbox-arrow-down.svg +4 -0
  423. data/vendor/heroicons/16/solid/inbox-stack.svg +4 -0
  424. data/vendor/heroicons/16/solid/inbox.svg +3 -0
  425. data/vendor/heroicons/16/solid/information-circle.svg +3 -0
  426. data/vendor/heroicons/16/solid/italic.svg +3 -0
  427. data/vendor/heroicons/16/solid/key.svg +3 -0
  428. data/vendor/heroicons/16/solid/language.svg +3 -0
  429. data/vendor/heroicons/16/solid/lifebuoy.svg +3 -0
  430. data/vendor/heroicons/16/solid/light-bulb.svg +3 -0
  431. data/vendor/heroicons/16/solid/link-slash.svg +3 -0
  432. data/vendor/heroicons/16/solid/link.svg +4 -0
  433. data/vendor/heroicons/16/solid/list-bullet.svg +3 -0
  434. data/vendor/heroicons/16/solid/lock-closed.svg +3 -0
  435. data/vendor/heroicons/16/solid/lock-open.svg +3 -0
  436. data/vendor/heroicons/16/solid/magnifying-glass-circle.svg +4 -0
  437. data/vendor/heroicons/16/solid/magnifying-glass-minus.svg +4 -0
  438. data/vendor/heroicons/16/solid/magnifying-glass-plus.svg +4 -0
  439. data/vendor/heroicons/16/solid/magnifying-glass.svg +3 -0
  440. data/vendor/heroicons/16/solid/map-pin.svg +3 -0
  441. data/vendor/heroicons/16/solid/map.svg +3 -0
  442. data/vendor/heroicons/16/solid/megaphone.svg +3 -0
  443. data/vendor/heroicons/16/solid/microphone.svg +4 -0
  444. data/vendor/heroicons/16/solid/minus-circle.svg +3 -0
  445. data/vendor/heroicons/16/solid/minus.svg +3 -0
  446. data/vendor/heroicons/16/solid/moon.svg +3 -0
  447. data/vendor/heroicons/16/solid/musical-note.svg +3 -0
  448. data/vendor/heroicons/16/solid/newspaper.svg +4 -0
  449. data/vendor/heroicons/16/solid/no-symbol.svg +3 -0
  450. data/vendor/heroicons/16/solid/numbered-list.svg +3 -0
  451. data/vendor/heroicons/16/solid/paint-brush.svg +3 -0
  452. data/vendor/heroicons/16/solid/paper-airplane.svg +3 -0
  453. data/vendor/heroicons/16/solid/paper-clip.svg +3 -0
  454. data/vendor/heroicons/16/solid/pause-circle.svg +3 -0
  455. data/vendor/heroicons/16/solid/pause.svg +3 -0
  456. data/vendor/heroicons/16/solid/pencil-square.svg +4 -0
  457. data/vendor/heroicons/16/solid/pencil.svg +3 -0
  458. data/vendor/heroicons/16/solid/percent-badge.svg +3 -0
  459. data/vendor/heroicons/16/solid/phone-arrow-down-left.svg +4 -0
  460. data/vendor/heroicons/16/solid/phone-arrow-up-right.svg +4 -0
  461. data/vendor/heroicons/16/solid/phone-x-mark.svg +4 -0
  462. data/vendor/heroicons/16/solid/phone.svg +3 -0
  463. data/vendor/heroicons/16/solid/photo.svg +3 -0
  464. data/vendor/heroicons/16/solid/play-circle.svg +3 -0
  465. data/vendor/heroicons/16/solid/play-pause.svg +3 -0
  466. data/vendor/heroicons/16/solid/play.svg +3 -0
  467. data/vendor/heroicons/16/solid/plus-circle.svg +3 -0
  468. data/vendor/heroicons/16/solid/plus.svg +3 -0
  469. data/vendor/heroicons/16/solid/power.svg +3 -0
  470. data/vendor/heroicons/16/solid/presentation-chart-bar.svg +3 -0
  471. data/vendor/heroicons/16/solid/presentation-chart-line.svg +3 -0
  472. data/vendor/heroicons/16/solid/printer.svg +3 -0
  473. data/vendor/heroicons/16/solid/puzzle-piece.svg +3 -0
  474. data/vendor/heroicons/16/solid/qr-code.svg +9 -0
  475. data/vendor/heroicons/16/solid/question-mark-circle.svg +3 -0
  476. data/vendor/heroicons/16/solid/queue-list.svg +3 -0
  477. data/vendor/heroicons/16/solid/radio.svg +3 -0
  478. data/vendor/heroicons/16/solid/receipt-percent.svg +3 -0
  479. data/vendor/heroicons/16/solid/receipt-refund.svg +3 -0
  480. data/vendor/heroicons/16/solid/rectangle-group.svg +3 -0
  481. data/vendor/heroicons/16/solid/rectangle-stack.svg +3 -0
  482. data/vendor/heroicons/16/solid/rocket-launch.svg +4 -0
  483. data/vendor/heroicons/16/solid/rss.svg +3 -0
  484. data/vendor/heroicons/16/solid/scale.svg +3 -0
  485. data/vendor/heroicons/16/solid/scissors.svg +4 -0
  486. data/vendor/heroicons/16/solid/server-stack.svg +4 -0
  487. data/vendor/heroicons/16/solid/server.svg +4 -0
  488. data/vendor/heroicons/16/solid/share.svg +3 -0
  489. data/vendor/heroicons/16/solid/shield-check.svg +3 -0
  490. data/vendor/heroicons/16/solid/shield-exclamation.svg +3 -0
  491. data/vendor/heroicons/16/solid/shopping-bag.svg +3 -0
  492. data/vendor/heroicons/16/solid/shopping-cart.svg +3 -0
  493. data/vendor/heroicons/16/solid/signal-slash.svg +3 -0
  494. data/vendor/heroicons/16/solid/signal.svg +5 -0
  495. data/vendor/heroicons/16/solid/slash.svg +3 -0
  496. data/vendor/heroicons/16/solid/sparkles.svg +3 -0
  497. data/vendor/heroicons/16/solid/speaker-wave.svg +4 -0
  498. data/vendor/heroicons/16/solid/speaker-x-mark.svg +3 -0
  499. data/vendor/heroicons/16/solid/square-2-stack.svg +4 -0
  500. data/vendor/heroicons/16/solid/square-3-stack-3d.svg +5 -0
  501. data/vendor/heroicons/16/solid/squares-2x2.svg +3 -0
  502. data/vendor/heroicons/16/solid/squares-plus.svg +3 -0
  503. data/vendor/heroicons/16/solid/star.svg +3 -0
  504. data/vendor/heroicons/16/solid/stop-circle.svg +3 -0
  505. data/vendor/heroicons/16/solid/stop.svg +3 -0
  506. data/vendor/heroicons/16/solid/strikethrough.svg +3 -0
  507. data/vendor/heroicons/16/solid/sun.svg +3 -0
  508. data/vendor/heroicons/16/solid/swatch.svg +4 -0
  509. data/vendor/heroicons/16/solid/table-cells.svg +3 -0
  510. data/vendor/heroicons/16/solid/tag.svg +3 -0
  511. data/vendor/heroicons/16/solid/ticket.svg +3 -0
  512. data/vendor/heroicons/16/solid/trash.svg +3 -0
  513. data/vendor/heroicons/16/solid/trophy.svg +3 -0
  514. data/vendor/heroicons/16/solid/truck.svg +5 -0
  515. data/vendor/heroicons/16/solid/tv.svg +4 -0
  516. data/vendor/heroicons/16/solid/underline.svg +3 -0
  517. data/vendor/heroicons/16/solid/user-circle.svg +3 -0
  518. data/vendor/heroicons/16/solid/user-group.svg +3 -0
  519. data/vendor/heroicons/16/solid/user-minus.svg +3 -0
  520. data/vendor/heroicons/16/solid/user-plus.svg +3 -0
  521. data/vendor/heroicons/16/solid/user.svg +3 -0
  522. data/vendor/heroicons/16/solid/users.svg +3 -0
  523. data/vendor/heroicons/16/solid/variable.svg +3 -0
  524. data/vendor/heroicons/16/solid/video-camera-slash.svg +3 -0
  525. data/vendor/heroicons/16/solid/video-camera.svg +3 -0
  526. data/vendor/heroicons/16/solid/view-columns.svg +3 -0
  527. data/vendor/heroicons/16/solid/viewfinder-circle.svg +3 -0
  528. data/vendor/heroicons/16/solid/wallet.svg +3 -0
  529. data/vendor/heroicons/16/solid/wifi.svg +3 -0
  530. data/vendor/heroicons/16/solid/window.svg +3 -0
  531. data/vendor/heroicons/16/solid/wrench-screwdriver.svg +4 -0
  532. data/vendor/heroicons/16/solid/wrench.svg +3 -0
  533. data/vendor/heroicons/16/solid/x-circle.svg +3 -0
  534. data/vendor/heroicons/16/solid/x-mark.svg +3 -0
  535. data/vendor/heroicons/20/solid/academic-cap.svg +3 -0
  536. data/vendor/heroicons/20/solid/adjustments-horizontal.svg +3 -0
  537. data/vendor/heroicons/20/solid/adjustments-vertical.svg +3 -0
  538. data/vendor/heroicons/20/solid/archive-box-arrow-down.svg +3 -0
  539. data/vendor/heroicons/20/solid/archive-box-x-mark.svg +4 -0
  540. data/vendor/heroicons/20/solid/archive-box.svg +4 -0
  541. data/vendor/heroicons/20/solid/arrow-down-circle.svg +3 -0
  542. data/vendor/heroicons/20/solid/arrow-down-left.svg +3 -0
  543. data/vendor/heroicons/20/solid/arrow-down-on-square-stack.svg +3 -0
  544. data/vendor/heroicons/20/solid/arrow-down-on-square.svg +3 -0
  545. data/vendor/heroicons/20/solid/arrow-down-right.svg +3 -0
  546. data/vendor/heroicons/20/solid/arrow-down-tray.svg +4 -0
  547. data/vendor/heroicons/20/solid/arrow-down.svg +3 -0
  548. data/vendor/heroicons/20/solid/arrow-left-circle.svg +3 -0
  549. data/vendor/heroicons/20/solid/arrow-left-end-on-rectangle.svg +4 -0
  550. data/vendor/heroicons/20/solid/arrow-left-on-rectangle.svg +4 -0
  551. data/vendor/heroicons/20/solid/arrow-left-start-on-rectangle.svg +4 -0
  552. data/vendor/heroicons/20/solid/arrow-left.svg +3 -0
  553. data/vendor/heroicons/20/solid/arrow-long-down.svg +3 -0
  554. data/vendor/heroicons/20/solid/arrow-long-left.svg +3 -0
  555. data/vendor/heroicons/20/solid/arrow-long-right.svg +3 -0
  556. data/vendor/heroicons/20/solid/arrow-long-up.svg +3 -0
  557. data/vendor/heroicons/20/solid/arrow-path-rounded-square.svg +3 -0
  558. data/vendor/heroicons/20/solid/arrow-path.svg +3 -0
  559. data/vendor/heroicons/20/solid/arrow-right-circle.svg +3 -0
  560. data/vendor/heroicons/20/solid/arrow-right-end-on-rectangle.svg +4 -0
  561. data/vendor/heroicons/20/solid/arrow-right-on-rectangle.svg +4 -0
  562. data/vendor/heroicons/20/solid/arrow-right-start-on-rectangle.svg +4 -0
  563. data/vendor/heroicons/20/solid/arrow-right.svg +3 -0
  564. data/vendor/heroicons/20/solid/arrow-small-down.svg +3 -0
  565. data/vendor/heroicons/20/solid/arrow-small-left.svg +3 -0
  566. data/vendor/heroicons/20/solid/arrow-small-right.svg +3 -0
  567. data/vendor/heroicons/20/solid/arrow-small-up.svg +3 -0
  568. data/vendor/heroicons/20/solid/arrow-top-right-on-square.svg +4 -0
  569. data/vendor/heroicons/20/solid/arrow-trending-down.svg +3 -0
  570. data/vendor/heroicons/20/solid/arrow-trending-up.svg +3 -0
  571. data/vendor/heroicons/20/solid/arrow-turn-down-left.svg +3 -0
  572. data/vendor/heroicons/20/solid/arrow-turn-down-right.svg +3 -0
  573. data/vendor/heroicons/20/solid/arrow-turn-left-down.svg +3 -0
  574. data/vendor/heroicons/20/solid/arrow-turn-left-up.svg +3 -0
  575. data/vendor/heroicons/20/solid/arrow-turn-right-down.svg +3 -0
  576. data/vendor/heroicons/20/solid/arrow-turn-right-up.svg +3 -0
  577. data/vendor/heroicons/20/solid/arrow-turn-up-left.svg +3 -0
  578. data/vendor/heroicons/20/solid/arrow-turn-up-right.svg +3 -0
  579. data/vendor/heroicons/20/solid/arrow-up-circle.svg +3 -0
  580. data/vendor/heroicons/20/solid/arrow-up-left.svg +3 -0
  581. data/vendor/heroicons/20/solid/arrow-up-on-square-stack.svg +3 -0
  582. data/vendor/heroicons/20/solid/arrow-up-on-square.svg +3 -0
  583. data/vendor/heroicons/20/solid/arrow-up-right.svg +3 -0
  584. data/vendor/heroicons/20/solid/arrow-up-tray.svg +4 -0
  585. data/vendor/heroicons/20/solid/arrow-up.svg +3 -0
  586. data/vendor/heroicons/20/solid/arrow-uturn-down.svg +3 -0
  587. data/vendor/heroicons/20/solid/arrow-uturn-left.svg +3 -0
  588. data/vendor/heroicons/20/solid/arrow-uturn-right.svg +3 -0
  589. data/vendor/heroicons/20/solid/arrow-uturn-up.svg +3 -0
  590. data/vendor/heroicons/20/solid/arrows-pointing-in.svg +3 -0
  591. data/vendor/heroicons/20/solid/arrows-pointing-out.svg +3 -0
  592. data/vendor/heroicons/20/solid/arrows-right-left.svg +3 -0
  593. data/vendor/heroicons/20/solid/arrows-up-down.svg +3 -0
  594. data/vendor/heroicons/20/solid/at-symbol.svg +3 -0
  595. data/vendor/heroicons/20/solid/backspace.svg +3 -0
  596. data/vendor/heroicons/20/solid/backward.svg +3 -0
  597. data/vendor/heroicons/20/solid/banknotes.svg +3 -0
  598. data/vendor/heroicons/20/solid/bars-2.svg +3 -0
  599. data/vendor/heroicons/20/solid/bars-3-bottom-left.svg +3 -0
  600. data/vendor/heroicons/20/solid/bars-3-bottom-right.svg +3 -0
  601. data/vendor/heroicons/20/solid/bars-3-center-left.svg +3 -0
  602. data/vendor/heroicons/20/solid/bars-3.svg +3 -0
  603. data/vendor/heroicons/20/solid/bars-4.svg +3 -0
  604. data/vendor/heroicons/20/solid/bars-arrow-down.svg +3 -0
  605. data/vendor/heroicons/20/solid/bars-arrow-up.svg +3 -0
  606. data/vendor/heroicons/20/solid/battery-0.svg +3 -0
  607. data/vendor/heroicons/20/solid/battery-100.svg +4 -0
  608. data/vendor/heroicons/20/solid/battery-50.svg +4 -0
  609. data/vendor/heroicons/20/solid/beaker.svg +3 -0
  610. data/vendor/heroicons/20/solid/bell-alert.svg +4 -0
  611. data/vendor/heroicons/20/solid/bell-slash.svg +3 -0
  612. data/vendor/heroicons/20/solid/bell-snooze.svg +3 -0
  613. data/vendor/heroicons/20/solid/bell.svg +3 -0
  614. data/vendor/heroicons/20/solid/bold.svg +3 -0
  615. data/vendor/heroicons/20/solid/bolt-slash.svg +4 -0
  616. data/vendor/heroicons/20/solid/bolt.svg +3 -0
  617. data/vendor/heroicons/20/solid/book-open.svg +3 -0
  618. data/vendor/heroicons/20/solid/bookmark-slash.svg +3 -0
  619. data/vendor/heroicons/20/solid/bookmark-square.svg +3 -0
  620. data/vendor/heroicons/20/solid/bookmark.svg +3 -0
  621. data/vendor/heroicons/20/solid/briefcase.svg +4 -0
  622. data/vendor/heroicons/20/solid/bug-ant.svg +3 -0
  623. data/vendor/heroicons/20/solid/building-library.svg +3 -0
  624. data/vendor/heroicons/20/solid/building-office-2.svg +3 -0
  625. data/vendor/heroicons/20/solid/building-office.svg +3 -0
  626. data/vendor/heroicons/20/solid/building-storefront.svg +3 -0
  627. data/vendor/heroicons/20/solid/cake.svg +3 -0
  628. data/vendor/heroicons/20/solid/calculator.svg +3 -0
  629. data/vendor/heroicons/20/solid/calendar-date-range.svg +4 -0
  630. data/vendor/heroicons/20/solid/calendar-days.svg +4 -0
  631. data/vendor/heroicons/20/solid/calendar.svg +3 -0
  632. data/vendor/heroicons/20/solid/camera.svg +3 -0
  633. data/vendor/heroicons/20/solid/chart-bar-square.svg +3 -0
  634. data/vendor/heroicons/20/solid/chart-bar.svg +3 -0
  635. data/vendor/heroicons/20/solid/chart-pie.svg +4 -0
  636. data/vendor/heroicons/20/solid/chat-bubble-bottom-center-text.svg +3 -0
  637. data/vendor/heroicons/20/solid/chat-bubble-bottom-center.svg +3 -0
  638. data/vendor/heroicons/20/solid/chat-bubble-left-ellipsis.svg +3 -0
  639. data/vendor/heroicons/20/solid/chat-bubble-left-right.svg +4 -0
  640. data/vendor/heroicons/20/solid/chat-bubble-left.svg +3 -0
  641. data/vendor/heroicons/20/solid/chat-bubble-oval-left-ellipsis.svg +3 -0
  642. data/vendor/heroicons/20/solid/chat-bubble-oval-left.svg +3 -0
  643. data/vendor/heroicons/20/solid/check-badge.svg +3 -0
  644. data/vendor/heroicons/20/solid/check-circle.svg +3 -0
  645. data/vendor/heroicons/20/solid/check.svg +3 -0
  646. data/vendor/heroicons/20/solid/chevron-double-down.svg +3 -0
  647. data/vendor/heroicons/20/solid/chevron-double-left.svg +3 -0
  648. data/vendor/heroicons/20/solid/chevron-double-right.svg +3 -0
  649. data/vendor/heroicons/20/solid/chevron-double-up.svg +3 -0
  650. data/vendor/heroicons/20/solid/chevron-down.svg +3 -0
  651. data/vendor/heroicons/20/solid/chevron-left.svg +3 -0
  652. data/vendor/heroicons/20/solid/chevron-right.svg +3 -0
  653. data/vendor/heroicons/20/solid/chevron-up-down.svg +3 -0
  654. data/vendor/heroicons/20/solid/chevron-up.svg +3 -0
  655. data/vendor/heroicons/20/solid/circle-stack.svg +3 -0
  656. data/vendor/heroicons/20/solid/clipboard-document-check.svg +4 -0
  657. data/vendor/heroicons/20/solid/clipboard-document-list.svg +4 -0
  658. data/vendor/heroicons/20/solid/clipboard-document.svg +4 -0
  659. data/vendor/heroicons/20/solid/clipboard.svg +3 -0
  660. data/vendor/heroicons/20/solid/clock.svg +3 -0
  661. data/vendor/heroicons/20/solid/cloud-arrow-down.svg +3 -0
  662. data/vendor/heroicons/20/solid/cloud-arrow-up.svg +3 -0
  663. data/vendor/heroicons/20/solid/cloud.svg +3 -0
  664. data/vendor/heroicons/20/solid/code-bracket-square.svg +3 -0
  665. data/vendor/heroicons/20/solid/code-bracket.svg +3 -0
  666. data/vendor/heroicons/20/solid/cog-6-tooth.svg +3 -0
  667. data/vendor/heroicons/20/solid/cog-8-tooth.svg +3 -0
  668. data/vendor/heroicons/20/solid/cog.svg +4 -0
  669. data/vendor/heroicons/20/solid/command-line.svg +3 -0
  670. data/vendor/heroicons/20/solid/computer-desktop.svg +3 -0
  671. data/vendor/heroicons/20/solid/cpu-chip.svg +4 -0
  672. data/vendor/heroicons/20/solid/credit-card.svg +3 -0
  673. data/vendor/heroicons/20/solid/cube-transparent.svg +3 -0
  674. data/vendor/heroicons/20/solid/cube.svg +3 -0
  675. data/vendor/heroicons/20/solid/currency-bangladeshi.svg +3 -0
  676. data/vendor/heroicons/20/solid/currency-dollar.svg +4 -0
  677. data/vendor/heroicons/20/solid/currency-euro.svg +3 -0
  678. data/vendor/heroicons/20/solid/currency-pound.svg +3 -0
  679. data/vendor/heroicons/20/solid/currency-rupee.svg +3 -0
  680. data/vendor/heroicons/20/solid/currency-yen.svg +3 -0
  681. data/vendor/heroicons/20/solid/cursor-arrow-rays.svg +3 -0
  682. data/vendor/heroicons/20/solid/cursor-arrow-ripple.svg +5 -0
  683. data/vendor/heroicons/20/solid/device-phone-mobile.svg +4 -0
  684. data/vendor/heroicons/20/solid/device-tablet.svg +3 -0
  685. data/vendor/heroicons/20/solid/divide.svg +3 -0
  686. data/vendor/heroicons/20/solid/document-arrow-down.svg +3 -0
  687. data/vendor/heroicons/20/solid/document-arrow-up.svg +3 -0
  688. data/vendor/heroicons/20/solid/document-chart-bar.svg +3 -0
  689. data/vendor/heroicons/20/solid/document-check.svg +3 -0
  690. data/vendor/heroicons/20/solid/document-currency-bangladeshi.svg +3 -0
  691. data/vendor/heroicons/20/solid/document-currency-dollar.svg +3 -0
  692. data/vendor/heroicons/20/solid/document-currency-euro.svg +3 -0
  693. data/vendor/heroicons/20/solid/document-currency-pound.svg +3 -0
  694. data/vendor/heroicons/20/solid/document-currency-rupee.svg +3 -0
  695. data/vendor/heroicons/20/solid/document-currency-yen.svg +3 -0
  696. data/vendor/heroicons/20/solid/document-duplicate.svg +4 -0
  697. data/vendor/heroicons/20/solid/document-magnifying-glass.svg +4 -0
  698. data/vendor/heroicons/20/solid/document-minus.svg +3 -0
  699. data/vendor/heroicons/20/solid/document-plus.svg +3 -0
  700. data/vendor/heroicons/20/solid/document-text.svg +3 -0
  701. data/vendor/heroicons/20/solid/document.svg +3 -0
  702. data/vendor/heroicons/20/solid/ellipsis-horizontal-circle.svg +3 -0
  703. data/vendor/heroicons/20/solid/ellipsis-horizontal.svg +3 -0
  704. data/vendor/heroicons/20/solid/ellipsis-vertical.svg +3 -0
  705. data/vendor/heroicons/20/solid/envelope-open.svg +3 -0
  706. data/vendor/heroicons/20/solid/envelope.svg +4 -0
  707. data/vendor/heroicons/20/solid/equals.svg +3 -0
  708. data/vendor/heroicons/20/solid/exclamation-circle.svg +3 -0
  709. data/vendor/heroicons/20/solid/exclamation-triangle.svg +3 -0
  710. data/vendor/heroicons/20/solid/eye-dropper.svg +3 -0
  711. data/vendor/heroicons/20/solid/eye-slash.svg +4 -0
  712. data/vendor/heroicons/20/solid/eye.svg +4 -0
  713. data/vendor/heroicons/20/solid/face-frown.svg +3 -0
  714. data/vendor/heroicons/20/solid/face-smile.svg +3 -0
  715. data/vendor/heroicons/20/solid/film.svg +3 -0
  716. data/vendor/heroicons/20/solid/finger-print.svg +3 -0
  717. data/vendor/heroicons/20/solid/fire.svg +3 -0
  718. data/vendor/heroicons/20/solid/flag.svg +3 -0
  719. data/vendor/heroicons/20/solid/folder-arrow-down.svg +3 -0
  720. data/vendor/heroicons/20/solid/folder-minus.svg +3 -0
  721. data/vendor/heroicons/20/solid/folder-open.svg +3 -0
  722. data/vendor/heroicons/20/solid/folder-plus.svg +3 -0
  723. data/vendor/heroicons/20/solid/folder.svg +3 -0
  724. data/vendor/heroicons/20/solid/forward.svg +3 -0
  725. data/vendor/heroicons/20/solid/funnel.svg +3 -0
  726. data/vendor/heroicons/20/solid/gif.svg +3 -0
  727. data/vendor/heroicons/20/solid/gift-top.svg +3 -0
  728. data/vendor/heroicons/20/solid/gift.svg +4 -0
  729. data/vendor/heroicons/20/solid/globe-alt.svg +3 -0
  730. data/vendor/heroicons/20/solid/globe-americas.svg +3 -0
  731. data/vendor/heroicons/20/solid/globe-asia-australia.svg +3 -0
  732. data/vendor/heroicons/20/solid/globe-europe-africa.svg +3 -0
  733. data/vendor/heroicons/20/solid/h1.svg +3 -0
  734. data/vendor/heroicons/20/solid/h2.svg +3 -0
  735. data/vendor/heroicons/20/solid/h3.svg +3 -0
  736. data/vendor/heroicons/20/solid/hand-raised.svg +3 -0
  737. data/vendor/heroicons/20/solid/hand-thumb-down.svg +3 -0
  738. data/vendor/heroicons/20/solid/hand-thumb-up.svg +3 -0
  739. data/vendor/heroicons/20/solid/hashtag.svg +3 -0
  740. data/vendor/heroicons/20/solid/heart.svg +3 -0
  741. data/vendor/heroicons/20/solid/home-modern.svg +3 -0
  742. data/vendor/heroicons/20/solid/home.svg +3 -0
  743. data/vendor/heroicons/20/solid/identification.svg +3 -0
  744. data/vendor/heroicons/20/solid/inbox-arrow-down.svg +4 -0
  745. data/vendor/heroicons/20/solid/inbox-stack.svg +4 -0
  746. data/vendor/heroicons/20/solid/inbox.svg +3 -0
  747. data/vendor/heroicons/20/solid/information-circle.svg +3 -0
  748. data/vendor/heroicons/20/solid/italic.svg +3 -0
  749. data/vendor/heroicons/20/solid/key.svg +3 -0
  750. data/vendor/heroicons/20/solid/language.svg +4 -0
  751. data/vendor/heroicons/20/solid/lifebuoy.svg +3 -0
  752. data/vendor/heroicons/20/solid/light-bulb.svg +3 -0
  753. data/vendor/heroicons/20/solid/link-slash.svg +3 -0
  754. data/vendor/heroicons/20/solid/link.svg +4 -0
  755. data/vendor/heroicons/20/solid/list-bullet.svg +3 -0
  756. data/vendor/heroicons/20/solid/lock-closed.svg +3 -0
  757. data/vendor/heroicons/20/solid/lock-open.svg +3 -0
  758. data/vendor/heroicons/20/solid/magnifying-glass-circle.svg +4 -0
  759. data/vendor/heroicons/20/solid/magnifying-glass-minus.svg +4 -0
  760. data/vendor/heroicons/20/solid/magnifying-glass-plus.svg +4 -0
  761. data/vendor/heroicons/20/solid/magnifying-glass.svg +3 -0
  762. data/vendor/heroicons/20/solid/map-pin.svg +3 -0
  763. data/vendor/heroicons/20/solid/map.svg +3 -0
  764. data/vendor/heroicons/20/solid/megaphone.svg +3 -0
  765. data/vendor/heroicons/20/solid/microphone.svg +4 -0
  766. data/vendor/heroicons/20/solid/minus-circle.svg +3 -0
  767. data/vendor/heroicons/20/solid/minus-small.svg +3 -0
  768. data/vendor/heroicons/20/solid/minus.svg +3 -0
  769. data/vendor/heroicons/20/solid/moon.svg +3 -0
  770. data/vendor/heroicons/20/solid/musical-note.svg +3 -0
  771. data/vendor/heroicons/20/solid/newspaper.svg +4 -0
  772. data/vendor/heroicons/20/solid/no-symbol.svg +3 -0
  773. data/vendor/heroicons/20/solid/numbered-list.svg +3 -0
  774. data/vendor/heroicons/20/solid/paint-brush.svg +3 -0
  775. data/vendor/heroicons/20/solid/paper-airplane.svg +3 -0
  776. data/vendor/heroicons/20/solid/paper-clip.svg +3 -0
  777. data/vendor/heroicons/20/solid/pause-circle.svg +3 -0
  778. data/vendor/heroicons/20/solid/pause.svg +3 -0
  779. data/vendor/heroicons/20/solid/pencil-square.svg +4 -0
  780. data/vendor/heroicons/20/solid/pencil.svg +3 -0
  781. data/vendor/heroicons/20/solid/percent-badge.svg +3 -0
  782. data/vendor/heroicons/20/solid/phone-arrow-down-left.svg +3 -0
  783. data/vendor/heroicons/20/solid/phone-arrow-up-right.svg +3 -0
  784. data/vendor/heroicons/20/solid/phone-x-mark.svg +3 -0
  785. data/vendor/heroicons/20/solid/phone.svg +3 -0
  786. data/vendor/heroicons/20/solid/photo.svg +3 -0
  787. data/vendor/heroicons/20/solid/play-circle.svg +3 -0
  788. data/vendor/heroicons/20/solid/play-pause.svg +3 -0
  789. data/vendor/heroicons/20/solid/play.svg +3 -0
  790. data/vendor/heroicons/20/solid/plus-circle.svg +3 -0
  791. data/vendor/heroicons/20/solid/plus-small.svg +3 -0
  792. data/vendor/heroicons/20/solid/plus.svg +3 -0
  793. data/vendor/heroicons/20/solid/power.svg +3 -0
  794. data/vendor/heroicons/20/solid/presentation-chart-bar.svg +3 -0
  795. data/vendor/heroicons/20/solid/presentation-chart-line.svg +3 -0
  796. data/vendor/heroicons/20/solid/printer.svg +3 -0
  797. data/vendor/heroicons/20/solid/puzzle-piece.svg +3 -0
  798. data/vendor/heroicons/20/solid/qr-code.svg +3 -0
  799. data/vendor/heroicons/20/solid/question-mark-circle.svg +3 -0
  800. data/vendor/heroicons/20/solid/queue-list.svg +3 -0
  801. data/vendor/heroicons/20/solid/radio.svg +3 -0
  802. data/vendor/heroicons/20/solid/receipt-percent.svg +3 -0
  803. data/vendor/heroicons/20/solid/receipt-refund.svg +3 -0
  804. data/vendor/heroicons/20/solid/rectangle-group.svg +3 -0
  805. data/vendor/heroicons/20/solid/rectangle-stack.svg +3 -0
  806. data/vendor/heroicons/20/solid/rocket-launch.svg +4 -0
  807. data/vendor/heroicons/20/solid/rss.svg +4 -0
  808. data/vendor/heroicons/20/solid/scale.svg +3 -0
  809. data/vendor/heroicons/20/solid/scissors.svg +4 -0
  810. data/vendor/heroicons/20/solid/server-stack.svg +4 -0
  811. data/vendor/heroicons/20/solid/server.svg +4 -0
  812. data/vendor/heroicons/20/solid/share.svg +3 -0
  813. data/vendor/heroicons/20/solid/shield-check.svg +3 -0
  814. data/vendor/heroicons/20/solid/shield-exclamation.svg +3 -0
  815. data/vendor/heroicons/20/solid/shopping-bag.svg +3 -0
  816. data/vendor/heroicons/20/solid/shopping-cart.svg +3 -0
  817. data/vendor/heroicons/20/solid/signal-slash.svg +3 -0
  818. data/vendor/heroicons/20/solid/signal.svg +4 -0
  819. data/vendor/heroicons/20/solid/slash.svg +3 -0
  820. data/vendor/heroicons/20/solid/sparkles.svg +3 -0
  821. data/vendor/heroicons/20/solid/speaker-wave.svg +4 -0
  822. data/vendor/heroicons/20/solid/speaker-x-mark.svg +3 -0
  823. data/vendor/heroicons/20/solid/square-2-stack.svg +4 -0
  824. data/vendor/heroicons/20/solid/square-3-stack-3d.svg +5 -0
  825. data/vendor/heroicons/20/solid/squares-2x2.svg +3 -0
  826. data/vendor/heroicons/20/solid/squares-plus.svg +3 -0
  827. data/vendor/heroicons/20/solid/star.svg +3 -0
  828. data/vendor/heroicons/20/solid/stop-circle.svg +3 -0
  829. data/vendor/heroicons/20/solid/stop.svg +3 -0
  830. data/vendor/heroicons/20/solid/strikethrough.svg +3 -0
  831. data/vendor/heroicons/20/solid/sun.svg +3 -0
  832. data/vendor/heroicons/20/solid/swatch.svg +3 -0
  833. data/vendor/heroicons/20/solid/table-cells.svg +3 -0
  834. data/vendor/heroicons/20/solid/tag.svg +3 -0
  835. data/vendor/heroicons/20/solid/ticket.svg +3 -0
  836. data/vendor/heroicons/20/solid/trash.svg +3 -0
  837. data/vendor/heroicons/20/solid/trophy.svg +3 -0
  838. data/vendor/heroicons/20/solid/truck.svg +4 -0
  839. data/vendor/heroicons/20/solid/tv.svg +4 -0
  840. data/vendor/heroicons/20/solid/underline.svg +3 -0
  841. data/vendor/heroicons/20/solid/user-circle.svg +3 -0
  842. data/vendor/heroicons/20/solid/user-group.svg +3 -0
  843. data/vendor/heroicons/20/solid/user-minus.svg +3 -0
  844. data/vendor/heroicons/20/solid/user-plus.svg +3 -0
  845. data/vendor/heroicons/20/solid/user.svg +3 -0
  846. data/vendor/heroicons/20/solid/users.svg +3 -0
  847. data/vendor/heroicons/20/solid/variable.svg +3 -0
  848. data/vendor/heroicons/20/solid/video-camera-slash.svg +3 -0
  849. data/vendor/heroicons/20/solid/video-camera.svg +3 -0
  850. data/vendor/heroicons/20/solid/view-columns.svg +3 -0
  851. data/vendor/heroicons/20/solid/viewfinder-circle.svg +3 -0
  852. data/vendor/heroicons/20/solid/wallet.svg +3 -0
  853. data/vendor/heroicons/20/solid/wifi.svg +3 -0
  854. data/vendor/heroicons/20/solid/window.svg +3 -0
  855. data/vendor/heroicons/20/solid/wrench-screwdriver.svg +4 -0
  856. data/vendor/heroicons/20/solid/wrench.svg +3 -0
  857. data/vendor/heroicons/20/solid/x-circle.svg +3 -0
  858. data/vendor/heroicons/20/solid/x-mark.svg +3 -0
  859. data/vendor/heroicons/24/outline/academic-cap.svg +3 -0
  860. data/vendor/heroicons/24/outline/adjustments-horizontal.svg +3 -0
  861. data/vendor/heroicons/24/outline/adjustments-vertical.svg +3 -0
  862. data/vendor/heroicons/24/outline/archive-box-arrow-down.svg +3 -0
  863. data/vendor/heroicons/24/outline/archive-box-x-mark.svg +3 -0
  864. data/vendor/heroicons/24/outline/archive-box.svg +3 -0
  865. data/vendor/heroicons/24/outline/arrow-down-circle.svg +3 -0
  866. data/vendor/heroicons/24/outline/arrow-down-left.svg +3 -0
  867. data/vendor/heroicons/24/outline/arrow-down-on-square-stack.svg +3 -0
  868. data/vendor/heroicons/24/outline/arrow-down-on-square.svg +3 -0
  869. data/vendor/heroicons/24/outline/arrow-down-right.svg +3 -0
  870. data/vendor/heroicons/24/outline/arrow-down-tray.svg +3 -0
  871. data/vendor/heroicons/24/outline/arrow-down.svg +3 -0
  872. data/vendor/heroicons/24/outline/arrow-left-circle.svg +3 -0
  873. data/vendor/heroicons/24/outline/arrow-left-end-on-rectangle.svg +3 -0
  874. data/vendor/heroicons/24/outline/arrow-left-on-rectangle.svg +3 -0
  875. data/vendor/heroicons/24/outline/arrow-left-start-on-rectangle.svg +3 -0
  876. data/vendor/heroicons/24/outline/arrow-left.svg +3 -0
  877. data/vendor/heroicons/24/outline/arrow-long-down.svg +3 -0
  878. data/vendor/heroicons/24/outline/arrow-long-left.svg +3 -0
  879. data/vendor/heroicons/24/outline/arrow-long-right.svg +3 -0
  880. data/vendor/heroicons/24/outline/arrow-long-up.svg +3 -0
  881. data/vendor/heroicons/24/outline/arrow-path-rounded-square.svg +3 -0
  882. data/vendor/heroicons/24/outline/arrow-path.svg +3 -0
  883. data/vendor/heroicons/24/outline/arrow-right-circle.svg +3 -0
  884. data/vendor/heroicons/24/outline/arrow-right-end-on-rectangle.svg +3 -0
  885. data/vendor/heroicons/24/outline/arrow-right-on-rectangle.svg +3 -0
  886. data/vendor/heroicons/24/outline/arrow-right-start-on-rectangle.svg +3 -0
  887. data/vendor/heroicons/24/outline/arrow-right.svg +3 -0
  888. data/vendor/heroicons/24/outline/arrow-small-down.svg +3 -0
  889. data/vendor/heroicons/24/outline/arrow-small-left.svg +3 -0
  890. data/vendor/heroicons/24/outline/arrow-small-right.svg +3 -0
  891. data/vendor/heroicons/24/outline/arrow-small-up.svg +3 -0
  892. data/vendor/heroicons/24/outline/arrow-top-right-on-square.svg +3 -0
  893. data/vendor/heroicons/24/outline/arrow-trending-down.svg +3 -0
  894. data/vendor/heroicons/24/outline/arrow-trending-up.svg +3 -0
  895. data/vendor/heroicons/24/outline/arrow-turn-down-left.svg +3 -0
  896. data/vendor/heroicons/24/outline/arrow-turn-down-right.svg +3 -0
  897. data/vendor/heroicons/24/outline/arrow-turn-left-down.svg +3 -0
  898. data/vendor/heroicons/24/outline/arrow-turn-left-up.svg +3 -0
  899. data/vendor/heroicons/24/outline/arrow-turn-right-down.svg +3 -0
  900. data/vendor/heroicons/24/outline/arrow-turn-right-up.svg +3 -0
  901. data/vendor/heroicons/24/outline/arrow-turn-up-left.svg +3 -0
  902. data/vendor/heroicons/24/outline/arrow-turn-up-right.svg +3 -0
  903. data/vendor/heroicons/24/outline/arrow-up-circle.svg +3 -0
  904. data/vendor/heroicons/24/outline/arrow-up-left.svg +3 -0
  905. data/vendor/heroicons/24/outline/arrow-up-on-square-stack.svg +3 -0
  906. data/vendor/heroicons/24/outline/arrow-up-on-square.svg +3 -0
  907. data/vendor/heroicons/24/outline/arrow-up-right.svg +3 -0
  908. data/vendor/heroicons/24/outline/arrow-up-tray.svg +3 -0
  909. data/vendor/heroicons/24/outline/arrow-up.svg +3 -0
  910. data/vendor/heroicons/24/outline/arrow-uturn-down.svg +3 -0
  911. data/vendor/heroicons/24/outline/arrow-uturn-left.svg +3 -0
  912. data/vendor/heroicons/24/outline/arrow-uturn-right.svg +3 -0
  913. data/vendor/heroicons/24/outline/arrow-uturn-up.svg +3 -0
  914. data/vendor/heroicons/24/outline/arrows-pointing-in.svg +3 -0
  915. data/vendor/heroicons/24/outline/arrows-pointing-out.svg +3 -0
  916. data/vendor/heroicons/24/outline/arrows-right-left.svg +3 -0
  917. data/vendor/heroicons/24/outline/arrows-up-down.svg +3 -0
  918. data/vendor/heroicons/24/outline/at-symbol.svg +3 -0
  919. data/vendor/heroicons/24/outline/backspace.svg +3 -0
  920. data/vendor/heroicons/24/outline/backward.svg +3 -0
  921. data/vendor/heroicons/24/outline/banknotes.svg +3 -0
  922. data/vendor/heroicons/24/outline/bars-2.svg +3 -0
  923. data/vendor/heroicons/24/outline/bars-3-bottom-left.svg +3 -0
  924. data/vendor/heroicons/24/outline/bars-3-bottom-right.svg +3 -0
  925. data/vendor/heroicons/24/outline/bars-3-center-left.svg +3 -0
  926. data/vendor/heroicons/24/outline/bars-3.svg +3 -0
  927. data/vendor/heroicons/24/outline/bars-4.svg +3 -0
  928. data/vendor/heroicons/24/outline/bars-arrow-down.svg +3 -0
  929. data/vendor/heroicons/24/outline/bars-arrow-up.svg +3 -0
  930. data/vendor/heroicons/24/outline/battery-0.svg +3 -0
  931. data/vendor/heroicons/24/outline/battery-100.svg +3 -0
  932. data/vendor/heroicons/24/outline/battery-50.svg +3 -0
  933. data/vendor/heroicons/24/outline/beaker.svg +3 -0
  934. data/vendor/heroicons/24/outline/bell-alert.svg +3 -0
  935. data/vendor/heroicons/24/outline/bell-slash.svg +3 -0
  936. data/vendor/heroicons/24/outline/bell-snooze.svg +3 -0
  937. data/vendor/heroicons/24/outline/bell.svg +3 -0
  938. data/vendor/heroicons/24/outline/bold.svg +3 -0
  939. data/vendor/heroicons/24/outline/bolt-slash.svg +3 -0
  940. data/vendor/heroicons/24/outline/bolt.svg +3 -0
  941. data/vendor/heroicons/24/outline/book-open.svg +3 -0
  942. data/vendor/heroicons/24/outline/bookmark-slash.svg +3 -0
  943. data/vendor/heroicons/24/outline/bookmark-square.svg +3 -0
  944. data/vendor/heroicons/24/outline/bookmark.svg +3 -0
  945. data/vendor/heroicons/24/outline/briefcase.svg +3 -0
  946. data/vendor/heroicons/24/outline/bug-ant.svg +3 -0
  947. data/vendor/heroicons/24/outline/building-library.svg +3 -0
  948. data/vendor/heroicons/24/outline/building-office-2.svg +3 -0
  949. data/vendor/heroicons/24/outline/building-office.svg +3 -0
  950. data/vendor/heroicons/24/outline/building-storefront.svg +3 -0
  951. data/vendor/heroicons/24/outline/cake.svg +3 -0
  952. data/vendor/heroicons/24/outline/calculator.svg +3 -0
  953. data/vendor/heroicons/24/outline/calendar-date-range.svg +3 -0
  954. data/vendor/heroicons/24/outline/calendar-days.svg +3 -0
  955. data/vendor/heroicons/24/outline/calendar.svg +3 -0
  956. data/vendor/heroicons/24/outline/camera.svg +4 -0
  957. data/vendor/heroicons/24/outline/chart-bar-square.svg +3 -0
  958. data/vendor/heroicons/24/outline/chart-bar.svg +3 -0
  959. data/vendor/heroicons/24/outline/chart-pie.svg +4 -0
  960. data/vendor/heroicons/24/outline/chat-bubble-bottom-center-text.svg +3 -0
  961. data/vendor/heroicons/24/outline/chat-bubble-bottom-center.svg +3 -0
  962. data/vendor/heroicons/24/outline/chat-bubble-left-ellipsis.svg +3 -0
  963. data/vendor/heroicons/24/outline/chat-bubble-left-right.svg +3 -0
  964. data/vendor/heroicons/24/outline/chat-bubble-left.svg +3 -0
  965. data/vendor/heroicons/24/outline/chat-bubble-oval-left-ellipsis.svg +3 -0
  966. data/vendor/heroicons/24/outline/chat-bubble-oval-left.svg +3 -0
  967. data/vendor/heroicons/24/outline/check-badge.svg +3 -0
  968. data/vendor/heroicons/24/outline/check-circle.svg +3 -0
  969. data/vendor/heroicons/24/outline/check.svg +3 -0
  970. data/vendor/heroicons/24/outline/chevron-double-down.svg +3 -0
  971. data/vendor/heroicons/24/outline/chevron-double-left.svg +3 -0
  972. data/vendor/heroicons/24/outline/chevron-double-right.svg +3 -0
  973. data/vendor/heroicons/24/outline/chevron-double-up.svg +4 -0
  974. data/vendor/heroicons/24/outline/chevron-down.svg +3 -0
  975. data/vendor/heroicons/24/outline/chevron-left.svg +3 -0
  976. data/vendor/heroicons/24/outline/chevron-right.svg +3 -0
  977. data/vendor/heroicons/24/outline/chevron-up-down.svg +3 -0
  978. data/vendor/heroicons/24/outline/chevron-up.svg +3 -0
  979. data/vendor/heroicons/24/outline/circle-stack.svg +3 -0
  980. data/vendor/heroicons/24/outline/clipboard-document-check.svg +3 -0
  981. data/vendor/heroicons/24/outline/clipboard-document-list.svg +3 -0
  982. data/vendor/heroicons/24/outline/clipboard-document.svg +3 -0
  983. data/vendor/heroicons/24/outline/clipboard.svg +3 -0
  984. data/vendor/heroicons/24/outline/clock.svg +3 -0
  985. data/vendor/heroicons/24/outline/cloud-arrow-down.svg +3 -0
  986. data/vendor/heroicons/24/outline/cloud-arrow-up.svg +3 -0
  987. data/vendor/heroicons/24/outline/cloud.svg +3 -0
  988. data/vendor/heroicons/24/outline/code-bracket-square.svg +3 -0
  989. data/vendor/heroicons/24/outline/code-bracket.svg +3 -0
  990. data/vendor/heroicons/24/outline/cog-6-tooth.svg +4 -0
  991. data/vendor/heroicons/24/outline/cog-8-tooth.svg +4 -0
  992. data/vendor/heroicons/24/outline/cog.svg +3 -0
  993. data/vendor/heroicons/24/outline/command-line.svg +3 -0
  994. data/vendor/heroicons/24/outline/computer-desktop.svg +3 -0
  995. data/vendor/heroicons/24/outline/cpu-chip.svg +3 -0
  996. data/vendor/heroicons/24/outline/credit-card.svg +3 -0
  997. data/vendor/heroicons/24/outline/cube-transparent.svg +3 -0
  998. data/vendor/heroicons/24/outline/cube.svg +3 -0
  999. data/vendor/heroicons/24/outline/currency-bangladeshi.svg +3 -0
  1000. data/vendor/heroicons/24/outline/currency-dollar.svg +3 -0
  1001. data/vendor/heroicons/24/outline/currency-euro.svg +3 -0
  1002. data/vendor/heroicons/24/outline/currency-pound.svg +3 -0
  1003. data/vendor/heroicons/24/outline/currency-rupee.svg +3 -0
  1004. data/vendor/heroicons/24/outline/currency-yen.svg +3 -0
  1005. data/vendor/heroicons/24/outline/cursor-arrow-rays.svg +3 -0
  1006. data/vendor/heroicons/24/outline/cursor-arrow-ripple.svg +3 -0
  1007. data/vendor/heroicons/24/outline/device-phone-mobile.svg +3 -0
  1008. data/vendor/heroicons/24/outline/device-tablet.svg +3 -0
  1009. data/vendor/heroicons/24/outline/divide.svg +3 -0
  1010. data/vendor/heroicons/24/outline/document-arrow-down.svg +3 -0
  1011. data/vendor/heroicons/24/outline/document-arrow-up.svg +3 -0
  1012. data/vendor/heroicons/24/outline/document-chart-bar.svg +3 -0
  1013. data/vendor/heroicons/24/outline/document-check.svg +3 -0
  1014. data/vendor/heroicons/24/outline/document-currency-bangladeshi.svg +3 -0
  1015. data/vendor/heroicons/24/outline/document-currency-dollar.svg +3 -0
  1016. data/vendor/heroicons/24/outline/document-currency-euro.svg +3 -0
  1017. data/vendor/heroicons/24/outline/document-currency-pound.svg +3 -0
  1018. data/vendor/heroicons/24/outline/document-currency-rupee.svg +3 -0
  1019. data/vendor/heroicons/24/outline/document-currency-yen.svg +3 -0
  1020. data/vendor/heroicons/24/outline/document-duplicate.svg +3 -0
  1021. data/vendor/heroicons/24/outline/document-magnifying-glass.svg +3 -0
  1022. data/vendor/heroicons/24/outline/document-minus.svg +3 -0
  1023. data/vendor/heroicons/24/outline/document-plus.svg +3 -0
  1024. data/vendor/heroicons/24/outline/document-text.svg +3 -0
  1025. data/vendor/heroicons/24/outline/document.svg +3 -0
  1026. data/vendor/heroicons/24/outline/ellipsis-horizontal-circle.svg +3 -0
  1027. data/vendor/heroicons/24/outline/ellipsis-horizontal.svg +3 -0
  1028. data/vendor/heroicons/24/outline/ellipsis-vertical.svg +3 -0
  1029. data/vendor/heroicons/24/outline/envelope-open.svg +3 -0
  1030. data/vendor/heroicons/24/outline/envelope.svg +3 -0
  1031. data/vendor/heroicons/24/outline/equals.svg +3 -0
  1032. data/vendor/heroicons/24/outline/exclamation-circle.svg +3 -0
  1033. data/vendor/heroicons/24/outline/exclamation-triangle.svg +3 -0
  1034. data/vendor/heroicons/24/outline/eye-dropper.svg +3 -0
  1035. data/vendor/heroicons/24/outline/eye-slash.svg +3 -0
  1036. data/vendor/heroicons/24/outline/eye.svg +4 -0
  1037. data/vendor/heroicons/24/outline/face-frown.svg +3 -0
  1038. data/vendor/heroicons/24/outline/face-smile.svg +3 -0
  1039. data/vendor/heroicons/24/outline/film.svg +3 -0
  1040. data/vendor/heroicons/24/outline/finger-print.svg +3 -0
  1041. data/vendor/heroicons/24/outline/fire.svg +4 -0
  1042. data/vendor/heroicons/24/outline/flag.svg +3 -0
  1043. data/vendor/heroicons/24/outline/folder-arrow-down.svg +3 -0
  1044. data/vendor/heroicons/24/outline/folder-minus.svg +3 -0
  1045. data/vendor/heroicons/24/outline/folder-open.svg +3 -0
  1046. data/vendor/heroicons/24/outline/folder-plus.svg +3 -0
  1047. data/vendor/heroicons/24/outline/folder.svg +3 -0
  1048. data/vendor/heroicons/24/outline/forward.svg +3 -0
  1049. data/vendor/heroicons/24/outline/funnel.svg +3 -0
  1050. data/vendor/heroicons/24/outline/gif.svg +3 -0
  1051. data/vendor/heroicons/24/outline/gift-top.svg +3 -0
  1052. data/vendor/heroicons/24/outline/gift.svg +3 -0
  1053. data/vendor/heroicons/24/outline/globe-alt.svg +3 -0
  1054. data/vendor/heroicons/24/outline/globe-americas.svg +3 -0
  1055. data/vendor/heroicons/24/outline/globe-asia-australia.svg +3 -0
  1056. data/vendor/heroicons/24/outline/globe-europe-africa.svg +3 -0
  1057. data/vendor/heroicons/24/outline/h1.svg +3 -0
  1058. data/vendor/heroicons/24/outline/h2.svg +3 -0
  1059. data/vendor/heroicons/24/outline/h3.svg +3 -0
  1060. data/vendor/heroicons/24/outline/hand-raised.svg +3 -0
  1061. data/vendor/heroicons/24/outline/hand-thumb-down.svg +3 -0
  1062. data/vendor/heroicons/24/outline/hand-thumb-up.svg +3 -0
  1063. data/vendor/heroicons/24/outline/hashtag.svg +3 -0
  1064. data/vendor/heroicons/24/outline/heart.svg +3 -0
  1065. data/vendor/heroicons/24/outline/home-modern.svg +3 -0
  1066. data/vendor/heroicons/24/outline/home.svg +3 -0
  1067. data/vendor/heroicons/24/outline/identification.svg +3 -0
  1068. data/vendor/heroicons/24/outline/inbox-arrow-down.svg +3 -0
  1069. data/vendor/heroicons/24/outline/inbox-stack.svg +3 -0
  1070. data/vendor/heroicons/24/outline/inbox.svg +3 -0
  1071. data/vendor/heroicons/24/outline/information-circle.svg +3 -0
  1072. data/vendor/heroicons/24/outline/italic.svg +3 -0
  1073. data/vendor/heroicons/24/outline/key.svg +3 -0
  1074. data/vendor/heroicons/24/outline/language.svg +3 -0
  1075. data/vendor/heroicons/24/outline/lifebuoy.svg +3 -0
  1076. data/vendor/heroicons/24/outline/light-bulb.svg +3 -0
  1077. data/vendor/heroicons/24/outline/link-slash.svg +3 -0
  1078. data/vendor/heroicons/24/outline/link.svg +3 -0
  1079. data/vendor/heroicons/24/outline/list-bullet.svg +3 -0
  1080. data/vendor/heroicons/24/outline/lock-closed.svg +3 -0
  1081. data/vendor/heroicons/24/outline/lock-open.svg +3 -0
  1082. data/vendor/heroicons/24/outline/magnifying-glass-circle.svg +3 -0
  1083. data/vendor/heroicons/24/outline/magnifying-glass-minus.svg +3 -0
  1084. data/vendor/heroicons/24/outline/magnifying-glass-plus.svg +3 -0
  1085. data/vendor/heroicons/24/outline/magnifying-glass.svg +3 -0
  1086. data/vendor/heroicons/24/outline/map-pin.svg +4 -0
  1087. data/vendor/heroicons/24/outline/map.svg +3 -0
  1088. data/vendor/heroicons/24/outline/megaphone.svg +3 -0
  1089. data/vendor/heroicons/24/outline/microphone.svg +3 -0
  1090. data/vendor/heroicons/24/outline/minus-circle.svg +3 -0
  1091. data/vendor/heroicons/24/outline/minus-small.svg +3 -0
  1092. data/vendor/heroicons/24/outline/minus.svg +3 -0
  1093. data/vendor/heroicons/24/outline/moon.svg +3 -0
  1094. data/vendor/heroicons/24/outline/musical-note.svg +3 -0
  1095. data/vendor/heroicons/24/outline/newspaper.svg +3 -0
  1096. data/vendor/heroicons/24/outline/no-symbol.svg +3 -0
  1097. data/vendor/heroicons/24/outline/numbered-list.svg +3 -0
  1098. data/vendor/heroicons/24/outline/paint-brush.svg +3 -0
  1099. data/vendor/heroicons/24/outline/paper-airplane.svg +3 -0
  1100. data/vendor/heroicons/24/outline/paper-clip.svg +3 -0
  1101. data/vendor/heroicons/24/outline/pause-circle.svg +3 -0
  1102. data/vendor/heroicons/24/outline/pause.svg +3 -0
  1103. data/vendor/heroicons/24/outline/pencil-square.svg +3 -0
  1104. data/vendor/heroicons/24/outline/pencil.svg +3 -0
  1105. data/vendor/heroicons/24/outline/percent-badge.svg +3 -0
  1106. data/vendor/heroicons/24/outline/phone-arrow-down-left.svg +3 -0
  1107. data/vendor/heroicons/24/outline/phone-arrow-up-right.svg +3 -0
  1108. data/vendor/heroicons/24/outline/phone-x-mark.svg +3 -0
  1109. data/vendor/heroicons/24/outline/phone.svg +3 -0
  1110. data/vendor/heroicons/24/outline/photo.svg +3 -0
  1111. data/vendor/heroicons/24/outline/play-circle.svg +4 -0
  1112. data/vendor/heroicons/24/outline/play-pause.svg +3 -0
  1113. data/vendor/heroicons/24/outline/play.svg +3 -0
  1114. data/vendor/heroicons/24/outline/plus-circle.svg +3 -0
  1115. data/vendor/heroicons/24/outline/plus-small.svg +3 -0
  1116. data/vendor/heroicons/24/outline/plus.svg +3 -0
  1117. data/vendor/heroicons/24/outline/power.svg +3 -0
  1118. data/vendor/heroicons/24/outline/presentation-chart-bar.svg +3 -0
  1119. data/vendor/heroicons/24/outline/presentation-chart-line.svg +3 -0
  1120. data/vendor/heroicons/24/outline/printer.svg +3 -0
  1121. data/vendor/heroicons/24/outline/puzzle-piece.svg +3 -0
  1122. data/vendor/heroicons/24/outline/qr-code.svg +4 -0
  1123. data/vendor/heroicons/24/outline/question-mark-circle.svg +3 -0
  1124. data/vendor/heroicons/24/outline/queue-list.svg +3 -0
  1125. data/vendor/heroicons/24/outline/radio.svg +3 -0
  1126. data/vendor/heroicons/24/outline/receipt-percent.svg +3 -0
  1127. data/vendor/heroicons/24/outline/receipt-refund.svg +3 -0
  1128. data/vendor/heroicons/24/outline/rectangle-group.svg +3 -0
  1129. data/vendor/heroicons/24/outline/rectangle-stack.svg +3 -0
  1130. data/vendor/heroicons/24/outline/rocket-launch.svg +3 -0
  1131. data/vendor/heroicons/24/outline/rss.svg +3 -0
  1132. data/vendor/heroicons/24/outline/scale.svg +3 -0
  1133. data/vendor/heroicons/24/outline/scissors.svg +3 -0
  1134. data/vendor/heroicons/24/outline/server-stack.svg +3 -0
  1135. data/vendor/heroicons/24/outline/server.svg +3 -0
  1136. data/vendor/heroicons/24/outline/share.svg +3 -0
  1137. data/vendor/heroicons/24/outline/shield-check.svg +3 -0
  1138. data/vendor/heroicons/24/outline/shield-exclamation.svg +3 -0
  1139. data/vendor/heroicons/24/outline/shopping-bag.svg +3 -0
  1140. data/vendor/heroicons/24/outline/shopping-cart.svg +3 -0
  1141. data/vendor/heroicons/24/outline/signal-slash.svg +3 -0
  1142. data/vendor/heroicons/24/outline/signal.svg +3 -0
  1143. data/vendor/heroicons/24/outline/slash.svg +3 -0
  1144. data/vendor/heroicons/24/outline/sparkles.svg +3 -0
  1145. data/vendor/heroicons/24/outline/speaker-wave.svg +3 -0
  1146. data/vendor/heroicons/24/outline/speaker-x-mark.svg +3 -0
  1147. data/vendor/heroicons/24/outline/square-2-stack.svg +3 -0
  1148. data/vendor/heroicons/24/outline/square-3-stack-3d.svg +3 -0
  1149. data/vendor/heroicons/24/outline/squares-2x2.svg +3 -0
  1150. data/vendor/heroicons/24/outline/squares-plus.svg +3 -0
  1151. data/vendor/heroicons/24/outline/star.svg +3 -0
  1152. data/vendor/heroicons/24/outline/stop-circle.svg +4 -0
  1153. data/vendor/heroicons/24/outline/stop.svg +3 -0
  1154. data/vendor/heroicons/24/outline/strikethrough.svg +3 -0
  1155. data/vendor/heroicons/24/outline/sun.svg +3 -0
  1156. data/vendor/heroicons/24/outline/swatch.svg +3 -0
  1157. data/vendor/heroicons/24/outline/table-cells.svg +3 -0
  1158. data/vendor/heroicons/24/outline/tag.svg +4 -0
  1159. data/vendor/heroicons/24/outline/ticket.svg +3 -0
  1160. data/vendor/heroicons/24/outline/trash.svg +3 -0
  1161. data/vendor/heroicons/24/outline/trophy.svg +3 -0
  1162. data/vendor/heroicons/24/outline/truck.svg +3 -0
  1163. data/vendor/heroicons/24/outline/tv.svg +3 -0
  1164. data/vendor/heroicons/24/outline/underline.svg +3 -0
  1165. data/vendor/heroicons/24/outline/user-circle.svg +3 -0
  1166. data/vendor/heroicons/24/outline/user-group.svg +3 -0
  1167. data/vendor/heroicons/24/outline/user-minus.svg +3 -0
  1168. data/vendor/heroicons/24/outline/user-plus.svg +3 -0
  1169. data/vendor/heroicons/24/outline/user.svg +3 -0
  1170. data/vendor/heroicons/24/outline/users.svg +3 -0
  1171. data/vendor/heroicons/24/outline/variable.svg +3 -0
  1172. data/vendor/heroicons/24/outline/video-camera-slash.svg +3 -0
  1173. data/vendor/heroicons/24/outline/video-camera.svg +3 -0
  1174. data/vendor/heroicons/24/outline/view-columns.svg +3 -0
  1175. data/vendor/heroicons/24/outline/viewfinder-circle.svg +3 -0
  1176. data/vendor/heroicons/24/outline/wallet.svg +3 -0
  1177. data/vendor/heroicons/24/outline/wifi.svg +3 -0
  1178. data/vendor/heroicons/24/outline/window.svg +3 -0
  1179. data/vendor/heroicons/24/outline/wrench-screwdriver.svg +3 -0
  1180. data/vendor/heroicons/24/outline/wrench.svg +4 -0
  1181. data/vendor/heroicons/24/outline/x-circle.svg +3 -0
  1182. data/vendor/heroicons/24/outline/x-mark.svg +3 -0
  1183. data/vendor/heroicons/24/solid/academic-cap.svg +5 -0
  1184. data/vendor/heroicons/24/solid/adjustments-horizontal.svg +3 -0
  1185. data/vendor/heroicons/24/solid/adjustments-vertical.svg +3 -0
  1186. data/vendor/heroicons/24/solid/archive-box-arrow-down.svg +4 -0
  1187. data/vendor/heroicons/24/solid/archive-box-x-mark.svg +4 -0
  1188. data/vendor/heroicons/24/solid/archive-box.svg +4 -0
  1189. data/vendor/heroicons/24/solid/arrow-down-circle.svg +3 -0
  1190. data/vendor/heroicons/24/solid/arrow-down-left.svg +3 -0
  1191. data/vendor/heroicons/24/solid/arrow-down-on-square-stack.svg +4 -0
  1192. data/vendor/heroicons/24/solid/arrow-down-on-square.svg +3 -0
  1193. data/vendor/heroicons/24/solid/arrow-down-right.svg +3 -0
  1194. data/vendor/heroicons/24/solid/arrow-down-tray.svg +3 -0
  1195. data/vendor/heroicons/24/solid/arrow-down.svg +3 -0
  1196. data/vendor/heroicons/24/solid/arrow-left-circle.svg +3 -0
  1197. data/vendor/heroicons/24/solid/arrow-left-end-on-rectangle.svg +3 -0
  1198. data/vendor/heroicons/24/solid/arrow-left-on-rectangle.svg +3 -0
  1199. data/vendor/heroicons/24/solid/arrow-left-start-on-rectangle.svg +3 -0
  1200. data/vendor/heroicons/24/solid/arrow-left.svg +3 -0
  1201. data/vendor/heroicons/24/solid/arrow-long-down.svg +3 -0
  1202. data/vendor/heroicons/24/solid/arrow-long-left.svg +3 -0
  1203. data/vendor/heroicons/24/solid/arrow-long-right.svg +3 -0
  1204. data/vendor/heroicons/24/solid/arrow-long-up.svg +3 -0
  1205. data/vendor/heroicons/24/solid/arrow-path-rounded-square.svg +3 -0
  1206. data/vendor/heroicons/24/solid/arrow-path.svg +3 -0
  1207. data/vendor/heroicons/24/solid/arrow-right-circle.svg +3 -0
  1208. data/vendor/heroicons/24/solid/arrow-right-end-on-rectangle.svg +3 -0
  1209. data/vendor/heroicons/24/solid/arrow-right-on-rectangle.svg +3 -0
  1210. data/vendor/heroicons/24/solid/arrow-right-start-on-rectangle.svg +3 -0
  1211. data/vendor/heroicons/24/solid/arrow-right.svg +3 -0
  1212. data/vendor/heroicons/24/solid/arrow-small-down.svg +3 -0
  1213. data/vendor/heroicons/24/solid/arrow-small-left.svg +3 -0
  1214. data/vendor/heroicons/24/solid/arrow-small-right.svg +3 -0
  1215. data/vendor/heroicons/24/solid/arrow-small-up.svg +3 -0
  1216. data/vendor/heroicons/24/solid/arrow-top-right-on-square.svg +3 -0
  1217. data/vendor/heroicons/24/solid/arrow-trending-down.svg +3 -0
  1218. data/vendor/heroicons/24/solid/arrow-trending-up.svg +3 -0
  1219. data/vendor/heroicons/24/solid/arrow-turn-down-left.svg +3 -0
  1220. data/vendor/heroicons/24/solid/arrow-turn-down-right.svg +3 -0
  1221. data/vendor/heroicons/24/solid/arrow-turn-left-down.svg +3 -0
  1222. data/vendor/heroicons/24/solid/arrow-turn-left-up.svg +3 -0
  1223. data/vendor/heroicons/24/solid/arrow-turn-right-down.svg +3 -0
  1224. data/vendor/heroicons/24/solid/arrow-turn-right-up.svg +3 -0
  1225. data/vendor/heroicons/24/solid/arrow-turn-up-left.svg +3 -0
  1226. data/vendor/heroicons/24/solid/arrow-turn-up-right.svg +3 -0
  1227. data/vendor/heroicons/24/solid/arrow-up-circle.svg +3 -0
  1228. data/vendor/heroicons/24/solid/arrow-up-left.svg +3 -0
  1229. data/vendor/heroicons/24/solid/arrow-up-on-square-stack.svg +4 -0
  1230. data/vendor/heroicons/24/solid/arrow-up-on-square.svg +3 -0
  1231. data/vendor/heroicons/24/solid/arrow-up-right.svg +3 -0
  1232. data/vendor/heroicons/24/solid/arrow-up-tray.svg +3 -0
  1233. data/vendor/heroicons/24/solid/arrow-up.svg +3 -0
  1234. data/vendor/heroicons/24/solid/arrow-uturn-down.svg +3 -0
  1235. data/vendor/heroicons/24/solid/arrow-uturn-left.svg +3 -0
  1236. data/vendor/heroicons/24/solid/arrow-uturn-right.svg +3 -0
  1237. data/vendor/heroicons/24/solid/arrow-uturn-up.svg +3 -0
  1238. data/vendor/heroicons/24/solid/arrows-pointing-in.svg +3 -0
  1239. data/vendor/heroicons/24/solid/arrows-pointing-out.svg +3 -0
  1240. data/vendor/heroicons/24/solid/arrows-right-left.svg +3 -0
  1241. data/vendor/heroicons/24/solid/arrows-up-down.svg +3 -0
  1242. data/vendor/heroicons/24/solid/at-symbol.svg +3 -0
  1243. data/vendor/heroicons/24/solid/backspace.svg +3 -0
  1244. data/vendor/heroicons/24/solid/backward.svg +3 -0
  1245. data/vendor/heroicons/24/solid/banknotes.svg +5 -0
  1246. data/vendor/heroicons/24/solid/bars-2.svg +3 -0
  1247. data/vendor/heroicons/24/solid/bars-3-bottom-left.svg +3 -0
  1248. data/vendor/heroicons/24/solid/bars-3-bottom-right.svg +3 -0
  1249. data/vendor/heroicons/24/solid/bars-3-center-left.svg +3 -0
  1250. data/vendor/heroicons/24/solid/bars-3.svg +3 -0
  1251. data/vendor/heroicons/24/solid/bars-4.svg +3 -0
  1252. data/vendor/heroicons/24/solid/bars-arrow-down.svg +3 -0
  1253. data/vendor/heroicons/24/solid/bars-arrow-up.svg +3 -0
  1254. data/vendor/heroicons/24/solid/battery-0.svg +3 -0
  1255. data/vendor/heroicons/24/solid/battery-100.svg +3 -0
  1256. data/vendor/heroicons/24/solid/battery-50.svg +4 -0
  1257. data/vendor/heroicons/24/solid/beaker.svg +3 -0
  1258. data/vendor/heroicons/24/solid/bell-alert.svg +4 -0
  1259. data/vendor/heroicons/24/solid/bell-slash.svg +4 -0
  1260. data/vendor/heroicons/24/solid/bell-snooze.svg +3 -0
  1261. data/vendor/heroicons/24/solid/bell.svg +3 -0
  1262. data/vendor/heroicons/24/solid/bold.svg +3 -0
  1263. data/vendor/heroicons/24/solid/bolt-slash.svg +3 -0
  1264. data/vendor/heroicons/24/solid/bolt.svg +3 -0
  1265. data/vendor/heroicons/24/solid/book-open.svg +3 -0
  1266. data/vendor/heroicons/24/solid/bookmark-slash.svg +3 -0
  1267. data/vendor/heroicons/24/solid/bookmark-square.svg +3 -0
  1268. data/vendor/heroicons/24/solid/bookmark.svg +3 -0
  1269. data/vendor/heroicons/24/solid/briefcase.svg +4 -0
  1270. data/vendor/heroicons/24/solid/bug-ant.svg +3 -0
  1271. data/vendor/heroicons/24/solid/building-library.svg +5 -0
  1272. data/vendor/heroicons/24/solid/building-office-2.svg +3 -0
  1273. data/vendor/heroicons/24/solid/building-office.svg +3 -0
  1274. data/vendor/heroicons/24/solid/building-storefront.svg +4 -0
  1275. data/vendor/heroicons/24/solid/cake.svg +3 -0
  1276. data/vendor/heroicons/24/solid/calculator.svg +3 -0
  1277. data/vendor/heroicons/24/solid/calendar-date-range.svg +4 -0
  1278. data/vendor/heroicons/24/solid/calendar-days.svg +4 -0
  1279. data/vendor/heroicons/24/solid/calendar.svg +3 -0
  1280. data/vendor/heroicons/24/solid/camera.svg +4 -0
  1281. data/vendor/heroicons/24/solid/chart-bar-square.svg +3 -0
  1282. data/vendor/heroicons/24/solid/chart-bar.svg +3 -0
  1283. data/vendor/heroicons/24/solid/chart-pie.svg +4 -0
  1284. data/vendor/heroicons/24/solid/chat-bubble-bottom-center-text.svg +3 -0
  1285. data/vendor/heroicons/24/solid/chat-bubble-bottom-center.svg +3 -0
  1286. data/vendor/heroicons/24/solid/chat-bubble-left-ellipsis.svg +3 -0
  1287. data/vendor/heroicons/24/solid/chat-bubble-left-right.svg +4 -0
  1288. data/vendor/heroicons/24/solid/chat-bubble-left.svg +3 -0
  1289. data/vendor/heroicons/24/solid/chat-bubble-oval-left-ellipsis.svg +3 -0
  1290. data/vendor/heroicons/24/solid/chat-bubble-oval-left.svg +3 -0
  1291. data/vendor/heroicons/24/solid/check-badge.svg +3 -0
  1292. data/vendor/heroicons/24/solid/check-circle.svg +3 -0
  1293. data/vendor/heroicons/24/solid/check.svg +3 -0
  1294. data/vendor/heroicons/24/solid/chevron-double-down.svg +4 -0
  1295. data/vendor/heroicons/24/solid/chevron-double-left.svg +4 -0
  1296. data/vendor/heroicons/24/solid/chevron-double-right.svg +4 -0
  1297. data/vendor/heroicons/24/solid/chevron-double-up.svg +4 -0
  1298. data/vendor/heroicons/24/solid/chevron-down.svg +3 -0
  1299. data/vendor/heroicons/24/solid/chevron-left.svg +3 -0
  1300. data/vendor/heroicons/24/solid/chevron-right.svg +3 -0
  1301. data/vendor/heroicons/24/solid/chevron-up-down.svg +3 -0
  1302. data/vendor/heroicons/24/solid/chevron-up.svg +3 -0
  1303. data/vendor/heroicons/24/solid/circle-stack.svg +6 -0
  1304. data/vendor/heroicons/24/solid/clipboard-document-check.svg +4 -0
  1305. data/vendor/heroicons/24/solid/clipboard-document-list.svg +4 -0
  1306. data/vendor/heroicons/24/solid/clipboard-document.svg +5 -0
  1307. data/vendor/heroicons/24/solid/clipboard.svg +3 -0
  1308. data/vendor/heroicons/24/solid/clock.svg +3 -0
  1309. data/vendor/heroicons/24/solid/cloud-arrow-down.svg +3 -0
  1310. data/vendor/heroicons/24/solid/cloud-arrow-up.svg +3 -0
  1311. data/vendor/heroicons/24/solid/cloud.svg +3 -0
  1312. data/vendor/heroicons/24/solid/code-bracket-square.svg +3 -0
  1313. data/vendor/heroicons/24/solid/code-bracket.svg +3 -0
  1314. data/vendor/heroicons/24/solid/cog-6-tooth.svg +3 -0
  1315. data/vendor/heroicons/24/solid/cog-8-tooth.svg +3 -0
  1316. data/vendor/heroicons/24/solid/cog.svg +4 -0
  1317. data/vendor/heroicons/24/solid/command-line.svg +3 -0
  1318. data/vendor/heroicons/24/solid/computer-desktop.svg +3 -0
  1319. data/vendor/heroicons/24/solid/cpu-chip.svg +4 -0
  1320. data/vendor/heroicons/24/solid/credit-card.svg +4 -0
  1321. data/vendor/heroicons/24/solid/cube-transparent.svg +3 -0
  1322. data/vendor/heroicons/24/solid/cube.svg +3 -0
  1323. data/vendor/heroicons/24/solid/currency-bangladeshi.svg +3 -0
  1324. data/vendor/heroicons/24/solid/currency-dollar.svg +4 -0
  1325. data/vendor/heroicons/24/solid/currency-euro.svg +3 -0
  1326. data/vendor/heroicons/24/solid/currency-pound.svg +3 -0
  1327. data/vendor/heroicons/24/solid/currency-rupee.svg +3 -0
  1328. data/vendor/heroicons/24/solid/currency-yen.svg +3 -0
  1329. data/vendor/heroicons/24/solid/cursor-arrow-rays.svg +3 -0
  1330. data/vendor/heroicons/24/solid/cursor-arrow-ripple.svg +3 -0
  1331. data/vendor/heroicons/24/solid/device-phone-mobile.svg +4 -0
  1332. data/vendor/heroicons/24/solid/device-tablet.svg +4 -0
  1333. data/vendor/heroicons/24/solid/divide.svg +3 -0
  1334. data/vendor/heroicons/24/solid/document-arrow-down.svg +4 -0
  1335. data/vendor/heroicons/24/solid/document-arrow-up.svg +4 -0
  1336. data/vendor/heroicons/24/solid/document-chart-bar.svg +4 -0
  1337. data/vendor/heroicons/24/solid/document-check.svg +4 -0
  1338. data/vendor/heroicons/24/solid/document-currency-bangladeshi.svg +3 -0
  1339. data/vendor/heroicons/24/solid/document-currency-dollar.svg +3 -0
  1340. data/vendor/heroicons/24/solid/document-currency-euro.svg +4 -0
  1341. data/vendor/heroicons/24/solid/document-currency-pound.svg +3 -0
  1342. data/vendor/heroicons/24/solid/document-currency-rupee.svg +3 -0
  1343. data/vendor/heroicons/24/solid/document-currency-yen.svg +3 -0
  1344. data/vendor/heroicons/24/solid/document-duplicate.svg +4 -0
  1345. data/vendor/heroicons/24/solid/document-magnifying-glass.svg +5 -0
  1346. data/vendor/heroicons/24/solid/document-minus.svg +4 -0
  1347. data/vendor/heroicons/24/solid/document-plus.svg +4 -0
  1348. data/vendor/heroicons/24/solid/document-text.svg +4 -0
  1349. data/vendor/heroicons/24/solid/document.svg +4 -0
  1350. data/vendor/heroicons/24/solid/ellipsis-horizontal-circle.svg +3 -0
  1351. data/vendor/heroicons/24/solid/ellipsis-horizontal.svg +3 -0
  1352. data/vendor/heroicons/24/solid/ellipsis-vertical.svg +3 -0
  1353. data/vendor/heroicons/24/solid/envelope-open.svg +4 -0
  1354. data/vendor/heroicons/24/solid/envelope.svg +4 -0
  1355. data/vendor/heroicons/24/solid/equals.svg +3 -0
  1356. data/vendor/heroicons/24/solid/exclamation-circle.svg +3 -0
  1357. data/vendor/heroicons/24/solid/exclamation-triangle.svg +3 -0
  1358. data/vendor/heroicons/24/solid/eye-dropper.svg +3 -0
  1359. data/vendor/heroicons/24/solid/eye-slash.svg +5 -0
  1360. data/vendor/heroicons/24/solid/eye.svg +4 -0
  1361. data/vendor/heroicons/24/solid/face-frown.svg +3 -0
  1362. data/vendor/heroicons/24/solid/face-smile.svg +3 -0
  1363. data/vendor/heroicons/24/solid/film.svg +3 -0
  1364. data/vendor/heroicons/24/solid/finger-print.svg +3 -0
  1365. data/vendor/heroicons/24/solid/fire.svg +3 -0
  1366. data/vendor/heroicons/24/solid/flag.svg +3 -0
  1367. data/vendor/heroicons/24/solid/folder-arrow-down.svg +3 -0
  1368. data/vendor/heroicons/24/solid/folder-minus.svg +3 -0
  1369. data/vendor/heroicons/24/solid/folder-open.svg +3 -0
  1370. data/vendor/heroicons/24/solid/folder-plus.svg +3 -0
  1371. data/vendor/heroicons/24/solid/folder.svg +3 -0
  1372. data/vendor/heroicons/24/solid/forward.svg +3 -0
  1373. data/vendor/heroicons/24/solid/funnel.svg +3 -0
  1374. data/vendor/heroicons/24/solid/gif.svg +3 -0
  1375. data/vendor/heroicons/24/solid/gift-top.svg +4 -0
  1376. data/vendor/heroicons/24/solid/gift.svg +3 -0
  1377. data/vendor/heroicons/24/solid/globe-alt.svg +3 -0
  1378. data/vendor/heroicons/24/solid/globe-americas.svg +3 -0
  1379. data/vendor/heroicons/24/solid/globe-asia-australia.svg +4 -0
  1380. data/vendor/heroicons/24/solid/globe-europe-africa.svg +3 -0
  1381. data/vendor/heroicons/24/solid/h1.svg +3 -0
  1382. data/vendor/heroicons/24/solid/h2.svg +3 -0
  1383. data/vendor/heroicons/24/solid/h3.svg +3 -0
  1384. data/vendor/heroicons/24/solid/hand-raised.svg +3 -0
  1385. data/vendor/heroicons/24/solid/hand-thumb-down.svg +3 -0
  1386. data/vendor/heroicons/24/solid/hand-thumb-up.svg +3 -0
  1387. data/vendor/heroicons/24/solid/hashtag.svg +3 -0
  1388. data/vendor/heroicons/24/solid/heart.svg +3 -0
  1389. data/vendor/heroicons/24/solid/home-modern.svg +4 -0
  1390. data/vendor/heroicons/24/solid/home.svg +4 -0
  1391. data/vendor/heroicons/24/solid/identification.svg +3 -0
  1392. data/vendor/heroicons/24/solid/inbox-arrow-down.svg +4 -0
  1393. data/vendor/heroicons/24/solid/inbox-stack.svg +4 -0
  1394. data/vendor/heroicons/24/solid/inbox.svg +3 -0
  1395. data/vendor/heroicons/24/solid/information-circle.svg +3 -0
  1396. data/vendor/heroicons/24/solid/italic.svg +3 -0
  1397. data/vendor/heroicons/24/solid/key.svg +3 -0
  1398. data/vendor/heroicons/24/solid/language.svg +3 -0
  1399. data/vendor/heroicons/24/solid/lifebuoy.svg +3 -0
  1400. data/vendor/heroicons/24/solid/light-bulb.svg +4 -0
  1401. data/vendor/heroicons/24/solid/link-slash.svg +3 -0
  1402. data/vendor/heroicons/24/solid/link.svg +3 -0
  1403. data/vendor/heroicons/24/solid/list-bullet.svg +3 -0
  1404. data/vendor/heroicons/24/solid/lock-closed.svg +3 -0
  1405. data/vendor/heroicons/24/solid/lock-open.svg +3 -0
  1406. data/vendor/heroicons/24/solid/magnifying-glass-circle.svg +4 -0
  1407. data/vendor/heroicons/24/solid/magnifying-glass-minus.svg +3 -0
  1408. data/vendor/heroicons/24/solid/magnifying-glass-plus.svg +3 -0
  1409. data/vendor/heroicons/24/solid/magnifying-glass.svg +3 -0
  1410. data/vendor/heroicons/24/solid/map-pin.svg +3 -0
  1411. data/vendor/heroicons/24/solid/map.svg +3 -0
  1412. data/vendor/heroicons/24/solid/megaphone.svg +3 -0
  1413. data/vendor/heroicons/24/solid/microphone.svg +4 -0
  1414. data/vendor/heroicons/24/solid/minus-circle.svg +3 -0
  1415. data/vendor/heroicons/24/solid/minus-small.svg +3 -0
  1416. data/vendor/heroicons/24/solid/minus.svg +3 -0
  1417. data/vendor/heroicons/24/solid/moon.svg +3 -0
  1418. data/vendor/heroicons/24/solid/musical-note.svg +3 -0
  1419. data/vendor/heroicons/24/solid/newspaper.svg +4 -0
  1420. data/vendor/heroicons/24/solid/no-symbol.svg +3 -0
  1421. data/vendor/heroicons/24/solid/numbered-list.svg +3 -0
  1422. data/vendor/heroicons/24/solid/paint-brush.svg +3 -0
  1423. data/vendor/heroicons/24/solid/paper-airplane.svg +3 -0
  1424. data/vendor/heroicons/24/solid/paper-clip.svg +3 -0
  1425. data/vendor/heroicons/24/solid/pause-circle.svg +3 -0
  1426. data/vendor/heroicons/24/solid/pause.svg +3 -0
  1427. data/vendor/heroicons/24/solid/pencil-square.svg +4 -0
  1428. data/vendor/heroicons/24/solid/pencil.svg +3 -0
  1429. data/vendor/heroicons/24/solid/percent-badge.svg +3 -0
  1430. data/vendor/heroicons/24/solid/phone-arrow-down-left.svg +4 -0
  1431. data/vendor/heroicons/24/solid/phone-arrow-up-right.svg +4 -0
  1432. data/vendor/heroicons/24/solid/phone-x-mark.svg +3 -0
  1433. data/vendor/heroicons/24/solid/phone.svg +3 -0
  1434. data/vendor/heroicons/24/solid/photo.svg +3 -0
  1435. data/vendor/heroicons/24/solid/play-circle.svg +3 -0
  1436. data/vendor/heroicons/24/solid/play-pause.svg +3 -0
  1437. data/vendor/heroicons/24/solid/play.svg +3 -0
  1438. data/vendor/heroicons/24/solid/plus-circle.svg +3 -0
  1439. data/vendor/heroicons/24/solid/plus-small.svg +3 -0
  1440. data/vendor/heroicons/24/solid/plus.svg +3 -0
  1441. data/vendor/heroicons/24/solid/power.svg +3 -0
  1442. data/vendor/heroicons/24/solid/presentation-chart-bar.svg +3 -0
  1443. data/vendor/heroicons/24/solid/presentation-chart-line.svg +3 -0
  1444. data/vendor/heroicons/24/solid/printer.svg +3 -0
  1445. data/vendor/heroicons/24/solid/puzzle-piece.svg +3 -0
  1446. data/vendor/heroicons/24/solid/qr-code.svg +3 -0
  1447. data/vendor/heroicons/24/solid/question-mark-circle.svg +3 -0
  1448. data/vendor/heroicons/24/solid/queue-list.svg +3 -0
  1449. data/vendor/heroicons/24/solid/radio.svg +3 -0
  1450. data/vendor/heroicons/24/solid/receipt-percent.svg +3 -0
  1451. data/vendor/heroicons/24/solid/receipt-refund.svg +3 -0
  1452. data/vendor/heroicons/24/solid/rectangle-group.svg +3 -0
  1453. data/vendor/heroicons/24/solid/rectangle-stack.svg +3 -0
  1454. data/vendor/heroicons/24/solid/rocket-launch.svg +4 -0
  1455. data/vendor/heroicons/24/solid/rss.svg +3 -0
  1456. data/vendor/heroicons/24/solid/scale.svg +3 -0
  1457. data/vendor/heroicons/24/solid/scissors.svg +4 -0
  1458. data/vendor/heroicons/24/solid/server-stack.svg +4 -0
  1459. data/vendor/heroicons/24/solid/server.svg +4 -0
  1460. data/vendor/heroicons/24/solid/share.svg +3 -0
  1461. data/vendor/heroicons/24/solid/shield-check.svg +3 -0
  1462. data/vendor/heroicons/24/solid/shield-exclamation.svg +3 -0
  1463. data/vendor/heroicons/24/solid/shopping-bag.svg +3 -0
  1464. data/vendor/heroicons/24/solid/shopping-cart.svg +3 -0
  1465. data/vendor/heroicons/24/solid/signal-slash.svg +3 -0
  1466. data/vendor/heroicons/24/solid/signal.svg +3 -0
  1467. data/vendor/heroicons/24/solid/slash.svg +3 -0
  1468. data/vendor/heroicons/24/solid/sparkles.svg +3 -0
  1469. data/vendor/heroicons/24/solid/speaker-wave.svg +4 -0
  1470. data/vendor/heroicons/24/solid/speaker-x-mark.svg +3 -0
  1471. data/vendor/heroicons/24/solid/square-2-stack.svg +4 -0
  1472. data/vendor/heroicons/24/solid/square-3-stack-3d.svg +5 -0
  1473. data/vendor/heroicons/24/solid/squares-2x2.svg +3 -0
  1474. data/vendor/heroicons/24/solid/squares-plus.svg +3 -0
  1475. data/vendor/heroicons/24/solid/star.svg +3 -0
  1476. data/vendor/heroicons/24/solid/stop-circle.svg +3 -0
  1477. data/vendor/heroicons/24/solid/stop.svg +3 -0
  1478. data/vendor/heroicons/24/solid/strikethrough.svg +3 -0
  1479. data/vendor/heroicons/24/solid/sun.svg +3 -0
  1480. data/vendor/heroicons/24/solid/swatch.svg +4 -0
  1481. data/vendor/heroicons/24/solid/table-cells.svg +3 -0
  1482. data/vendor/heroicons/24/solid/tag.svg +3 -0
  1483. data/vendor/heroicons/24/solid/ticket.svg +3 -0
  1484. data/vendor/heroicons/24/solid/trash.svg +3 -0
  1485. data/vendor/heroicons/24/solid/trophy.svg +3 -0
  1486. data/vendor/heroicons/24/solid/truck.svg +5 -0
  1487. data/vendor/heroicons/24/solid/tv.svg +4 -0
  1488. data/vendor/heroicons/24/solid/underline.svg +3 -0
  1489. data/vendor/heroicons/24/solid/user-circle.svg +3 -0
  1490. data/vendor/heroicons/24/solid/user-group.svg +4 -0
  1491. data/vendor/heroicons/24/solid/user-minus.svg +3 -0
  1492. data/vendor/heroicons/24/solid/user-plus.svg +3 -0
  1493. data/vendor/heroicons/24/solid/user.svg +3 -0
  1494. data/vendor/heroicons/24/solid/users.svg +3 -0
  1495. data/vendor/heroicons/24/solid/variable.svg +3 -0
  1496. data/vendor/heroicons/24/solid/video-camera-slash.svg +3 -0
  1497. data/vendor/heroicons/24/solid/video-camera.svg +3 -0
  1498. data/vendor/heroicons/24/solid/view-columns.svg +3 -0
  1499. data/vendor/heroicons/24/solid/viewfinder-circle.svg +3 -0
  1500. data/vendor/heroicons/24/solid/wallet.svg +3 -0
  1501. data/vendor/heroicons/24/solid/wifi.svg +3 -0
  1502. data/vendor/heroicons/24/solid/window.svg +3 -0
  1503. data/vendor/heroicons/24/solid/wrench-screwdriver.svg +5 -0
  1504. data/vendor/heroicons/24/solid/wrench.svg +3 -0
  1505. data/vendor/heroicons/24/solid/x-circle.svg +3 -0
  1506. data/vendor/heroicons/24/solid/x-mark.svg +3 -0
  1507. data/vendor/heroicons/LICENSE +21 -0
  1508. data/vendor/heroicons/VERSION +5 -0
  1509. metadata +1664 -0
@@ -0,0 +1,952 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'set'
4
+
5
+ require_relative 'site_loader'
6
+ require_relative 'renderer'
7
+ require_relative 'artifact_writer'
8
+
9
+ module Abqari
10
+ # Site is the public façade and orchestrator. The heavy lifting lives
11
+ # in three collaborators:
12
+ #
13
+ # - SiteLoader : config + pages + data ingestion, nav/footer cascade
14
+ # - Renderer : page generators, parallel render, post-process,
15
+ # template cache, shared-deps mtime
16
+ # - ArtifactWriter: output dir reset, public/ + fonts + d3 copying,
17
+ # sitemap/feed/robots/etc.
18
+ #
19
+ # Site retains all read-mostly query helpers (collections, taxonomies,
20
+ # related, featured, posts_by_term, …) and the lookup accessors used
21
+ # from RenderContext and partials (assets, images, visualizations,
22
+ # folio, data, nav_links, footer_links, social_links). The split is
23
+ # internal — the public API is unchanged.
24
+ class Site
25
+ # Built-in collections. `bundles` and `series` are first-class meta-
26
+ # collections — they group `publications` (or anything else the
27
+ # consuming site decides to bundle) into retailable sets. They work
28
+ # standalone (manual content at `content/bundles/<slug>/` and
29
+ # `content/series/<slug>/`) and Folio populates them automatically
30
+ # when configured — same collection name, same layout, same URL
31
+ # pattern either way.
32
+ DEFAULT_COLLECTIONS = {
33
+ 'posts' => {
34
+ 'source' => 'content/posts',
35
+ 'permalink' => '/posts/:slug/',
36
+ 'layout' => 'post'
37
+ },
38
+ 'photos' => {
39
+ 'source' => 'content/photos',
40
+ 'permalink' => '/photos/:slug/',
41
+ 'layout' => 'photo'
42
+ },
43
+ 'publications' => {
44
+ 'source' => 'content/publications',
45
+ 'permalink' => '/publications/:slug/',
46
+ 'layout' => 'publication',
47
+ 'bundle' => true
48
+ },
49
+ 'bundles' => {
50
+ 'source' => 'content/bundles',
51
+ 'permalink' => '/bundles/:slug/',
52
+ 'layout' => 'bundle',
53
+ 'bundle' => true
54
+ },
55
+ 'series' => {
56
+ 'source' => 'content/series',
57
+ 'permalink' => '/series/:slug/',
58
+ 'layout' => 'series',
59
+ 'bundle' => true
60
+ },
61
+ 'workshops' => {
62
+ 'source' => 'content/workshops',
63
+ 'permalink' => '/workshops/:slug/',
64
+ 'layout' => 'workshop',
65
+ 'bundle' => true
66
+ }
67
+ }.freeze
68
+
69
+ DEFAULT_TAXONOMIES = {
70
+ 'tags' => {
71
+ 'permalink' => '/tags/:slug/',
72
+ 'layout' => 'tag'
73
+ }
74
+ }.freeze
75
+
76
+ attr_reader :config, :pages, :generated_pages, :env, :loader, :renderer, :artifacts
77
+
78
+ def initialize
79
+ @env = (ENV['ABQARI_ENV'] || 'development').to_sym
80
+ @loader = SiteLoader.new(self)
81
+ raw = @loader.load_config
82
+ SiteConfig.validate!(raw, env: @env)
83
+ # Fold static defaults under the user's config so call sites can
84
+ # do `config['indexable']` instead of `config.fetch(..., true)`.
85
+ # Dynamic defaults (minify, env-based) stay in their callers.
86
+ @config = SiteConfig.with_defaults(raw)
87
+ @pages = []
88
+ @generated_pages = []
89
+ # Contribute phase is open until Renderer#generate_all closes it.
90
+ @collections_final = false
91
+ # Per-build memo registry. All `||=` caches on Site route
92
+ # through `memo(key) { … }` so a rebuild only has to clear one
93
+ # hash; adding a new memo can never go out of sync with the
94
+ # rebuild-reset code. See `reset_state_for_rebuild!`.
95
+ @memos = {}
96
+ @memo_mutex = Mutex.new
97
+ @renderer = Renderer.new(self)
98
+ @artifacts = ArtifactWriter.new(self)
99
+
100
+ # Load site-local plugins (plugins/**/*.rb). Plugins register
101
+ # themselves with `Abqari::Hooks.register(...)` at top level —
102
+ # the registrations land in the global hook table and fire on
103
+ # subsequent `Hooks.run` / `run_filter` calls during build.
104
+ PluginLoader.load_from(site_root)
105
+ end
106
+
107
+ # ------------------------------------------------------------------
108
+ # Orchestration
109
+ # ------------------------------------------------------------------
110
+
111
+ # build(incremental: false) wipes _site/ and rebuilds everything (default).
112
+ # build(incremental: true) preserves _site/ and uses mtime-aware copying
113
+ # so unchanged files are skipped — used by the dev-server watcher.
114
+ #
115
+ # `apply_timezone!` mutates `ENV['TZ']` so naked dates parse against
116
+ # one consistent zone regardless of where the build runs. That's a
117
+ # process-wide side effect, so we save the prior value and restore
118
+ # it in `ensure` — host processes (test harnesses, dev-server
119
+ # watchers calling `build` repeatedly, applications embedding the
120
+ # gem) get TZ back at the value they had before the build, not
121
+ # `'UTC'` (or whatever the site configured).
122
+ # `side_effects: false` skips the outbound network steps (POSSE
123
+ # syndication, webmention sending). `bin/audit` builds in production
124
+ # to exercise the real CSP/minify/fingerprint paths, but it must not
125
+ # broadcast the posts it's auditing — an audit is a dry run, not a
126
+ # publish.
127
+ def build(incremental: false, side_effects: true)
128
+ @incremental = incremental
129
+ prev_tz = ENV['TZ']
130
+ apply_timezone!
131
+
132
+ Hooks.run(:before_build, self)
133
+
134
+ # Theme config is validated before ANY filesystem effect — a
135
+ # typo'd or traversal-shaped `theme:` must abort here, not after
136
+ # the output dir is wiped or mid-render with per-page errors.
137
+ assets.validate_theme!
138
+
139
+ @artifacts.reset_output unless incremental
140
+ reset_state_for_rebuild!
141
+
142
+ @pages = @loader.load_pages
143
+ Hooks.run(:after_load_pages, self)
144
+
145
+ Folio.new(self).fetch # publications + bundles, derives series
146
+ Indieweb::Fetcher.new(self).fetch # webmentions (received via webmention.io)
147
+ @renderer.generate_all # tag pages, paginated shards, viz, folio, related
148
+ Hooks.run(:after_generate, self)
149
+
150
+ assets.process
151
+ images.process
152
+
153
+ @artifacts.copy_fonts
154
+ @artifacts.copy_d3
155
+ @renderer.render_pages
156
+ BundleAssets.new(self).copy
157
+ @artifacts.copy_public
158
+ @artifacts.write_deploy_artifacts
159
+ visualizations.write_data
160
+ Search.new(self).run
161
+ if side_effects
162
+ Indieweb::Sender.new(self).send_all # POST webmentions for new outbound links (opt-in)
163
+ Syndication::Dispatcher.new(self).run # POSSE: crosspost to Mastodon/Bluesky (opt-in)
164
+ end
165
+
166
+ # Build-complete sentinel (`Abqari::BUILD_OK_SENTINEL`). Written
167
+ # ONLY on the success path — if any step above raises, this line
168
+ # never runs and the file stays absent. Deployers (bin/deploy,
169
+ # CI pipelines that rsync/scp _site/) check for it before
170
+ # publishing so a half-built _site/ from a crashed build can't
171
+ # accidentally ship over a working site. Includes the build
172
+ # timestamp + the gem version so a stale sentinel (older than
173
+ # the source files under content/) is detectable.
174
+ File.write(
175
+ File.join(output_dir, Abqari::BUILD_OK_SENTINEL),
176
+ "version: #{Abqari::VERSION}\nbuilt_at: #{Time.now.utc.iso8601}\n"
177
+ )
178
+
179
+ Log.info "Built #{all_pages.size} page(s) in #{env}#{incremental ? ' (incremental)' : ''} → _site/"
180
+ ensure
181
+ Hooks.run(:after_build, self) if defined?(@incremental)
182
+ ENV['TZ'] = prev_tz
183
+ end
184
+
185
+ def incremental?
186
+ @incremental == true
187
+ end
188
+
189
+ # Internal — collaborators only. Generators push into the list with
190
+ # `site.add_generated_page(page)` so the public API stays read-only.
191
+ #
192
+ # Adding a page invalidates the per-collection caches because
193
+ # generated pages that implement `#collection` (PublisherShowPage
194
+ # in particular) join their collection — a memoised
195
+ # `collection(name)` result from before this add is now stale.
196
+ # The pagination / related generators call `site.collection`
197
+ # mid-`generate_all`, so invalidating at every add keeps the memo
198
+ # honest without requiring careful generator-ordering.
199
+ def add_generated_page(page)
200
+ assert_collection_open!(page)
201
+
202
+ @generated_pages << page
203
+ @memos.delete(:collection_cache)
204
+ @memos.delete(:collection_url_index_cache)
205
+ @memos.delete(:posts) if page.respond_to?(:post?) && page.post?
206
+ end
207
+
208
+ # Close the contribute phase. Called by `Renderer#generate_all` once
209
+ # every generator that can add pages to a collection has run; from
210
+ # here on, collections are what the deriving generators (pagination,
211
+ # taxonomies, related indexes) will see.
212
+ def finalise_collections!
213
+ @collections_final = true
214
+ end
215
+
216
+ def collections_final?
217
+ @collections_final == true
218
+ end
219
+
220
+ # Raise if a page tries to join a collection after the barrier.
221
+ #
222
+ # Pagination reads a collection and freezes the slices into
223
+ # `Paginator` objects; anything added afterwards is silently missing
224
+ # from the archive and every shard. That's the worst shape of bug
225
+ # this codebase can produce — output that is quietly incomplete, with
226
+ # a green build and nothing to investigate. Better a loud failure at
227
+ # the moment the ordering is violated, naming the page.
228
+ #
229
+ # Only collection-joining pages are refused. Taxonomy pages,
230
+ # paginated shards, visualizations and related indexes are all
231
+ # produced BY the derive phase and belong to no collection, so they
232
+ # add freely.
233
+ def assert_collection_open!(page)
234
+ return unless collections_final?
235
+ return unless page.respond_to?(:collection) && page.collection
236
+
237
+ raise <<~MSG
238
+ #{page.class} joins the '#{page.collection}' collection but was added after
239
+ collections were finalised (url: #{page.respond_to?(:url) ? page.url : '?'}).
240
+
241
+ Pages that join a collection must be generated in the contribute
242
+ phase of Renderer#generate_all, before Site#finalise_collections!.
243
+ Adding one later means pagination has already sliced the
244
+ collection without it, so it would be missing from the archive
245
+ and its shards with no other symptom.
246
+ MSG
247
+ end
248
+
249
+ # ------------------------------------------------------------------
250
+ # Path resolution — two roots.
251
+ #
252
+ # `engine_root` is the abqari gem's location. Where the structural
253
+ # assets live: `_common.css`, layouts/partials, built-in themes,
254
+ # built-in icons, vendored 3rd-party assets (heroicons, d3).
255
+ #
256
+ # `site_root` is the consuming site's location. Where the site-
257
+ # specific stuff lives: `config/site.yml`, `content/`, `data/`,
258
+ # `vendor/folio/`, `public/`, `_site/` (the build output), `audit/`.
259
+ # ------------------------------------------------------------------
260
+
261
+ def engine_root
262
+ Abqari::ROOT
263
+ end
264
+
265
+ def site_root
266
+ @site_root ||= ENV['ABQARI_SITE_ROOT'] || Dir.pwd
267
+ end
268
+
269
+ # Resolve a relative path with site-first, engine-fallback semantics.
270
+ # Returns the site path if a file/dir exists there, otherwise returns
271
+ # the engine path (which may itself not exist — caller checks).
272
+ def find_in_paths(rel)
273
+ site_path = File.join(site_root, rel)
274
+ return site_path if File.exist?(site_path)
275
+
276
+ File.join(engine_root, rel)
277
+ end
278
+
279
+ # Absolute, always. `Page#url` derives every internal URL by
280
+ # stripping this prefix off the page's output path, and the output
281
+ # path is absolute — so a relative `ABQARI_OUTPUT_DIR=_site` used to
282
+ # strip nothing and leave the developer's full filesystem path
283
+ # embedded in every href, `<loc>` and feed link:
284
+ #
285
+ # <loc>https://example.com/Users/me/dev/mysite//about/</loc>
286
+ #
287
+ # Files still landed in the right place, so the build reported
288
+ # success and shipped a sitemap advertising local paths to the world.
289
+ # A trailing slash was the mirror-image bug: it consumed the leading
290
+ # `/` and produced scheme-relative URLs. `expand_path` normalises
291
+ # both, and matches what `ArtifactWriter#reset_output` already does
292
+ # before it deletes anything — the two had drifted, which is how a
293
+ # value safe enough to delete under could still corrupt every URL.
294
+ def output_dir
295
+ raw = ENV['ABQARI_OUTPUT_DIR']
296
+ return File.join(site_root, '_site') if raw.nil? || raw.strip.empty?
297
+
298
+ File.expand_path(raw, site_root)
299
+ end
300
+
301
+ # ------------------------------------------------------------------
302
+ # Collections
303
+ # ------------------------------------------------------------------
304
+
305
+ # Merged config for a single collection.
306
+ #
307
+ # Defaults come from DEFAULT_COLLECTIONS. User overrides under
308
+ # `collections.<name>:` win.
309
+ #
310
+ # Slug aliasing: when the user sets `slug:` on a built-in collection,
311
+ # the URL permalink and layout name derive from it. The source
312
+ # directory always stays canonical so the on-disk content layout is
313
+ # consistent across sites — only public-facing URLs and the layout
314
+ # name change.
315
+ def collection_config(name)
316
+ defaults = DEFAULT_COLLECTIONS[name] || {}
317
+ override = (config['collections'] || {})[name] || {}
318
+
319
+ slug = override['slug'].to_s
320
+ if !slug.empty?
321
+ derived = {
322
+ 'permalink' => "/#{slug}/:slug/",
323
+ 'layout' => singularize_slug(slug)
324
+ }
325
+ defaults.merge(derived).merge(override)
326
+ else
327
+ defaults.merge(override)
328
+ end
329
+ end
330
+
331
+ # Naive singularizer for deriving a layout name from a plural slug.
332
+ # Handles the cases collection slugs actually take:
333
+ # stories → story (ies → y)
334
+ # books → book (s → '')
335
+ # photos → photo (s → '')
336
+ # publications → publication
337
+ #
338
+ # English exceptions — words that look plural but aren't, or whose
339
+ # singular form matches a different rule. Without the allow-list:
340
+ # news → new (wrong)
341
+ # series → serie (wrong; the singular is also "series")
342
+ # lens → len (wrong)
343
+ # Words ending in `ss` (boss, press) also stay as-is — covered by
344
+ # the explicit guard so adding new exceptions only requires one
345
+ # place to edit.
346
+ #
347
+ # The narrow scope is deliberate: collection slugs are usually
348
+ # short English nouns, not arbitrary text. If a consuming site
349
+ # picks a slug that doesn't singularize cleanly here, the docs
350
+ # recommend setting `layout:` explicitly in the collection config.
351
+ INVARIANT_SLUGS = %w[news series lens species means physics analytics].freeze
352
+
353
+ def singularize_slug(word)
354
+ return word if INVARIANT_SLUGS.include?(word)
355
+ return word if word.end_with?('ss')
356
+
357
+ word.sub(/ies$/, 'y').sub(/s$/, '')
358
+ end
359
+
360
+ # Resolve a name to its canonical collection name. Accepts the
361
+ # canonical key ('posts') or the user-configured slug ('stories'
362
+ # when posts has slug: stories) and returns the canonical key.
363
+ def resolve_collection_name(name)
364
+ collections.each do |canonical, cfg|
365
+ return canonical if cfg['slug'].to_s == name.to_s
366
+ end
367
+ name.to_s
368
+ end
369
+
370
+ # All collections — built-ins plus any user-defined ones from
371
+ # `collections:` in config/site.yml. Returns name => merged-config
372
+ # hash. Page#collection iterates this to find which collection a
373
+ # source file belongs to.
374
+ def collections
375
+ result = {}
376
+ DEFAULT_COLLECTIONS.each_key { |name| result[name] = collection_config(name) }
377
+ (config['collections'] || {}).each_key { |name| result[name] ||= collection_config(name) }
378
+ result
379
+ end
380
+
381
+ # Extensions published out of a bundle directory: the built-in
382
+ # allow-list (`Page::Bundle::PUBLISHABLE_EXTENSIONS`) plus anything
383
+ # the site adds via
384
+ #
385
+ # bundle_assets:
386
+ # extensions: [.gpx, .stl]
387
+ #
388
+ # Additive rather than replacing, so a site that wants one extra
389
+ # download type doesn't have to restate the media defaults (and
390
+ # silently lose an image format when the defaults grow). Entries are
391
+ # normalised to lower-case and dot-prefixed, so `GPX`, `.gpx` and
392
+ # `gpx` all work.
393
+ def bundle_asset_extensions
394
+ memo(:bundle_asset_extensions) do
395
+ extra = Array((config['bundle_assets'] || {})['extensions'])
396
+ .map { |e| e.to_s.strip.downcase }
397
+ .reject(&:empty?)
398
+ .map { |e| e.start_with?('.') ? e : ".#{e}" }
399
+
400
+ # Markdown can't be opted back in. It's content, and publishing
401
+ # it as an asset is precisely the bug this allow-list closes —
402
+ # a `published: false` sibling shipped verbatim to production.
403
+ content, allowed = extra.partition { |e| Page::Bundle::CONTENT_EXTENSIONS.include?(e) }
404
+ unless content.empty?
405
+ Log.warn "Ignoring #{content.join(', ')} in `bundle_assets.extensions:` — " \
406
+ 'markdown is content, not an asset, and publishing it would expose ' \
407
+ 'files marked `published: false`. Move the file out of the bundle if ' \
408
+ 'you want it published.'
409
+ end
410
+
411
+ (Page::Bundle::PUBLISHABLE_EXTENSIONS + allowed).to_set
412
+ end
413
+ end
414
+
415
+ # Resolve a page like `content/photos/index.md` to the collection
416
+ # name (`photos`) it acts as the index for. Returns nil for pages
417
+ # that aren't a collection index. Bundle-style collections like
418
+ # `posts` and `photos` exclude their own index.md from
419
+ # Page#collection, so this helper closes the gap for callers that
420
+ # need "what collection does this index page represent?".
421
+ def collection_index_name(page)
422
+ # Generated pages (PublisherShowPage, RelatedIndexPage, paginated
423
+ # shards, etc.) don't have a real source_path — return nil.
424
+ return nil unless page.respond_to?(:source_path) && page.source_path
425
+ return nil unless File.basename(page.source_path) == 'index.md'
426
+
427
+ collections.each do |name, cfg|
428
+ source = File.join(site_root, cfg['source'])
429
+ return name if page.source_path == File.join(source, 'index.md')
430
+ end
431
+ nil
432
+ end
433
+
434
+ # Pages in a named collection, sorted newest-first by date when
435
+ # present. Accepts either the canonical collection name or its
436
+ # slug alias — both return the same pages.
437
+ #
438
+ # Memoised per-canonical-name. Templates that render a collection
439
+ # listing call this repeatedly across a build; the underlying
440
+ # `@pages.select` is O(N), so without memoisation each render is
441
+ # O(N) work × number of partial calls. Reset on `reset_state_for_rebuild!`.
442
+ def collection(name)
443
+ canonical = resolve_collection_name(name)
444
+ cache = memo(:collection_cache) { {} }
445
+ cache[canonical] ||= begin
446
+ # Manual content pages (Page objects) AND generated pages that
447
+ # opt in by exposing `#collection` returning the canonical
448
+ # name. PublisherShowPage is the primary example —
449
+ # externally-sourced publications, bundles, and series join
450
+ # their respective collections so templates iterate one
451
+ # merged list.
452
+ manual = @pages.select { |p| p.collection == canonical }
453
+ generated = @generated_pages.select do |p|
454
+ p.respond_to?(:collection) && p.collection == canonical
455
+ end
456
+ # Manual wins on slug collision — an override page at
457
+ # `content/publications/<slug>/index.md` suppresses the
458
+ # auto-generated externally-sourced entry for the same slug.
459
+ manual_slugs = manual.map { |p| p.respond_to?(:slug) ? p.slug : nil }.compact.to_set
460
+ generated.reject! { |p| p.respond_to?(:slug) && manual_slugs.include?(p.slug) }
461
+
462
+ pages_in = manual + generated
463
+ if pages_in.any? { |p| p.respond_to?(:date) && p.date }
464
+ pages_in.sort_by { |p| (p.respond_to?(:date) && p.date) || Time.at(0) }.reverse
465
+ else
466
+ pages_in.sort_by { |p| p.title.to_s }
467
+ end
468
+ end
469
+ end
470
+
471
+ # url → index hash for `collection(name)`. Built once on first
472
+ # access per collection and cached. Lets `next_in_collection` and
473
+ # `related` answer "which slot is this page in?" in O(1) instead
474
+ # of O(N) — and since both are called once per show-view render,
475
+ # the total cost across a build is O(pages) instead of O(pages²).
476
+ def collection_url_index(name)
477
+ canonical = resolve_collection_name(name)
478
+ cache = memo(:collection_url_index_cache) { {} }
479
+ cache[canonical] ||= begin
480
+ index = {}
481
+ collection(canonical).each_with_index { |page, i| index[page.url] = i }
482
+ index
483
+ end
484
+ end
485
+
486
+ # Featured-item lookup. `site.featured('publications', 'the-field-guide')`
487
+ # returns the matching page or nil — useful for "show this one item
488
+ # prominently on the home page" patterns.
489
+ def featured(collection_name, slug)
490
+ return nil unless slug && !slug.to_s.empty?
491
+
492
+ collection(collection_name).find do |p|
493
+ p.slug == slug.to_s ||
494
+ p.url.split('/').reject(&:empty?).last == slug.to_s
495
+ end
496
+ end
497
+
498
+ # Related pages — candidates from the same collection, scored by
499
+ # how many tags / series / countries / etc. they share with the
500
+ # source page. By default returns ALL matches with positive
501
+ # overlap, ranked highest-score first.
502
+ #
503
+ # site.related(page) # full ranked list
504
+ # site.related(page, limit: 3) # top 3
505
+ # site.related(page, match_by: %w[tags series])
506
+ def related(page, limit: nil, match_by: nil)
507
+ return [] unless page.respond_to?(:collection) && page.collection
508
+
509
+ cfg = collection_config(page.collection).dig('show', 'related') || {}
510
+ return [] if cfg['enabled'] == false
511
+
512
+ effective_match_by = Array(match_by || cfg.fetch('match_by', 'tags'))
513
+
514
+ # Use the url-index lookup to skip the source page in O(1); the
515
+ # earlier `.reject { |p| p.url == page.url }` did an O(N) scan
516
+ # per page rendered, which the related-list call sites repeat
517
+ # across the whole collection.
518
+ idx_map = collection_url_index(page.collection)
519
+ pages_in = collection(page.collection)
520
+ source_idx = idx_map[page.url]
521
+ candidates = source_idx ? pages_in.reject.with_index { |_, i| i == source_idx } : pages_in
522
+
523
+ # Earlier fields in match_by weight more — count them with a
524
+ # multiplier so "matches series first, then country" comes out
525
+ # as expected even when both share with the source.
526
+ scored = candidates.map do |candidate|
527
+ score = effective_match_by.each_with_index.sum do |field, idx|
528
+ weight = effective_match_by.size - idx
529
+ shared_term_count(page.frontmatter[field], candidate.frontmatter[field]) * weight
530
+ end
531
+ [score, candidate]
532
+ end
533
+
534
+ sorted = scored.select { |score, _| score.positive? }
535
+ .sort_by { |score, candidate| [-score, -(candidate.respond_to?(:date) && candidate.date ? candidate.date.to_i : 0)] }
536
+ .map(&:last)
537
+
538
+ limit ? sorted.first(limit) : sorted
539
+ end
540
+
541
+ # The "next" page in a dated collection's chronological order. "Next"
542
+ # means strictly newer — the post that came after this one in time.
543
+ # Returns nil when the source is the newest in the collection, isn't
544
+ # in the collection, or `next.enabled` is false.
545
+ def next_in_collection(page)
546
+ return nil unless page.respond_to?(:collection) && page.collection
547
+
548
+ cfg = collection_config(page.collection).dig('show', 'next') || {}
549
+ return nil if cfg['enabled'] == false
550
+
551
+ pages = collection(page.collection) # newest first
552
+ idx = collection_url_index(page.collection)[page.url]
553
+ return nil unless idx
554
+
555
+ # Newer neighbour sits at the smaller index. When idx is 0 we're
556
+ # already at the newest — render nothing.
557
+ idx.positive? ? pages[idx - 1] : nil
558
+ end
559
+
560
+ # The "next" page within the same series — the page with the
561
+ # smallest `series_position` strictly greater than this page's.
562
+ # Requires the page to have BOTH `series:` and `series_position:`
563
+ # in frontmatter, and to belong to a collection (so the series is
564
+ # scoped consistently with the per-collection series taxonomies).
565
+ #
566
+ # Returns nil when:
567
+ # - The page isn't in a series (no `series:` frontmatter).
568
+ # - The page has no `series_position:` (can't order it).
569
+ # - The page is the last position in the series.
570
+ # - The page is outside a collection.
571
+ #
572
+ # Used by the post show view to render a "Next in the series" card
573
+ # in place of the chronological "Up next" card when a series
574
+ # relationship exists. Generic across collections — works for
575
+ # posts, photos, publications, workshops alike.
576
+ def next_in_series(page)
577
+ series_sibling(page, :forward)
578
+ end
579
+
580
+ # The "previous" page within the same series — the page with the
581
+ # largest `series_position` strictly less than this page's. Exact
582
+ # mirror of `next_in_series`: same guards, same nil semantics, same
583
+ # per-collection scoping.
584
+ #
585
+ # Exists because course-shaped collections (a module of ordered
586
+ # lessons) need to navigate backwards as well as forwards. The
587
+ # `_series_pager` partial pairs the two into one prev/next nav;
588
+ # `_next_in_series` remains the forward-only card.
589
+ def prev_in_series(page)
590
+ series_sibling(page, :back)
591
+ end
592
+
593
+ # Shared-term count between two frontmatter values. Both can be
594
+ # scalars (`country: Syria`) or arrays (`tags: [a, b]`); we use
595
+ # `Array()` to normalise. Returns 0 when either side is missing.
596
+ def shared_term_count(a, b)
597
+ return 0 if a.nil? || b.nil?
598
+
599
+ a_set = Array(a).map(&:to_s).to_set
600
+ b_set = Array(b).map(&:to_s).to_set
601
+ (a_set & b_set).size
602
+ end
603
+
604
+ # ------------------------------------------------------------------
605
+ # Taxonomies
606
+ # ------------------------------------------------------------------
607
+
608
+ # User config and defaults are merged so the built-in `tags`
609
+ # taxonomy stays available even when the user defines their own.
610
+ def taxonomies
611
+ user = config['taxonomies'] || {}
612
+ DEFAULT_TAXONOMIES.merge(user)
613
+ end
614
+
615
+ def taxonomy_config(name)
616
+ defaults = DEFAULT_TAXONOMIES[name] || {}
617
+ override = taxonomies[name] || {}
618
+ defaults.merge(override)
619
+ end
620
+
621
+ # Which taxonomy owns the series index for `collection_name` — the
622
+ # first taxonomy whose `field:` is `series` and whose `collection:`
623
+ # scope matches. Returns the taxonomy name (e.g. `'posts_series'`)
624
+ # or nil when the collection has no series taxonomy configured.
625
+ #
626
+ # Layouts must not hardcode `'posts_series'`: the `post` layout is
627
+ # deliberately reusable (cookbook, glossary, lessons), and every
628
+ # collection that reuses it has its own `<collection>_series`
629
+ # taxonomy. A hardcoded name sends every series breadcrumb in every
630
+ # reusing collection to the posts series index instead of its own.
631
+ def series_taxonomy_for(collection_name)
632
+ return nil if collection_name.to_s.empty?
633
+
634
+ memo("series_taxonomy_#{collection_name}") do
635
+ taxonomies.find do |_name, cfg|
636
+ cfg['field'].to_s == 'series' &&
637
+ cfg['collection'].to_s == collection_name.to_s
638
+ end&.first
639
+ end
640
+ end
641
+
642
+ # Index dated pages by taxonomy term. Reads `frontmatter[field]`
643
+ # where `field` defaults to the taxonomy name (overridable via
644
+ # `field:` in config).
645
+ #
646
+ # When the taxonomy config sets `collection: <name>`, the
647
+ # aggregation is scoped to that collection — items in other
648
+ # collections with the same field value don't appear. Used by the
649
+ # per-collection series taxonomies (`posts_series`, `photos_series`,
650
+ # …) so a photo with `series: "Notes 2026"` and a post with
651
+ # `series: "Notes 2026"` are independent series, not a shared one.
652
+ #
653
+ # No `collection:` in the config → cross-collection aggregation,
654
+ # the historical behaviour. The default `tags` taxonomy keeps this
655
+ # so a post and a photo both tagged `travel` land on /tags/travel/
656
+ # together.
657
+ def posts_by_term(taxonomy)
658
+ cfg = taxonomy_config(taxonomy)
659
+ field = cfg['field'] || taxonomy
660
+ scope = cfg['collection']
661
+
662
+ result = Hash.new { |h, k| h[k] = [] }
663
+ taxonomy_pages.each do |page|
664
+ next if scope && page.collection != scope
665
+
666
+ Array(page.frontmatter[field]).each { |term| result[term] << page }
667
+ end
668
+ result
669
+ end
670
+
671
+ # Pages that taxonomies index — every page in every collection.
672
+ # Sorted newest-first; pages without a `date` (workshops have
673
+ # `date_from`, not `date`; some collections may opt out of dating
674
+ # entirely) sort to the end as Time.at(0). Memoised — same shape
675
+ # as `posts`, called from every taxonomy partial.
676
+ def taxonomy_pages
677
+ memo(:taxonomy_pages) do
678
+ @pages.select(&:collection)
679
+ .sort_by { |p| p.date || Time.at(0) }
680
+ .reverse
681
+ end
682
+ end
683
+
684
+ # ------------------------------------------------------------------
685
+ # Page accessors
686
+ # ------------------------------------------------------------------
687
+
688
+ def all_pages
689
+ @pages + @generated_pages
690
+ end
691
+
692
+ # Memoised — `posts` is read by the posts index, every per-post
693
+ # `next_in_collection`, the feed, the sitemap, the home page's
694
+ # latest-post module, and several JSON-LD partials. Recomputing
695
+ # on each call is O(N); cache once per build.
696
+ def posts
697
+ # Guard the sort against a date-less post (no `date:` frontmatter
698
+ # and no `YYYY-MM-DD-` dir prefix): `sort_by(&:date)` on a nil
699
+ # raises `comparison of NilClass with Time failed`. Undated posts
700
+ # sort to the end, matching `taxonomy_pages`.
701
+ memo(:posts) { @pages.select(&:post?).sort_by { |p| p.date || Time.at(0) }.reverse }
702
+ end
703
+
704
+ def posts_by_tag
705
+ memo(:posts_by_tag) do
706
+ result = Hash.new { |h, k| h[k] = [] }
707
+ posts.each do |post|
708
+ post.tags.each { |tag| result[tag] << post }
709
+ end
710
+ result
711
+ end
712
+ end
713
+
714
+ # ------------------------------------------------------------------
715
+ # Pipelines + data
716
+ # ------------------------------------------------------------------
717
+
718
+ def assets
719
+ memo(:assets) { AssetPipeline.new(self) }
720
+ end
721
+
722
+ def images
723
+ memo(:images) { ImagePipeline.new(self) }
724
+ end
725
+
726
+ def visualizations
727
+ memo(:visualizations) { Visualizations.new(self) }
728
+ end
729
+
730
+ def folio
731
+ memo(:folio) { Folio.new(self) }
732
+ end
733
+
734
+ def data
735
+ memo(:data) { @loader.load_data }
736
+ end
737
+
738
+ # IndieWeb — webmentions received for a given page URL. Returns an
739
+ # array of mention hashes (newest first) or `[]` when none are
740
+ # cached for that URL. The mention shape mirrors webmention.io's
741
+ # JF2 output: `{ 'wm-property' => 'in-reply-to' | 'like-of' | ...,
742
+ # 'author' => { 'name' => ..., 'url' => ..., 'photo' => ... },
743
+ # 'content' => { 'text' => ... }, 'published' => '2024-01-15T...',
744
+ # 'url' => 'https://reply.example.com/post' }`.
745
+ #
746
+ # The lookup is path-normalised (trailing slash added) so
747
+ # `/posts/foo/` matches whether the original mention pointed at
748
+ # `https://example.com/posts/foo` or `https://example.com/posts/foo/`.
749
+ def webmentions_for(url)
750
+ return [] unless data['webmentions'].is_a?(Hash)
751
+ path = url.to_s
752
+ path = "#{path}/" unless path.end_with?('/')
753
+ data['webmentions'][path] || []
754
+ end
755
+
756
+ # ------------------------------------------------------------------
757
+ # Nav / footer / social
758
+ # ------------------------------------------------------------------
759
+
760
+ def nav_links
761
+ @loader.nav_links
762
+ end
763
+
764
+ def footer_links
765
+ @loader.footer_links
766
+ end
767
+
768
+ # Social icons — emitted in the footer when `social:` is set in
769
+ # site.yml. Each key must match an SVG filename in app/icons/<key>.svg.
770
+ def social_links
771
+ raw = config['social']
772
+ return [] unless raw.is_a?(Hash)
773
+
774
+ raw.map { |key, url| { 'icon' => key.to_s, 'url' => url, 'label' => key.to_s.capitalize } }
775
+ end
776
+
777
+ # ------------------------------------------------------------------
778
+ # Renderer delegations
779
+ # ------------------------------------------------------------------
780
+
781
+ # Lazily compile and cache an ERB template. Safe to call from threads.
782
+ def compiled_template(path)
783
+ @renderer.compiled_template(path)
784
+ end
785
+
786
+ def shared_deps_mtime
787
+ @renderer.shared_deps_mtime
788
+ end
789
+
790
+ # Per-layout mtime — used by Page#needs_render? to skip pages
791
+ # whose layout chain hasn't been touched since their last build.
792
+ def layout_deps_mtime(layout_name)
793
+ @renderer.layout_deps_mtime(layout_name)
794
+ end
795
+
796
+ def post_process(html, page: nil)
797
+ @renderer.post_process(html, page: page)
798
+ end
799
+
800
+ def minify_html?
801
+ @renderer.minify_html?
802
+ end
803
+
804
+ # ------------------------------------------------------------------
805
+ # External symlink check — public because Page#bundle_assets and
806
+ # BundleAssets both call it during enumeration.
807
+ # ------------------------------------------------------------------
808
+
809
+ # True when `path` is a symlink whose target lives outside site_root.
810
+ # In-tree symlinks (e.g. linking one bundle's asset into another) are
811
+ # still allowed — that's a legitimate authoring pattern. Dangling /
812
+ # looping symlinks are skipped with a warning rather than crashing
813
+ # the build.
814
+ #
815
+ # Set `ABQARI_ALLOW_EXTERNAL_SYMLINKS=true` to bypass.
816
+ def external_symlink?(path)
817
+ return false if ENV['ABQARI_ALLOW_EXTERNAL_SYMLINKS'] == 'true'
818
+
819
+ lstat = File.lstat(path)
820
+ return false unless lstat.symlink?
821
+
822
+ # realpath on both sides so platform path quirks (macOS resolves
823
+ # /var → /private/var) don't make an in-tree symlink look external.
824
+ target = File.realpath(path)
825
+ root = File.realpath(site_root)
826
+ escaped = !(target == root || target.start_with?(root + File::SEPARATOR))
827
+ Log.warn "Skipping symlink that escapes site_root: #{path} -> #{target}" if escaped
828
+ escaped
829
+ rescue Errno::ENOENT, Errno::ELOOP => e
830
+ # Dangling or looping symlink. Either way, skip and warn — don't
831
+ # crash the build.
832
+ Log.warn "Skipping unreadable symlink #{path}: #{e.class}: #{e.message}"
833
+ true
834
+ end
835
+
836
+ private
837
+
838
+ # Anchor every Time.parse call during a build to a single zone so
839
+ # naked dates like "2026-06-15" mean the same moment regardless of
840
+ # whether the build runs on a US laptop, a Singapore phone, or a
841
+ # UTC CI runner. Without this, a future-dated post would publish
842
+ # at different wall-clock times in different deploys.
843
+ #
844
+ # Dates with explicit offsets (e.g. "2026-06-15T08:00:00+08:00")
845
+ # still honour their offset; this only affects naked dates and
846
+ # `Time.now`.
847
+ #
848
+ # Called from `build` (not `initialize`) and paired with an
849
+ # `ensure` block that restores the prior `ENV['TZ']`. Process-wide
850
+ # side effects are scoped to the duration of a single build —
851
+ # tests and host applications that share the Ruby process see
852
+ # their TZ environment untouched outside of build calls.
853
+ def apply_timezone!
854
+ tz = (config['timezone'] || 'UTC').to_s.strip
855
+ ENV['TZ'] = tz unless tz.empty?
856
+ end
857
+
858
+ # Reset between (re)builds so the dev-server's incremental rebuild
859
+ # picks up generator + template changes correctly. Clearing the
860
+ # `@memos` hash drops every memoised value at once — partition
861
+ # views (posts, posts_by_tag, taxonomy_pages, collection),
862
+ # pipelines (assets, images, visualizations), Folio, loaded
863
+ # data. Adding a new `memo(...)` accessor anywhere on Site is
864
+ # automatically picked up here; the old per-field nil-list could
865
+ # silently go out of sync.
866
+ def reset_state_for_rebuild!
867
+ @generated_pages = []
868
+ # Reopen the contribute phase. Without this the dev server's
869
+ # second incremental rebuild would raise on the first publisher
870
+ # page it generated, because the flag survived the first build.
871
+ @collections_final = false
872
+ @memos.clear
873
+ @renderer.clear_template_cache
874
+ end
875
+
876
+ # Shared scan behind `next_in_series` / `prev_in_series`. Direction
877
+ # `:forward` takes the smallest position above the current one,
878
+ # `:back` the largest position below it.
879
+ #
880
+ # A candidate's `series_position` must be a real Integer. A quoted
881
+ # YAML value ("3") drops that page out of the chain with no other
882
+ # symptom, which is why `bin/audit` flags the type — see
883
+ # `Audit::Content#flag_series_position_problems`. The *current*
884
+ # page's position is coerced with `to_i` so a page whose own value
885
+ # is mistyped can still find its neighbours.
886
+ #
887
+ # Two pages sharing a position are invisible to each other in both
888
+ # directions (the comparison is strict), so the chain silently
889
+ # skips one. The audit flags duplicates for the same reason.
890
+ def series_sibling(page, direction)
891
+ return nil unless page.respond_to?(:frontmatter)
892
+ return nil unless page.respond_to?(:collection) && page.collection
893
+
894
+ series_name = page.frontmatter['series'].to_s
895
+ return nil if series_name.empty?
896
+
897
+ raw_pos = page.frontmatter['series_position']
898
+ return nil if raw_pos.nil?
899
+
900
+ current_pos = raw_pos.to_i
901
+ candidates = collection(page.collection).select do |p|
902
+ next false unless p.frontmatter['series'].to_s == series_name
903
+
904
+ pos = p.frontmatter['series_position']
905
+ next false unless pos.is_a?(Integer)
906
+
907
+ direction == :forward ? pos > current_pos : pos < current_pos
908
+ end
909
+
910
+ positions = ->(p) { p.frontmatter['series_position'] }
911
+ direction == :forward ? candidates.min_by(&positions) : candidates.max_by(&positions)
912
+ end
913
+
914
+ # Memoise the result of `block` under `key` for the lifetime of
915
+ # this Site instance (or until `reset_state_for_rebuild!` runs).
916
+ # Every cache on Site routes through here so there's a single
917
+ # source of truth for what gets cleared between rebuilds.
918
+ #
919
+ # Mutex-guarded because templates call memoised accessors
920
+ # (`site.collection`, `site.posts`, …) from the parallel render
921
+ # pool. In practice most memos are warm before `render_pages`
922
+ # starts, and on MRI the GVL makes a torn Hash unlikely — but
923
+ # "unlikely on one implementation" isn't a guarantee, and
924
+ # `Renderer` already takes exactly this precaution for its own
925
+ # template and mtime caches. The lock is uncontended once a value
926
+ # exists, so the steady-state cost is a single `Hash#key?`.
927
+ #
928
+ # Re-entrant by design: a memoised accessor whose block calls
929
+ # another memoised accessor would deadlock on a plain Mutex, so the
930
+ # fast path reads WITHOUT the lock and the block runs OUTSIDE it.
931
+ # Two threads racing a cold key may both compute; they produce the
932
+ # same value and the last write wins, which is the standard,
933
+ # harmless memoisation race.
934
+ def memo(key)
935
+ return @memos[key] if @memos.key?(key)
936
+
937
+ value = yield
938
+ # `||=` rather than assuming the ivar: tests build sites with
939
+ # `Site.allocate` and set only the ivars they need, and a
940
+ # NoMethodError on nil there would be a baffling way to learn
941
+ # about a lock. The real constructor always sets it, so the
942
+ # lazy-init race is unreachable outside single-threaded test code.
943
+ (@memo_mutex ||= Mutex.new).synchronize { @memos[key] = value }
944
+ @memos[key]
945
+ end
946
+
947
+ def folio_enabled?
948
+ cfg = config['folio'] || {}
949
+ !cfg['base_url'].to_s.empty? && !cfg['author_slug'].to_s.empty?
950
+ end
951
+ end
952
+ end