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.
- checksums.yaml +7 -0
- data/CHANGELOG.md +889 -0
- data/LICENSE +21 -0
- data/README.md +2739 -0
- data/SECURITY.md +73 -0
- data/THIRD_PARTY_NOTICES.md +46 -0
- data/app/assets/css/_common.css +3125 -0
- data/app/assets/js/carousel.js +39 -0
- data/app/assets/js/contact-button.js +28 -0
- data/app/assets/js/random-pool.js +44 -0
- data/app/assets/js/search-init.js +11 -0
- data/app/assets/js/theme-toggle.js +39 -0
- data/app/assets/js/viz-tag-bubble.js +108 -0
- data/app/assets/js/viz-tag-cooccurrence.js +125 -0
- data/app/assets/js/viz-topic-constellation.js +142 -0
- data/app/icons/bluesky.svg +3 -0
- data/app/icons/github.svg +3 -0
- data/app/icons/linkedin.svg +3 -0
- data/app/icons/mail.svg +4 -0
- data/app/icons/mastodon.svg +3 -0
- data/app/icons/moon.svg +3 -0
- data/app/icons/rss.svg +3 -0
- data/app/icons/sun.svg +4 -0
- data/app/icons/x.svg +3 -0
- data/app/views/layouts/about.html.erb +70 -0
- data/app/views/layouts/application.html.erb +65 -0
- data/app/views/layouts/book_series_index.html.erb +43 -0
- data/app/views/layouts/bundle.html.erb +111 -0
- data/app/views/layouts/bundles_index.html.erb +46 -0
- data/app/views/layouts/country_index.html.erb +59 -0
- data/app/views/layouts/gallery_index.html.erb +126 -0
- data/app/views/layouts/home.html.erb +107 -0
- data/app/views/layouts/photo.html.erb +100 -0
- data/app/views/layouts/photos_archive.html.erb +101 -0
- data/app/views/layouts/photos_index.html.erb +204 -0
- data/app/views/layouts/post.html.erb +153 -0
- data/app/views/layouts/posts_archive.html.erb +98 -0
- data/app/views/layouts/posts_index.html.erb +80 -0
- data/app/views/layouts/publication.html.erb +116 -0
- data/app/views/layouts/publications_archive.html.erb +89 -0
- data/app/views/layouts/publications_index.html.erb +246 -0
- data/app/views/layouts/related_index.html.erb +48 -0
- data/app/views/layouts/series.html.erb +110 -0
- data/app/views/layouts/series_index.html.erb +202 -0
- data/app/views/layouts/tag.html.erb +16 -0
- data/app/views/layouts/visualization.html.erb +32 -0
- data/app/views/layouts/workshop.html.erb +163 -0
- data/app/views/layouts/workshops_index.html.erb +209 -0
- data/app/views/partials/_back_link.html.erb +27 -0
- data/app/views/partials/_back_to_index.html.erb +25 -0
- data/app/views/partials/_book_grid.html.erb +76 -0
- data/app/views/partials/_book_jsonld.html.erb +72 -0
- data/app/views/partials/_book_related.html.erb +87 -0
- data/app/views/partials/_breadcrumb_jsonld.html.erb +60 -0
- data/app/views/partials/_bundle_cta.html.erb +26 -0
- data/app/views/partials/_carousel.html.erb +64 -0
- data/app/views/partials/_collection_page_jsonld.html.erb +81 -0
- data/app/views/partials/_contact_button.html.erb +42 -0
- data/app/views/partials/_course_jsonld.html.erb +95 -0
- data/app/views/partials/_draft_banner.html.erb +20 -0
- data/app/views/partials/_event_jsonld.html.erb +122 -0
- data/app/views/partials/_footer.html.erb +88 -0
- data/app/views/partials/_future_banner.html.erb +25 -0
- data/app/views/partials/_head.html.erb +440 -0
- data/app/views/partials/_image_gallery.html.erb +64 -0
- data/app/views/partials/_image_object_jsonld.html.erb +61 -0
- data/app/views/partials/_nav.html.erb +63 -0
- data/app/views/partials/_newsletter_subscribe.html.erb +85 -0
- data/app/views/partials/_next_in_series.html.erb +27 -0
- data/app/views/partials/_next_item.html.erb +38 -0
- data/app/views/partials/_pagination.html.erb +15 -0
- data/app/views/partials/_person_jsonld.html.erb +46 -0
- data/app/views/partials/_plausible.html.erb +24 -0
- data/app/views/partials/_post_list.html.erb +101 -0
- data/app/views/partials/_post_series_previews.html.erb +92 -0
- data/app/views/partials/_publication_card.html.erb +75 -0
- data/app/views/partials/_publication_header.html.erb +61 -0
- data/app/views/partials/_related_item.html.erb +68 -0
- data/app/views/partials/_related_items.html.erb +105 -0
- data/app/views/partials/_search.html.erb +26 -0
- data/app/views/partials/_series_pager.html.erb +48 -0
- data/app/views/partials/_skip_link.html.erb +12 -0
- data/app/views/partials/_taxonomy_row.html.erb +62 -0
- data/app/views/partials/_testimonials.html.erb +149 -0
- data/app/views/partials/_theme_toggle.html.erb +19 -0
- data/app/views/partials/_toc.html.erb +136 -0
- data/app/views/partials/_webmentions.html.erb +131 -0
- data/app/views/partials/_website_jsonld.html.erb +39 -0
- data/app/views/partials/home/_contact.html.erb +19 -0
- data/app/views/partials/home/_featured_publication.html.erb +107 -0
- data/app/views/partials/home/_latest_photo.html.erb +95 -0
- data/app/views/partials/home/_latest_post.html.erb +48 -0
- data/app/views/partials/home/_latest_publication.html.erb +89 -0
- data/app/views/partials/home/_next_workshop.html.erb +119 -0
- data/app/views/partials/home/_photo_gallery.html.erb +71 -0
- data/app/views/partials/home/_random_photo.html.erb +106 -0
- data/app/views/partials/home/_random_post.html.erb +64 -0
- data/exe/abqari +37 -0
- data/lib/abqari/artifact_writer.rb +196 -0
- data/lib/abqari/asset_pipeline.rb +235 -0
- data/lib/abqari/audit/a11y.rb +80 -0
- data/lib/abqari/audit/content.rb +154 -0
- data/lib/abqari/audit/dependencies.rb +127 -0
- data/lib/abqari/audit/links.rb +120 -0
- data/lib/abqari/audit/performance.rb +120 -0
- data/lib/abqari/audit/privacy.rb +42 -0
- data/lib/abqari/audit/rule.rb +56 -0
- data/lib/abqari/audit/seo.rb +105 -0
- data/lib/abqari/audit.rb +149 -0
- data/lib/abqari/bundle_assets.rb +127 -0
- data/lib/abqari/cli/new.rb +541 -0
- data/lib/abqari/cli/theme.rb +181 -0
- data/lib/abqari/cli.rb +130 -0
- data/lib/abqari/erbi_template.rb +72 -0
- data/lib/abqari/feed.rb +159 -0
- data/lib/abqari/folio.rb +195 -0
- data/lib/abqari/font_pipeline.rb +104 -0
- data/lib/abqari/headers_file.rb +324 -0
- data/lib/abqari/helpers.rb +308 -0
- data/lib/abqari/hooks.rb +136 -0
- data/lib/abqari/http_safe.rb +222 -0
- data/lib/abqari/image_pipeline.rb +800 -0
- data/lib/abqari/importers/base.rb +351 -0
- data/lib/abqari/importers/cli.rb +169 -0
- data/lib/abqari/importers/ghost.rb +113 -0
- data/lib/abqari/importers/jekyll.rb +256 -0
- data/lib/abqari/importers/substack.rb +204 -0
- data/lib/abqari/importers/support/html_to_markdown.rb +126 -0
- data/lib/abqari/importers/support/image_downloader.rb +170 -0
- data/lib/abqari/importers/support/report.rb +87 -0
- data/lib/abqari/importers/support/slug_normalizer.rb +53 -0
- data/lib/abqari/importers.rb +64 -0
- data/lib/abqari/indieweb.rb +551 -0
- data/lib/abqari/llms_txt.rb +110 -0
- data/lib/abqari/log.rb +61 -0
- data/lib/abqari/manifest.rb +58 -0
- data/lib/abqari/minifier.rb +108 -0
- data/lib/abqari/og_image_generator.rb +223 -0
- data/lib/abqari/page/bundle.rb +152 -0
- data/lib/abqari/page/incremental.rb +74 -0
- data/lib/abqari/page/parser.rb +129 -0
- data/lib/abqari/page/path.rb +153 -0
- data/lib/abqari/page.rb +424 -0
- data/lib/abqari/paginated_shard.rb +109 -0
- data/lib/abqari/paginator.rb +35 -0
- data/lib/abqari/path_safe.rb +62 -0
- data/lib/abqari/plausible_script.rb +20 -0
- data/lib/abqari/publication_normaliser.rb +111 -0
- data/lib/abqari/publisher_pages.rb +342 -0
- data/lib/abqari/redirects.rb +134 -0
- data/lib/abqari/related_index_page.rb +79 -0
- data/lib/abqari/render_context/cover_helpers.rb +338 -0
- data/lib/abqari/render_context/picture_helpers.rb +178 -0
- data/lib/abqari/render_context/publication_helpers.rb +120 -0
- data/lib/abqari/render_context.rb +251 -0
- data/lib/abqari/renderer.rb +788 -0
- data/lib/abqari/robots.rb +93 -0
- data/lib/abqari/search.rb +68 -0
- data/lib/abqari/security_txt.rb +44 -0
- data/lib/abqari/server.rb +508 -0
- data/lib/abqari/site.rb +952 -0
- data/lib/abqari/site_config.rb +212 -0
- data/lib/abqari/site_loader.rb +265 -0
- data/lib/abqari/sitemap.rb +87 -0
- data/lib/abqari/speculation_rules_guard.rb +26 -0
- data/lib/abqari/syndication.rb +466 -0
- data/lib/abqari/syntax_highlighter.rb +146 -0
- data/lib/abqari/taxonomy_page.rb +129 -0
- data/lib/abqari/templates/site_skeleton/.github/dependabot.yml +53 -0
- data/lib/abqari/templates/site_skeleton/.github/workflows/deploy-cloudflare.yml +107 -0
- data/lib/abqari/templates/site_skeleton/.github/workflows/deploy-github-pages.yml +107 -0
- data/lib/abqari/templates/site_skeleton/.github/workflows/deploy-render.yml +87 -0
- data/lib/abqari/templates/site_skeleton/.gitignore +24 -0
- data/lib/abqari/templates/site_skeleton/.ruby-version.tt +1 -0
- data/lib/abqari/templates/site_skeleton/Gemfile.tt +20 -0
- data/lib/abqari/templates/site_skeleton/README.md.tt +60 -0
- data/lib/abqari/templates/site_skeleton/app/assets/css/site.css +9 -0
- data/lib/abqari/templates/site_skeleton/bin/audit +46 -0
- data/lib/abqari/templates/site_skeleton/bin/build +32 -0
- data/lib/abqari/templates/site_skeleton/bin/fetch-folio +32 -0
- data/lib/abqari/templates/site_skeleton/bin/fetch-fonts +20 -0
- data/lib/abqari/templates/site_skeleton/bin/import +31 -0
- data/lib/abqari/templates/site_skeleton/bin/index +30 -0
- data/lib/abqari/templates/site_skeleton/bin/new +235 -0
- data/lib/abqari/templates/site_skeleton/bin/serve +30 -0
- data/lib/abqari/templates/site_skeleton/config/site.blank.yml.tt +65 -0
- data/lib/abqari/templates/site_skeleton/config/site.yml.tt +266 -0
- data/lib/abqari/templates/site_skeleton/content/404.md +17 -0
- data/lib/abqari/templates/site_skeleton/content/about.blank.md.tt +12 -0
- data/lib/abqari/templates/site_skeleton/content/about.md.tt +18 -0
- data/lib/abqari/templates/site_skeleton/content/index.blank.md.tt +11 -0
- data/lib/abqari/templates/site_skeleton/content/index.md.tt +34 -0
- data/lib/abqari/templates/site_skeleton/content/photos/index.md.tt +12 -0
- data/lib/abqari/templates/site_skeleton/content/posts/index.md +12 -0
- data/lib/abqari/templates/site_skeleton/content/posts/welcome/index.md.tt +50 -0
- data/lib/abqari/templates/site_skeleton/content/publications/index.md.tt +13 -0
- data/lib/abqari/templates/site_skeleton/content/workshops/index.md.tt +13 -0
- data/lib/abqari/templates/site_skeleton/public/robots.txt +6 -0
- data/lib/abqari/templates/site_skeleton/themes/.gitkeep +0 -0
- data/lib/abqari/templates/site_skeleton/vendor/folio/.gitkeep +0 -0
- data/lib/abqari/templates/site_skeleton/vendor/fonts/.gitkeep +0 -0
- data/lib/abqari/theme_bootstrap.rb +19 -0
- data/lib/abqari/theme_fonts.rb +51 -0
- data/lib/abqari/version.rb +18 -0
- data/lib/abqari/visualizations.rb +215 -0
- data/lib/abqari.rb +154 -0
- data/themes/bootstrap/css/app.css +97 -0
- data/themes/bootstrap/public/LICENSE +21 -0
- data/themes/bootstrap/public/css/bootstrap.min.css +6 -0
- data/themes/bootstrap/public/css/bootstrap.min.css.map +1 -0
- data/themes/bootstrap/public/js/bootstrap.bundle.min.js +7 -0
- data/themes/bootstrap/public/js/bootstrap.bundle.min.js.map +1 -0
- data/themes/custom/css/app.css +176 -0
- data/themes/magazine/css/app.css +242 -0
- data/themes/minimal/css/app.css +151 -0
- data/themes/notebook/css/app.css +205 -0
- data/themes/sand/css/app.css +179 -0
- data/vendor/d3/d3.v7.min.js +2 -0
- data/vendor/heroicons/16/solid/academic-cap.svg +4 -0
- data/vendor/heroicons/16/solid/adjustments-horizontal.svg +3 -0
- data/vendor/heroicons/16/solid/adjustments-vertical.svg +3 -0
- data/vendor/heroicons/16/solid/archive-box-arrow-down.svg +4 -0
- data/vendor/heroicons/16/solid/archive-box-x-mark.svg +4 -0
- data/vendor/heroicons/16/solid/archive-box.svg +4 -0
- data/vendor/heroicons/16/solid/arrow-down-circle.svg +3 -0
- data/vendor/heroicons/16/solid/arrow-down-left.svg +3 -0
- data/vendor/heroicons/16/solid/arrow-down-on-square-stack.svg +4 -0
- data/vendor/heroicons/16/solid/arrow-down-on-square.svg +3 -0
- data/vendor/heroicons/16/solid/arrow-down-right.svg +3 -0
- data/vendor/heroicons/16/solid/arrow-down-tray.svg +4 -0
- data/vendor/heroicons/16/solid/arrow-down.svg +3 -0
- data/vendor/heroicons/16/solid/arrow-left-circle.svg +3 -0
- data/vendor/heroicons/16/solid/arrow-left-end-on-rectangle.svg +4 -0
- data/vendor/heroicons/16/solid/arrow-left-start-on-rectangle.svg +3 -0
- data/vendor/heroicons/16/solid/arrow-left.svg +3 -0
- data/vendor/heroicons/16/solid/arrow-long-down.svg +3 -0
- data/vendor/heroicons/16/solid/arrow-long-left.svg +3 -0
- data/vendor/heroicons/16/solid/arrow-long-right.svg +3 -0
- data/vendor/heroicons/16/solid/arrow-long-up.svg +3 -0
- data/vendor/heroicons/16/solid/arrow-path-rounded-square.svg +3 -0
- data/vendor/heroicons/16/solid/arrow-path.svg +3 -0
- data/vendor/heroicons/16/solid/arrow-right-circle.svg +3 -0
- data/vendor/heroicons/16/solid/arrow-right-end-on-rectangle.svg +4 -0
- data/vendor/heroicons/16/solid/arrow-right-start-on-rectangle.svg +3 -0
- data/vendor/heroicons/16/solid/arrow-right.svg +3 -0
- data/vendor/heroicons/16/solid/arrow-top-right-on-square.svg +4 -0
- data/vendor/heroicons/16/solid/arrow-trending-down.svg +3 -0
- data/vendor/heroicons/16/solid/arrow-trending-up.svg +3 -0
- data/vendor/heroicons/16/solid/arrow-turn-down-left.svg +3 -0
- data/vendor/heroicons/16/solid/arrow-turn-down-right.svg +3 -0
- data/vendor/heroicons/16/solid/arrow-turn-left-down.svg +3 -0
- data/vendor/heroicons/16/solid/arrow-turn-left-up.svg +3 -0
- data/vendor/heroicons/16/solid/arrow-turn-right-down.svg +3 -0
- data/vendor/heroicons/16/solid/arrow-turn-right-up.svg +3 -0
- data/vendor/heroicons/16/solid/arrow-turn-up-left.svg +3 -0
- data/vendor/heroicons/16/solid/arrow-turn-up-right.svg +3 -0
- data/vendor/heroicons/16/solid/arrow-up-circle.svg +3 -0
- data/vendor/heroicons/16/solid/arrow-up-left.svg +3 -0
- data/vendor/heroicons/16/solid/arrow-up-on-square-stack.svg +4 -0
- data/vendor/heroicons/16/solid/arrow-up-on-square.svg +3 -0
- data/vendor/heroicons/16/solid/arrow-up-right.svg +3 -0
- data/vendor/heroicons/16/solid/arrow-up-tray.svg +4 -0
- data/vendor/heroicons/16/solid/arrow-up.svg +3 -0
- data/vendor/heroicons/16/solid/arrow-uturn-down.svg +3 -0
- data/vendor/heroicons/16/solid/arrow-uturn-left.svg +3 -0
- data/vendor/heroicons/16/solid/arrow-uturn-right.svg +3 -0
- data/vendor/heroicons/16/solid/arrow-uturn-up.svg +3 -0
- data/vendor/heroicons/16/solid/arrows-pointing-in.svg +3 -0
- data/vendor/heroicons/16/solid/arrows-pointing-out.svg +3 -0
- data/vendor/heroicons/16/solid/arrows-right-left.svg +3 -0
- data/vendor/heroicons/16/solid/arrows-up-down.svg +3 -0
- data/vendor/heroicons/16/solid/at-symbol.svg +3 -0
- data/vendor/heroicons/16/solid/backspace.svg +3 -0
- data/vendor/heroicons/16/solid/backward.svg +3 -0
- data/vendor/heroicons/16/solid/banknotes.svg +4 -0
- data/vendor/heroicons/16/solid/bars-2.svg +3 -0
- data/vendor/heroicons/16/solid/bars-3-bottom-left.svg +3 -0
- data/vendor/heroicons/16/solid/bars-3-bottom-right.svg +3 -0
- data/vendor/heroicons/16/solid/bars-3-center-left.svg +3 -0
- data/vendor/heroicons/16/solid/bars-3.svg +3 -0
- data/vendor/heroicons/16/solid/bars-4.svg +3 -0
- data/vendor/heroicons/16/solid/bars-arrow-down.svg +3 -0
- data/vendor/heroicons/16/solid/bars-arrow-up.svg +3 -0
- data/vendor/heroicons/16/solid/battery-0.svg +3 -0
- data/vendor/heroicons/16/solid/battery-100.svg +4 -0
- data/vendor/heroicons/16/solid/battery-50.svg +4 -0
- data/vendor/heroicons/16/solid/beaker.svg +3 -0
- data/vendor/heroicons/16/solid/bell-alert.svg +4 -0
- data/vendor/heroicons/16/solid/bell-slash.svg +4 -0
- data/vendor/heroicons/16/solid/bell-snooze.svg +3 -0
- data/vendor/heroicons/16/solid/bell.svg +3 -0
- data/vendor/heroicons/16/solid/bold.svg +3 -0
- data/vendor/heroicons/16/solid/bolt-slash.svg +3 -0
- data/vendor/heroicons/16/solid/bolt.svg +3 -0
- data/vendor/heroicons/16/solid/book-open.svg +3 -0
- data/vendor/heroicons/16/solid/bookmark-slash.svg +3 -0
- data/vendor/heroicons/16/solid/bookmark-square.svg +3 -0
- data/vendor/heroicons/16/solid/bookmark.svg +3 -0
- data/vendor/heroicons/16/solid/briefcase.svg +4 -0
- data/vendor/heroicons/16/solid/bug-ant.svg +3 -0
- data/vendor/heroicons/16/solid/building-library.svg +3 -0
- data/vendor/heroicons/16/solid/building-office-2.svg +3 -0
- data/vendor/heroicons/16/solid/building-office.svg +3 -0
- data/vendor/heroicons/16/solid/building-storefront.svg +3 -0
- data/vendor/heroicons/16/solid/cake.svg +3 -0
- data/vendor/heroicons/16/solid/calculator.svg +3 -0
- data/vendor/heroicons/16/solid/calendar-date-range.svg +4 -0
- data/vendor/heroicons/16/solid/calendar-days.svg +4 -0
- data/vendor/heroicons/16/solid/calendar.svg +3 -0
- data/vendor/heroicons/16/solid/camera.svg +4 -0
- data/vendor/heroicons/16/solid/chart-bar-square.svg +3 -0
- data/vendor/heroicons/16/solid/chart-bar.svg +3 -0
- data/vendor/heroicons/16/solid/chart-pie.svg +4 -0
- data/vendor/heroicons/16/solid/chat-bubble-bottom-center-text.svg +3 -0
- data/vendor/heroicons/16/solid/chat-bubble-bottom-center.svg +3 -0
- data/vendor/heroicons/16/solid/chat-bubble-left-ellipsis.svg +3 -0
- data/vendor/heroicons/16/solid/chat-bubble-left-right.svg +4 -0
- data/vendor/heroicons/16/solid/chat-bubble-left.svg +3 -0
- data/vendor/heroicons/16/solid/chat-bubble-oval-left-ellipsis.svg +3 -0
- data/vendor/heroicons/16/solid/chat-bubble-oval-left.svg +3 -0
- data/vendor/heroicons/16/solid/check-badge.svg +3 -0
- data/vendor/heroicons/16/solid/check-circle.svg +3 -0
- data/vendor/heroicons/16/solid/check.svg +3 -0
- data/vendor/heroicons/16/solid/chevron-double-down.svg +3 -0
- data/vendor/heroicons/16/solid/chevron-double-left.svg +3 -0
- data/vendor/heroicons/16/solid/chevron-double-right.svg +3 -0
- data/vendor/heroicons/16/solid/chevron-double-up.svg +3 -0
- data/vendor/heroicons/16/solid/chevron-down.svg +3 -0
- data/vendor/heroicons/16/solid/chevron-left.svg +3 -0
- data/vendor/heroicons/16/solid/chevron-right.svg +3 -0
- data/vendor/heroicons/16/solid/chevron-up-down.svg +3 -0
- data/vendor/heroicons/16/solid/chevron-up.svg +3 -0
- data/vendor/heroicons/16/solid/circle-stack.svg +5 -0
- data/vendor/heroicons/16/solid/clipboard-document-check.svg +4 -0
- data/vendor/heroicons/16/solid/clipboard-document-list.svg +4 -0
- data/vendor/heroicons/16/solid/clipboard-document.svg +4 -0
- data/vendor/heroicons/16/solid/clipboard.svg +3 -0
- data/vendor/heroicons/16/solid/clock.svg +3 -0
- data/vendor/heroicons/16/solid/cloud-arrow-down.svg +3 -0
- data/vendor/heroicons/16/solid/cloud-arrow-up.svg +3 -0
- data/vendor/heroicons/16/solid/cloud.svg +3 -0
- data/vendor/heroicons/16/solid/code-bracket-square.svg +3 -0
- data/vendor/heroicons/16/solid/code-bracket.svg +3 -0
- data/vendor/heroicons/16/solid/cog-6-tooth.svg +3 -0
- data/vendor/heroicons/16/solid/cog-8-tooth.svg +3 -0
- data/vendor/heroicons/16/solid/cog.svg +3 -0
- data/vendor/heroicons/16/solid/command-line.svg +3 -0
- data/vendor/heroicons/16/solid/computer-desktop.svg +3 -0
- data/vendor/heroicons/16/solid/cpu-chip.svg +4 -0
- data/vendor/heroicons/16/solid/credit-card.svg +4 -0
- data/vendor/heroicons/16/solid/cube-transparent.svg +3 -0
- data/vendor/heroicons/16/solid/cube.svg +3 -0
- data/vendor/heroicons/16/solid/currency-bangladeshi.svg +3 -0
- data/vendor/heroicons/16/solid/currency-dollar.svg +4 -0
- data/vendor/heroicons/16/solid/currency-euro.svg +3 -0
- data/vendor/heroicons/16/solid/currency-pound.svg +3 -0
- data/vendor/heroicons/16/solid/currency-rupee.svg +3 -0
- data/vendor/heroicons/16/solid/currency-yen.svg +3 -0
- data/vendor/heroicons/16/solid/cursor-arrow-rays.svg +3 -0
- data/vendor/heroicons/16/solid/cursor-arrow-ripple.svg +5 -0
- data/vendor/heroicons/16/solid/device-phone-mobile.svg +4 -0
- data/vendor/heroicons/16/solid/device-tablet.svg +4 -0
- data/vendor/heroicons/16/solid/divide.svg +4 -0
- data/vendor/heroicons/16/solid/document-arrow-down.svg +3 -0
- data/vendor/heroicons/16/solid/document-arrow-up.svg +3 -0
- data/vendor/heroicons/16/solid/document-chart-bar.svg +3 -0
- data/vendor/heroicons/16/solid/document-check.svg +3 -0
- data/vendor/heroicons/16/solid/document-currency-bangladeshi.svg +3 -0
- data/vendor/heroicons/16/solid/document-currency-dollar.svg +4 -0
- data/vendor/heroicons/16/solid/document-currency-euro.svg +3 -0
- data/vendor/heroicons/16/solid/document-currency-pound.svg +3 -0
- data/vendor/heroicons/16/solid/document-currency-rupee.svg +3 -0
- data/vendor/heroicons/16/solid/document-currency-yen.svg +3 -0
- data/vendor/heroicons/16/solid/document-duplicate.svg +4 -0
- data/vendor/heroicons/16/solid/document-magnifying-glass.svg +4 -0
- data/vendor/heroicons/16/solid/document-minus.svg +3 -0
- data/vendor/heroicons/16/solid/document-plus.svg +3 -0
- data/vendor/heroicons/16/solid/document-text.svg +3 -0
- data/vendor/heroicons/16/solid/document.svg +3 -0
- data/vendor/heroicons/16/solid/ellipsis-horizontal-circle.svg +3 -0
- data/vendor/heroicons/16/solid/ellipsis-horizontal.svg +3 -0
- data/vendor/heroicons/16/solid/ellipsis-vertical.svg +3 -0
- data/vendor/heroicons/16/solid/envelope-open.svg +3 -0
- data/vendor/heroicons/16/solid/envelope.svg +4 -0
- data/vendor/heroicons/16/solid/equals.svg +3 -0
- data/vendor/heroicons/16/solid/exclamation-circle.svg +3 -0
- data/vendor/heroicons/16/solid/exclamation-triangle.svg +3 -0
- data/vendor/heroicons/16/solid/eye-dropper.svg +3 -0
- data/vendor/heroicons/16/solid/eye-slash.svg +4 -0
- data/vendor/heroicons/16/solid/eye.svg +4 -0
- data/vendor/heroicons/16/solid/face-frown.svg +3 -0
- data/vendor/heroicons/16/solid/face-smile.svg +3 -0
- data/vendor/heroicons/16/solid/film.svg +3 -0
- data/vendor/heroicons/16/solid/finger-print.svg +3 -0
- data/vendor/heroicons/16/solid/fire.svg +3 -0
- data/vendor/heroicons/16/solid/flag.svg +3 -0
- data/vendor/heroicons/16/solid/folder-arrow-down.svg +3 -0
- data/vendor/heroicons/16/solid/folder-minus.svg +3 -0
- data/vendor/heroicons/16/solid/folder-open.svg +3 -0
- data/vendor/heroicons/16/solid/folder-plus.svg +3 -0
- data/vendor/heroicons/16/solid/folder.svg +3 -0
- data/vendor/heroicons/16/solid/forward.svg +3 -0
- data/vendor/heroicons/16/solid/funnel.svg +3 -0
- data/vendor/heroicons/16/solid/gif.svg +3 -0
- data/vendor/heroicons/16/solid/gift-top.svg +4 -0
- data/vendor/heroicons/16/solid/gift.svg +4 -0
- data/vendor/heroicons/16/solid/globe-alt.svg +3 -0
- data/vendor/heroicons/16/solid/globe-americas.svg +3 -0
- data/vendor/heroicons/16/solid/globe-asia-australia.svg +3 -0
- data/vendor/heroicons/16/solid/globe-europe-africa.svg +3 -0
- data/vendor/heroicons/16/solid/h1.svg +3 -0
- data/vendor/heroicons/16/solid/h2.svg +3 -0
- data/vendor/heroicons/16/solid/h3.svg +3 -0
- data/vendor/heroicons/16/solid/hand-raised.svg +3 -0
- data/vendor/heroicons/16/solid/hand-thumb-down.svg +3 -0
- data/vendor/heroicons/16/solid/hand-thumb-up.svg +3 -0
- data/vendor/heroicons/16/solid/hashtag.svg +3 -0
- data/vendor/heroicons/16/solid/heart.svg +3 -0
- data/vendor/heroicons/16/solid/home-modern.svg +3 -0
- data/vendor/heroicons/16/solid/home.svg +3 -0
- data/vendor/heroicons/16/solid/identification.svg +3 -0
- data/vendor/heroicons/16/solid/inbox-arrow-down.svg +4 -0
- data/vendor/heroicons/16/solid/inbox-stack.svg +4 -0
- data/vendor/heroicons/16/solid/inbox.svg +3 -0
- data/vendor/heroicons/16/solid/information-circle.svg +3 -0
- data/vendor/heroicons/16/solid/italic.svg +3 -0
- data/vendor/heroicons/16/solid/key.svg +3 -0
- data/vendor/heroicons/16/solid/language.svg +3 -0
- data/vendor/heroicons/16/solid/lifebuoy.svg +3 -0
- data/vendor/heroicons/16/solid/light-bulb.svg +3 -0
- data/vendor/heroicons/16/solid/link-slash.svg +3 -0
- data/vendor/heroicons/16/solid/link.svg +4 -0
- data/vendor/heroicons/16/solid/list-bullet.svg +3 -0
- data/vendor/heroicons/16/solid/lock-closed.svg +3 -0
- data/vendor/heroicons/16/solid/lock-open.svg +3 -0
- data/vendor/heroicons/16/solid/magnifying-glass-circle.svg +4 -0
- data/vendor/heroicons/16/solid/magnifying-glass-minus.svg +4 -0
- data/vendor/heroicons/16/solid/magnifying-glass-plus.svg +4 -0
- data/vendor/heroicons/16/solid/magnifying-glass.svg +3 -0
- data/vendor/heroicons/16/solid/map-pin.svg +3 -0
- data/vendor/heroicons/16/solid/map.svg +3 -0
- data/vendor/heroicons/16/solid/megaphone.svg +3 -0
- data/vendor/heroicons/16/solid/microphone.svg +4 -0
- data/vendor/heroicons/16/solid/minus-circle.svg +3 -0
- data/vendor/heroicons/16/solid/minus.svg +3 -0
- data/vendor/heroicons/16/solid/moon.svg +3 -0
- data/vendor/heroicons/16/solid/musical-note.svg +3 -0
- data/vendor/heroicons/16/solid/newspaper.svg +4 -0
- data/vendor/heroicons/16/solid/no-symbol.svg +3 -0
- data/vendor/heroicons/16/solid/numbered-list.svg +3 -0
- data/vendor/heroicons/16/solid/paint-brush.svg +3 -0
- data/vendor/heroicons/16/solid/paper-airplane.svg +3 -0
- data/vendor/heroicons/16/solid/paper-clip.svg +3 -0
- data/vendor/heroicons/16/solid/pause-circle.svg +3 -0
- data/vendor/heroicons/16/solid/pause.svg +3 -0
- data/vendor/heroicons/16/solid/pencil-square.svg +4 -0
- data/vendor/heroicons/16/solid/pencil.svg +3 -0
- data/vendor/heroicons/16/solid/percent-badge.svg +3 -0
- data/vendor/heroicons/16/solid/phone-arrow-down-left.svg +4 -0
- data/vendor/heroicons/16/solid/phone-arrow-up-right.svg +4 -0
- data/vendor/heroicons/16/solid/phone-x-mark.svg +4 -0
- data/vendor/heroicons/16/solid/phone.svg +3 -0
- data/vendor/heroicons/16/solid/photo.svg +3 -0
- data/vendor/heroicons/16/solid/play-circle.svg +3 -0
- data/vendor/heroicons/16/solid/play-pause.svg +3 -0
- data/vendor/heroicons/16/solid/play.svg +3 -0
- data/vendor/heroicons/16/solid/plus-circle.svg +3 -0
- data/vendor/heroicons/16/solid/plus.svg +3 -0
- data/vendor/heroicons/16/solid/power.svg +3 -0
- data/vendor/heroicons/16/solid/presentation-chart-bar.svg +3 -0
- data/vendor/heroicons/16/solid/presentation-chart-line.svg +3 -0
- data/vendor/heroicons/16/solid/printer.svg +3 -0
- data/vendor/heroicons/16/solid/puzzle-piece.svg +3 -0
- data/vendor/heroicons/16/solid/qr-code.svg +9 -0
- data/vendor/heroicons/16/solid/question-mark-circle.svg +3 -0
- data/vendor/heroicons/16/solid/queue-list.svg +3 -0
- data/vendor/heroicons/16/solid/radio.svg +3 -0
- data/vendor/heroicons/16/solid/receipt-percent.svg +3 -0
- data/vendor/heroicons/16/solid/receipt-refund.svg +3 -0
- data/vendor/heroicons/16/solid/rectangle-group.svg +3 -0
- data/vendor/heroicons/16/solid/rectangle-stack.svg +3 -0
- data/vendor/heroicons/16/solid/rocket-launch.svg +4 -0
- data/vendor/heroicons/16/solid/rss.svg +3 -0
- data/vendor/heroicons/16/solid/scale.svg +3 -0
- data/vendor/heroicons/16/solid/scissors.svg +4 -0
- data/vendor/heroicons/16/solid/server-stack.svg +4 -0
- data/vendor/heroicons/16/solid/server.svg +4 -0
- data/vendor/heroicons/16/solid/share.svg +3 -0
- data/vendor/heroicons/16/solid/shield-check.svg +3 -0
- data/vendor/heroicons/16/solid/shield-exclamation.svg +3 -0
- data/vendor/heroicons/16/solid/shopping-bag.svg +3 -0
- data/vendor/heroicons/16/solid/shopping-cart.svg +3 -0
- data/vendor/heroicons/16/solid/signal-slash.svg +3 -0
- data/vendor/heroicons/16/solid/signal.svg +5 -0
- data/vendor/heroicons/16/solid/slash.svg +3 -0
- data/vendor/heroicons/16/solid/sparkles.svg +3 -0
- data/vendor/heroicons/16/solid/speaker-wave.svg +4 -0
- data/vendor/heroicons/16/solid/speaker-x-mark.svg +3 -0
- data/vendor/heroicons/16/solid/square-2-stack.svg +4 -0
- data/vendor/heroicons/16/solid/square-3-stack-3d.svg +5 -0
- data/vendor/heroicons/16/solid/squares-2x2.svg +3 -0
- data/vendor/heroicons/16/solid/squares-plus.svg +3 -0
- data/vendor/heroicons/16/solid/star.svg +3 -0
- data/vendor/heroicons/16/solid/stop-circle.svg +3 -0
- data/vendor/heroicons/16/solid/stop.svg +3 -0
- data/vendor/heroicons/16/solid/strikethrough.svg +3 -0
- data/vendor/heroicons/16/solid/sun.svg +3 -0
- data/vendor/heroicons/16/solid/swatch.svg +4 -0
- data/vendor/heroicons/16/solid/table-cells.svg +3 -0
- data/vendor/heroicons/16/solid/tag.svg +3 -0
- data/vendor/heroicons/16/solid/ticket.svg +3 -0
- data/vendor/heroicons/16/solid/trash.svg +3 -0
- data/vendor/heroicons/16/solid/trophy.svg +3 -0
- data/vendor/heroicons/16/solid/truck.svg +5 -0
- data/vendor/heroicons/16/solid/tv.svg +4 -0
- data/vendor/heroicons/16/solid/underline.svg +3 -0
- data/vendor/heroicons/16/solid/user-circle.svg +3 -0
- data/vendor/heroicons/16/solid/user-group.svg +3 -0
- data/vendor/heroicons/16/solid/user-minus.svg +3 -0
- data/vendor/heroicons/16/solid/user-plus.svg +3 -0
- data/vendor/heroicons/16/solid/user.svg +3 -0
- data/vendor/heroicons/16/solid/users.svg +3 -0
- data/vendor/heroicons/16/solid/variable.svg +3 -0
- data/vendor/heroicons/16/solid/video-camera-slash.svg +3 -0
- data/vendor/heroicons/16/solid/video-camera.svg +3 -0
- data/vendor/heroicons/16/solid/view-columns.svg +3 -0
- data/vendor/heroicons/16/solid/viewfinder-circle.svg +3 -0
- data/vendor/heroicons/16/solid/wallet.svg +3 -0
- data/vendor/heroicons/16/solid/wifi.svg +3 -0
- data/vendor/heroicons/16/solid/window.svg +3 -0
- data/vendor/heroicons/16/solid/wrench-screwdriver.svg +4 -0
- data/vendor/heroicons/16/solid/wrench.svg +3 -0
- data/vendor/heroicons/16/solid/x-circle.svg +3 -0
- data/vendor/heroicons/16/solid/x-mark.svg +3 -0
- data/vendor/heroicons/20/solid/academic-cap.svg +3 -0
- data/vendor/heroicons/20/solid/adjustments-horizontal.svg +3 -0
- data/vendor/heroicons/20/solid/adjustments-vertical.svg +3 -0
- data/vendor/heroicons/20/solid/archive-box-arrow-down.svg +3 -0
- data/vendor/heroicons/20/solid/archive-box-x-mark.svg +4 -0
- data/vendor/heroicons/20/solid/archive-box.svg +4 -0
- data/vendor/heroicons/20/solid/arrow-down-circle.svg +3 -0
- data/vendor/heroicons/20/solid/arrow-down-left.svg +3 -0
- data/vendor/heroicons/20/solid/arrow-down-on-square-stack.svg +3 -0
- data/vendor/heroicons/20/solid/arrow-down-on-square.svg +3 -0
- data/vendor/heroicons/20/solid/arrow-down-right.svg +3 -0
- data/vendor/heroicons/20/solid/arrow-down-tray.svg +4 -0
- data/vendor/heroicons/20/solid/arrow-down.svg +3 -0
- data/vendor/heroicons/20/solid/arrow-left-circle.svg +3 -0
- data/vendor/heroicons/20/solid/arrow-left-end-on-rectangle.svg +4 -0
- data/vendor/heroicons/20/solid/arrow-left-on-rectangle.svg +4 -0
- data/vendor/heroicons/20/solid/arrow-left-start-on-rectangle.svg +4 -0
- data/vendor/heroicons/20/solid/arrow-left.svg +3 -0
- data/vendor/heroicons/20/solid/arrow-long-down.svg +3 -0
- data/vendor/heroicons/20/solid/arrow-long-left.svg +3 -0
- data/vendor/heroicons/20/solid/arrow-long-right.svg +3 -0
- data/vendor/heroicons/20/solid/arrow-long-up.svg +3 -0
- data/vendor/heroicons/20/solid/arrow-path-rounded-square.svg +3 -0
- data/vendor/heroicons/20/solid/arrow-path.svg +3 -0
- data/vendor/heroicons/20/solid/arrow-right-circle.svg +3 -0
- data/vendor/heroicons/20/solid/arrow-right-end-on-rectangle.svg +4 -0
- data/vendor/heroicons/20/solid/arrow-right-on-rectangle.svg +4 -0
- data/vendor/heroicons/20/solid/arrow-right-start-on-rectangle.svg +4 -0
- data/vendor/heroicons/20/solid/arrow-right.svg +3 -0
- data/vendor/heroicons/20/solid/arrow-small-down.svg +3 -0
- data/vendor/heroicons/20/solid/arrow-small-left.svg +3 -0
- data/vendor/heroicons/20/solid/arrow-small-right.svg +3 -0
- data/vendor/heroicons/20/solid/arrow-small-up.svg +3 -0
- data/vendor/heroicons/20/solid/arrow-top-right-on-square.svg +4 -0
- data/vendor/heroicons/20/solid/arrow-trending-down.svg +3 -0
- data/vendor/heroicons/20/solid/arrow-trending-up.svg +3 -0
- data/vendor/heroicons/20/solid/arrow-turn-down-left.svg +3 -0
- data/vendor/heroicons/20/solid/arrow-turn-down-right.svg +3 -0
- data/vendor/heroicons/20/solid/arrow-turn-left-down.svg +3 -0
- data/vendor/heroicons/20/solid/arrow-turn-left-up.svg +3 -0
- data/vendor/heroicons/20/solid/arrow-turn-right-down.svg +3 -0
- data/vendor/heroicons/20/solid/arrow-turn-right-up.svg +3 -0
- data/vendor/heroicons/20/solid/arrow-turn-up-left.svg +3 -0
- data/vendor/heroicons/20/solid/arrow-turn-up-right.svg +3 -0
- data/vendor/heroicons/20/solid/arrow-up-circle.svg +3 -0
- data/vendor/heroicons/20/solid/arrow-up-left.svg +3 -0
- data/vendor/heroicons/20/solid/arrow-up-on-square-stack.svg +3 -0
- data/vendor/heroicons/20/solid/arrow-up-on-square.svg +3 -0
- data/vendor/heroicons/20/solid/arrow-up-right.svg +3 -0
- data/vendor/heroicons/20/solid/arrow-up-tray.svg +4 -0
- data/vendor/heroicons/20/solid/arrow-up.svg +3 -0
- data/vendor/heroicons/20/solid/arrow-uturn-down.svg +3 -0
- data/vendor/heroicons/20/solid/arrow-uturn-left.svg +3 -0
- data/vendor/heroicons/20/solid/arrow-uturn-right.svg +3 -0
- data/vendor/heroicons/20/solid/arrow-uturn-up.svg +3 -0
- data/vendor/heroicons/20/solid/arrows-pointing-in.svg +3 -0
- data/vendor/heroicons/20/solid/arrows-pointing-out.svg +3 -0
- data/vendor/heroicons/20/solid/arrows-right-left.svg +3 -0
- data/vendor/heroicons/20/solid/arrows-up-down.svg +3 -0
- data/vendor/heroicons/20/solid/at-symbol.svg +3 -0
- data/vendor/heroicons/20/solid/backspace.svg +3 -0
- data/vendor/heroicons/20/solid/backward.svg +3 -0
- data/vendor/heroicons/20/solid/banknotes.svg +3 -0
- data/vendor/heroicons/20/solid/bars-2.svg +3 -0
- data/vendor/heroicons/20/solid/bars-3-bottom-left.svg +3 -0
- data/vendor/heroicons/20/solid/bars-3-bottom-right.svg +3 -0
- data/vendor/heroicons/20/solid/bars-3-center-left.svg +3 -0
- data/vendor/heroicons/20/solid/bars-3.svg +3 -0
- data/vendor/heroicons/20/solid/bars-4.svg +3 -0
- data/vendor/heroicons/20/solid/bars-arrow-down.svg +3 -0
- data/vendor/heroicons/20/solid/bars-arrow-up.svg +3 -0
- data/vendor/heroicons/20/solid/battery-0.svg +3 -0
- data/vendor/heroicons/20/solid/battery-100.svg +4 -0
- data/vendor/heroicons/20/solid/battery-50.svg +4 -0
- data/vendor/heroicons/20/solid/beaker.svg +3 -0
- data/vendor/heroicons/20/solid/bell-alert.svg +4 -0
- data/vendor/heroicons/20/solid/bell-slash.svg +3 -0
- data/vendor/heroicons/20/solid/bell-snooze.svg +3 -0
- data/vendor/heroicons/20/solid/bell.svg +3 -0
- data/vendor/heroicons/20/solid/bold.svg +3 -0
- data/vendor/heroicons/20/solid/bolt-slash.svg +4 -0
- data/vendor/heroicons/20/solid/bolt.svg +3 -0
- data/vendor/heroicons/20/solid/book-open.svg +3 -0
- data/vendor/heroicons/20/solid/bookmark-slash.svg +3 -0
- data/vendor/heroicons/20/solid/bookmark-square.svg +3 -0
- data/vendor/heroicons/20/solid/bookmark.svg +3 -0
- data/vendor/heroicons/20/solid/briefcase.svg +4 -0
- data/vendor/heroicons/20/solid/bug-ant.svg +3 -0
- data/vendor/heroicons/20/solid/building-library.svg +3 -0
- data/vendor/heroicons/20/solid/building-office-2.svg +3 -0
- data/vendor/heroicons/20/solid/building-office.svg +3 -0
- data/vendor/heroicons/20/solid/building-storefront.svg +3 -0
- data/vendor/heroicons/20/solid/cake.svg +3 -0
- data/vendor/heroicons/20/solid/calculator.svg +3 -0
- data/vendor/heroicons/20/solid/calendar-date-range.svg +4 -0
- data/vendor/heroicons/20/solid/calendar-days.svg +4 -0
- data/vendor/heroicons/20/solid/calendar.svg +3 -0
- data/vendor/heroicons/20/solid/camera.svg +3 -0
- data/vendor/heroicons/20/solid/chart-bar-square.svg +3 -0
- data/vendor/heroicons/20/solid/chart-bar.svg +3 -0
- data/vendor/heroicons/20/solid/chart-pie.svg +4 -0
- data/vendor/heroicons/20/solid/chat-bubble-bottom-center-text.svg +3 -0
- data/vendor/heroicons/20/solid/chat-bubble-bottom-center.svg +3 -0
- data/vendor/heroicons/20/solid/chat-bubble-left-ellipsis.svg +3 -0
- data/vendor/heroicons/20/solid/chat-bubble-left-right.svg +4 -0
- data/vendor/heroicons/20/solid/chat-bubble-left.svg +3 -0
- data/vendor/heroicons/20/solid/chat-bubble-oval-left-ellipsis.svg +3 -0
- data/vendor/heroicons/20/solid/chat-bubble-oval-left.svg +3 -0
- data/vendor/heroicons/20/solid/check-badge.svg +3 -0
- data/vendor/heroicons/20/solid/check-circle.svg +3 -0
- data/vendor/heroicons/20/solid/check.svg +3 -0
- data/vendor/heroicons/20/solid/chevron-double-down.svg +3 -0
- data/vendor/heroicons/20/solid/chevron-double-left.svg +3 -0
- data/vendor/heroicons/20/solid/chevron-double-right.svg +3 -0
- data/vendor/heroicons/20/solid/chevron-double-up.svg +3 -0
- data/vendor/heroicons/20/solid/chevron-down.svg +3 -0
- data/vendor/heroicons/20/solid/chevron-left.svg +3 -0
- data/vendor/heroicons/20/solid/chevron-right.svg +3 -0
- data/vendor/heroicons/20/solid/chevron-up-down.svg +3 -0
- data/vendor/heroicons/20/solid/chevron-up.svg +3 -0
- data/vendor/heroicons/20/solid/circle-stack.svg +3 -0
- data/vendor/heroicons/20/solid/clipboard-document-check.svg +4 -0
- data/vendor/heroicons/20/solid/clipboard-document-list.svg +4 -0
- data/vendor/heroicons/20/solid/clipboard-document.svg +4 -0
- data/vendor/heroicons/20/solid/clipboard.svg +3 -0
- data/vendor/heroicons/20/solid/clock.svg +3 -0
- data/vendor/heroicons/20/solid/cloud-arrow-down.svg +3 -0
- data/vendor/heroicons/20/solid/cloud-arrow-up.svg +3 -0
- data/vendor/heroicons/20/solid/cloud.svg +3 -0
- data/vendor/heroicons/20/solid/code-bracket-square.svg +3 -0
- data/vendor/heroicons/20/solid/code-bracket.svg +3 -0
- data/vendor/heroicons/20/solid/cog-6-tooth.svg +3 -0
- data/vendor/heroicons/20/solid/cog-8-tooth.svg +3 -0
- data/vendor/heroicons/20/solid/cog.svg +4 -0
- data/vendor/heroicons/20/solid/command-line.svg +3 -0
- data/vendor/heroicons/20/solid/computer-desktop.svg +3 -0
- data/vendor/heroicons/20/solid/cpu-chip.svg +4 -0
- data/vendor/heroicons/20/solid/credit-card.svg +3 -0
- data/vendor/heroicons/20/solid/cube-transparent.svg +3 -0
- data/vendor/heroicons/20/solid/cube.svg +3 -0
- data/vendor/heroicons/20/solid/currency-bangladeshi.svg +3 -0
- data/vendor/heroicons/20/solid/currency-dollar.svg +4 -0
- data/vendor/heroicons/20/solid/currency-euro.svg +3 -0
- data/vendor/heroicons/20/solid/currency-pound.svg +3 -0
- data/vendor/heroicons/20/solid/currency-rupee.svg +3 -0
- data/vendor/heroicons/20/solid/currency-yen.svg +3 -0
- data/vendor/heroicons/20/solid/cursor-arrow-rays.svg +3 -0
- data/vendor/heroicons/20/solid/cursor-arrow-ripple.svg +5 -0
- data/vendor/heroicons/20/solid/device-phone-mobile.svg +4 -0
- data/vendor/heroicons/20/solid/device-tablet.svg +3 -0
- data/vendor/heroicons/20/solid/divide.svg +3 -0
- data/vendor/heroicons/20/solid/document-arrow-down.svg +3 -0
- data/vendor/heroicons/20/solid/document-arrow-up.svg +3 -0
- data/vendor/heroicons/20/solid/document-chart-bar.svg +3 -0
- data/vendor/heroicons/20/solid/document-check.svg +3 -0
- data/vendor/heroicons/20/solid/document-currency-bangladeshi.svg +3 -0
- data/vendor/heroicons/20/solid/document-currency-dollar.svg +3 -0
- data/vendor/heroicons/20/solid/document-currency-euro.svg +3 -0
- data/vendor/heroicons/20/solid/document-currency-pound.svg +3 -0
- data/vendor/heroicons/20/solid/document-currency-rupee.svg +3 -0
- data/vendor/heroicons/20/solid/document-currency-yen.svg +3 -0
- data/vendor/heroicons/20/solid/document-duplicate.svg +4 -0
- data/vendor/heroicons/20/solid/document-magnifying-glass.svg +4 -0
- data/vendor/heroicons/20/solid/document-minus.svg +3 -0
- data/vendor/heroicons/20/solid/document-plus.svg +3 -0
- data/vendor/heroicons/20/solid/document-text.svg +3 -0
- data/vendor/heroicons/20/solid/document.svg +3 -0
- data/vendor/heroicons/20/solid/ellipsis-horizontal-circle.svg +3 -0
- data/vendor/heroicons/20/solid/ellipsis-horizontal.svg +3 -0
- data/vendor/heroicons/20/solid/ellipsis-vertical.svg +3 -0
- data/vendor/heroicons/20/solid/envelope-open.svg +3 -0
- data/vendor/heroicons/20/solid/envelope.svg +4 -0
- data/vendor/heroicons/20/solid/equals.svg +3 -0
- data/vendor/heroicons/20/solid/exclamation-circle.svg +3 -0
- data/vendor/heroicons/20/solid/exclamation-triangle.svg +3 -0
- data/vendor/heroicons/20/solid/eye-dropper.svg +3 -0
- data/vendor/heroicons/20/solid/eye-slash.svg +4 -0
- data/vendor/heroicons/20/solid/eye.svg +4 -0
- data/vendor/heroicons/20/solid/face-frown.svg +3 -0
- data/vendor/heroicons/20/solid/face-smile.svg +3 -0
- data/vendor/heroicons/20/solid/film.svg +3 -0
- data/vendor/heroicons/20/solid/finger-print.svg +3 -0
- data/vendor/heroicons/20/solid/fire.svg +3 -0
- data/vendor/heroicons/20/solid/flag.svg +3 -0
- data/vendor/heroicons/20/solid/folder-arrow-down.svg +3 -0
- data/vendor/heroicons/20/solid/folder-minus.svg +3 -0
- data/vendor/heroicons/20/solid/folder-open.svg +3 -0
- data/vendor/heroicons/20/solid/folder-plus.svg +3 -0
- data/vendor/heroicons/20/solid/folder.svg +3 -0
- data/vendor/heroicons/20/solid/forward.svg +3 -0
- data/vendor/heroicons/20/solid/funnel.svg +3 -0
- data/vendor/heroicons/20/solid/gif.svg +3 -0
- data/vendor/heroicons/20/solid/gift-top.svg +3 -0
- data/vendor/heroicons/20/solid/gift.svg +4 -0
- data/vendor/heroicons/20/solid/globe-alt.svg +3 -0
- data/vendor/heroicons/20/solid/globe-americas.svg +3 -0
- data/vendor/heroicons/20/solid/globe-asia-australia.svg +3 -0
- data/vendor/heroicons/20/solid/globe-europe-africa.svg +3 -0
- data/vendor/heroicons/20/solid/h1.svg +3 -0
- data/vendor/heroicons/20/solid/h2.svg +3 -0
- data/vendor/heroicons/20/solid/h3.svg +3 -0
- data/vendor/heroicons/20/solid/hand-raised.svg +3 -0
- data/vendor/heroicons/20/solid/hand-thumb-down.svg +3 -0
- data/vendor/heroicons/20/solid/hand-thumb-up.svg +3 -0
- data/vendor/heroicons/20/solid/hashtag.svg +3 -0
- data/vendor/heroicons/20/solid/heart.svg +3 -0
- data/vendor/heroicons/20/solid/home-modern.svg +3 -0
- data/vendor/heroicons/20/solid/home.svg +3 -0
- data/vendor/heroicons/20/solid/identification.svg +3 -0
- data/vendor/heroicons/20/solid/inbox-arrow-down.svg +4 -0
- data/vendor/heroicons/20/solid/inbox-stack.svg +4 -0
- data/vendor/heroicons/20/solid/inbox.svg +3 -0
- data/vendor/heroicons/20/solid/information-circle.svg +3 -0
- data/vendor/heroicons/20/solid/italic.svg +3 -0
- data/vendor/heroicons/20/solid/key.svg +3 -0
- data/vendor/heroicons/20/solid/language.svg +4 -0
- data/vendor/heroicons/20/solid/lifebuoy.svg +3 -0
- data/vendor/heroicons/20/solid/light-bulb.svg +3 -0
- data/vendor/heroicons/20/solid/link-slash.svg +3 -0
- data/vendor/heroicons/20/solid/link.svg +4 -0
- data/vendor/heroicons/20/solid/list-bullet.svg +3 -0
- data/vendor/heroicons/20/solid/lock-closed.svg +3 -0
- data/vendor/heroicons/20/solid/lock-open.svg +3 -0
- data/vendor/heroicons/20/solid/magnifying-glass-circle.svg +4 -0
- data/vendor/heroicons/20/solid/magnifying-glass-minus.svg +4 -0
- data/vendor/heroicons/20/solid/magnifying-glass-plus.svg +4 -0
- data/vendor/heroicons/20/solid/magnifying-glass.svg +3 -0
- data/vendor/heroicons/20/solid/map-pin.svg +3 -0
- data/vendor/heroicons/20/solid/map.svg +3 -0
- data/vendor/heroicons/20/solid/megaphone.svg +3 -0
- data/vendor/heroicons/20/solid/microphone.svg +4 -0
- data/vendor/heroicons/20/solid/minus-circle.svg +3 -0
- data/vendor/heroicons/20/solid/minus-small.svg +3 -0
- data/vendor/heroicons/20/solid/minus.svg +3 -0
- data/vendor/heroicons/20/solid/moon.svg +3 -0
- data/vendor/heroicons/20/solid/musical-note.svg +3 -0
- data/vendor/heroicons/20/solid/newspaper.svg +4 -0
- data/vendor/heroicons/20/solid/no-symbol.svg +3 -0
- data/vendor/heroicons/20/solid/numbered-list.svg +3 -0
- data/vendor/heroicons/20/solid/paint-brush.svg +3 -0
- data/vendor/heroicons/20/solid/paper-airplane.svg +3 -0
- data/vendor/heroicons/20/solid/paper-clip.svg +3 -0
- data/vendor/heroicons/20/solid/pause-circle.svg +3 -0
- data/vendor/heroicons/20/solid/pause.svg +3 -0
- data/vendor/heroicons/20/solid/pencil-square.svg +4 -0
- data/vendor/heroicons/20/solid/pencil.svg +3 -0
- data/vendor/heroicons/20/solid/percent-badge.svg +3 -0
- data/vendor/heroicons/20/solid/phone-arrow-down-left.svg +3 -0
- data/vendor/heroicons/20/solid/phone-arrow-up-right.svg +3 -0
- data/vendor/heroicons/20/solid/phone-x-mark.svg +3 -0
- data/vendor/heroicons/20/solid/phone.svg +3 -0
- data/vendor/heroicons/20/solid/photo.svg +3 -0
- data/vendor/heroicons/20/solid/play-circle.svg +3 -0
- data/vendor/heroicons/20/solid/play-pause.svg +3 -0
- data/vendor/heroicons/20/solid/play.svg +3 -0
- data/vendor/heroicons/20/solid/plus-circle.svg +3 -0
- data/vendor/heroicons/20/solid/plus-small.svg +3 -0
- data/vendor/heroicons/20/solid/plus.svg +3 -0
- data/vendor/heroicons/20/solid/power.svg +3 -0
- data/vendor/heroicons/20/solid/presentation-chart-bar.svg +3 -0
- data/vendor/heroicons/20/solid/presentation-chart-line.svg +3 -0
- data/vendor/heroicons/20/solid/printer.svg +3 -0
- data/vendor/heroicons/20/solid/puzzle-piece.svg +3 -0
- data/vendor/heroicons/20/solid/qr-code.svg +3 -0
- data/vendor/heroicons/20/solid/question-mark-circle.svg +3 -0
- data/vendor/heroicons/20/solid/queue-list.svg +3 -0
- data/vendor/heroicons/20/solid/radio.svg +3 -0
- data/vendor/heroicons/20/solid/receipt-percent.svg +3 -0
- data/vendor/heroicons/20/solid/receipt-refund.svg +3 -0
- data/vendor/heroicons/20/solid/rectangle-group.svg +3 -0
- data/vendor/heroicons/20/solid/rectangle-stack.svg +3 -0
- data/vendor/heroicons/20/solid/rocket-launch.svg +4 -0
- data/vendor/heroicons/20/solid/rss.svg +4 -0
- data/vendor/heroicons/20/solid/scale.svg +3 -0
- data/vendor/heroicons/20/solid/scissors.svg +4 -0
- data/vendor/heroicons/20/solid/server-stack.svg +4 -0
- data/vendor/heroicons/20/solid/server.svg +4 -0
- data/vendor/heroicons/20/solid/share.svg +3 -0
- data/vendor/heroicons/20/solid/shield-check.svg +3 -0
- data/vendor/heroicons/20/solid/shield-exclamation.svg +3 -0
- data/vendor/heroicons/20/solid/shopping-bag.svg +3 -0
- data/vendor/heroicons/20/solid/shopping-cart.svg +3 -0
- data/vendor/heroicons/20/solid/signal-slash.svg +3 -0
- data/vendor/heroicons/20/solid/signal.svg +4 -0
- data/vendor/heroicons/20/solid/slash.svg +3 -0
- data/vendor/heroicons/20/solid/sparkles.svg +3 -0
- data/vendor/heroicons/20/solid/speaker-wave.svg +4 -0
- data/vendor/heroicons/20/solid/speaker-x-mark.svg +3 -0
- data/vendor/heroicons/20/solid/square-2-stack.svg +4 -0
- data/vendor/heroicons/20/solid/square-3-stack-3d.svg +5 -0
- data/vendor/heroicons/20/solid/squares-2x2.svg +3 -0
- data/vendor/heroicons/20/solid/squares-plus.svg +3 -0
- data/vendor/heroicons/20/solid/star.svg +3 -0
- data/vendor/heroicons/20/solid/stop-circle.svg +3 -0
- data/vendor/heroicons/20/solid/stop.svg +3 -0
- data/vendor/heroicons/20/solid/strikethrough.svg +3 -0
- data/vendor/heroicons/20/solid/sun.svg +3 -0
- data/vendor/heroicons/20/solid/swatch.svg +3 -0
- data/vendor/heroicons/20/solid/table-cells.svg +3 -0
- data/vendor/heroicons/20/solid/tag.svg +3 -0
- data/vendor/heroicons/20/solid/ticket.svg +3 -0
- data/vendor/heroicons/20/solid/trash.svg +3 -0
- data/vendor/heroicons/20/solid/trophy.svg +3 -0
- data/vendor/heroicons/20/solid/truck.svg +4 -0
- data/vendor/heroicons/20/solid/tv.svg +4 -0
- data/vendor/heroicons/20/solid/underline.svg +3 -0
- data/vendor/heroicons/20/solid/user-circle.svg +3 -0
- data/vendor/heroicons/20/solid/user-group.svg +3 -0
- data/vendor/heroicons/20/solid/user-minus.svg +3 -0
- data/vendor/heroicons/20/solid/user-plus.svg +3 -0
- data/vendor/heroicons/20/solid/user.svg +3 -0
- data/vendor/heroicons/20/solid/users.svg +3 -0
- data/vendor/heroicons/20/solid/variable.svg +3 -0
- data/vendor/heroicons/20/solid/video-camera-slash.svg +3 -0
- data/vendor/heroicons/20/solid/video-camera.svg +3 -0
- data/vendor/heroicons/20/solid/view-columns.svg +3 -0
- data/vendor/heroicons/20/solid/viewfinder-circle.svg +3 -0
- data/vendor/heroicons/20/solid/wallet.svg +3 -0
- data/vendor/heroicons/20/solid/wifi.svg +3 -0
- data/vendor/heroicons/20/solid/window.svg +3 -0
- data/vendor/heroicons/20/solid/wrench-screwdriver.svg +4 -0
- data/vendor/heroicons/20/solid/wrench.svg +3 -0
- data/vendor/heroicons/20/solid/x-circle.svg +3 -0
- data/vendor/heroicons/20/solid/x-mark.svg +3 -0
- data/vendor/heroicons/24/outline/academic-cap.svg +3 -0
- data/vendor/heroicons/24/outline/adjustments-horizontal.svg +3 -0
- data/vendor/heroicons/24/outline/adjustments-vertical.svg +3 -0
- data/vendor/heroicons/24/outline/archive-box-arrow-down.svg +3 -0
- data/vendor/heroicons/24/outline/archive-box-x-mark.svg +3 -0
- data/vendor/heroicons/24/outline/archive-box.svg +3 -0
- data/vendor/heroicons/24/outline/arrow-down-circle.svg +3 -0
- data/vendor/heroicons/24/outline/arrow-down-left.svg +3 -0
- data/vendor/heroicons/24/outline/arrow-down-on-square-stack.svg +3 -0
- data/vendor/heroicons/24/outline/arrow-down-on-square.svg +3 -0
- data/vendor/heroicons/24/outline/arrow-down-right.svg +3 -0
- data/vendor/heroicons/24/outline/arrow-down-tray.svg +3 -0
- data/vendor/heroicons/24/outline/arrow-down.svg +3 -0
- data/vendor/heroicons/24/outline/arrow-left-circle.svg +3 -0
- data/vendor/heroicons/24/outline/arrow-left-end-on-rectangle.svg +3 -0
- data/vendor/heroicons/24/outline/arrow-left-on-rectangle.svg +3 -0
- data/vendor/heroicons/24/outline/arrow-left-start-on-rectangle.svg +3 -0
- data/vendor/heroicons/24/outline/arrow-left.svg +3 -0
- data/vendor/heroicons/24/outline/arrow-long-down.svg +3 -0
- data/vendor/heroicons/24/outline/arrow-long-left.svg +3 -0
- data/vendor/heroicons/24/outline/arrow-long-right.svg +3 -0
- data/vendor/heroicons/24/outline/arrow-long-up.svg +3 -0
- data/vendor/heroicons/24/outline/arrow-path-rounded-square.svg +3 -0
- data/vendor/heroicons/24/outline/arrow-path.svg +3 -0
- data/vendor/heroicons/24/outline/arrow-right-circle.svg +3 -0
- data/vendor/heroicons/24/outline/arrow-right-end-on-rectangle.svg +3 -0
- data/vendor/heroicons/24/outline/arrow-right-on-rectangle.svg +3 -0
- data/vendor/heroicons/24/outline/arrow-right-start-on-rectangle.svg +3 -0
- data/vendor/heroicons/24/outline/arrow-right.svg +3 -0
- data/vendor/heroicons/24/outline/arrow-small-down.svg +3 -0
- data/vendor/heroicons/24/outline/arrow-small-left.svg +3 -0
- data/vendor/heroicons/24/outline/arrow-small-right.svg +3 -0
- data/vendor/heroicons/24/outline/arrow-small-up.svg +3 -0
- data/vendor/heroicons/24/outline/arrow-top-right-on-square.svg +3 -0
- data/vendor/heroicons/24/outline/arrow-trending-down.svg +3 -0
- data/vendor/heroicons/24/outline/arrow-trending-up.svg +3 -0
- data/vendor/heroicons/24/outline/arrow-turn-down-left.svg +3 -0
- data/vendor/heroicons/24/outline/arrow-turn-down-right.svg +3 -0
- data/vendor/heroicons/24/outline/arrow-turn-left-down.svg +3 -0
- data/vendor/heroicons/24/outline/arrow-turn-left-up.svg +3 -0
- data/vendor/heroicons/24/outline/arrow-turn-right-down.svg +3 -0
- data/vendor/heroicons/24/outline/arrow-turn-right-up.svg +3 -0
- data/vendor/heroicons/24/outline/arrow-turn-up-left.svg +3 -0
- data/vendor/heroicons/24/outline/arrow-turn-up-right.svg +3 -0
- data/vendor/heroicons/24/outline/arrow-up-circle.svg +3 -0
- data/vendor/heroicons/24/outline/arrow-up-left.svg +3 -0
- data/vendor/heroicons/24/outline/arrow-up-on-square-stack.svg +3 -0
- data/vendor/heroicons/24/outline/arrow-up-on-square.svg +3 -0
- data/vendor/heroicons/24/outline/arrow-up-right.svg +3 -0
- data/vendor/heroicons/24/outline/arrow-up-tray.svg +3 -0
- data/vendor/heroicons/24/outline/arrow-up.svg +3 -0
- data/vendor/heroicons/24/outline/arrow-uturn-down.svg +3 -0
- data/vendor/heroicons/24/outline/arrow-uturn-left.svg +3 -0
- data/vendor/heroicons/24/outline/arrow-uturn-right.svg +3 -0
- data/vendor/heroicons/24/outline/arrow-uturn-up.svg +3 -0
- data/vendor/heroicons/24/outline/arrows-pointing-in.svg +3 -0
- data/vendor/heroicons/24/outline/arrows-pointing-out.svg +3 -0
- data/vendor/heroicons/24/outline/arrows-right-left.svg +3 -0
- data/vendor/heroicons/24/outline/arrows-up-down.svg +3 -0
- data/vendor/heroicons/24/outline/at-symbol.svg +3 -0
- data/vendor/heroicons/24/outline/backspace.svg +3 -0
- data/vendor/heroicons/24/outline/backward.svg +3 -0
- data/vendor/heroicons/24/outline/banknotes.svg +3 -0
- data/vendor/heroicons/24/outline/bars-2.svg +3 -0
- data/vendor/heroicons/24/outline/bars-3-bottom-left.svg +3 -0
- data/vendor/heroicons/24/outline/bars-3-bottom-right.svg +3 -0
- data/vendor/heroicons/24/outline/bars-3-center-left.svg +3 -0
- data/vendor/heroicons/24/outline/bars-3.svg +3 -0
- data/vendor/heroicons/24/outline/bars-4.svg +3 -0
- data/vendor/heroicons/24/outline/bars-arrow-down.svg +3 -0
- data/vendor/heroicons/24/outline/bars-arrow-up.svg +3 -0
- data/vendor/heroicons/24/outline/battery-0.svg +3 -0
- data/vendor/heroicons/24/outline/battery-100.svg +3 -0
- data/vendor/heroicons/24/outline/battery-50.svg +3 -0
- data/vendor/heroicons/24/outline/beaker.svg +3 -0
- data/vendor/heroicons/24/outline/bell-alert.svg +3 -0
- data/vendor/heroicons/24/outline/bell-slash.svg +3 -0
- data/vendor/heroicons/24/outline/bell-snooze.svg +3 -0
- data/vendor/heroicons/24/outline/bell.svg +3 -0
- data/vendor/heroicons/24/outline/bold.svg +3 -0
- data/vendor/heroicons/24/outline/bolt-slash.svg +3 -0
- data/vendor/heroicons/24/outline/bolt.svg +3 -0
- data/vendor/heroicons/24/outline/book-open.svg +3 -0
- data/vendor/heroicons/24/outline/bookmark-slash.svg +3 -0
- data/vendor/heroicons/24/outline/bookmark-square.svg +3 -0
- data/vendor/heroicons/24/outline/bookmark.svg +3 -0
- data/vendor/heroicons/24/outline/briefcase.svg +3 -0
- data/vendor/heroicons/24/outline/bug-ant.svg +3 -0
- data/vendor/heroicons/24/outline/building-library.svg +3 -0
- data/vendor/heroicons/24/outline/building-office-2.svg +3 -0
- data/vendor/heroicons/24/outline/building-office.svg +3 -0
- data/vendor/heroicons/24/outline/building-storefront.svg +3 -0
- data/vendor/heroicons/24/outline/cake.svg +3 -0
- data/vendor/heroicons/24/outline/calculator.svg +3 -0
- data/vendor/heroicons/24/outline/calendar-date-range.svg +3 -0
- data/vendor/heroicons/24/outline/calendar-days.svg +3 -0
- data/vendor/heroicons/24/outline/calendar.svg +3 -0
- data/vendor/heroicons/24/outline/camera.svg +4 -0
- data/vendor/heroicons/24/outline/chart-bar-square.svg +3 -0
- data/vendor/heroicons/24/outline/chart-bar.svg +3 -0
- data/vendor/heroicons/24/outline/chart-pie.svg +4 -0
- data/vendor/heroicons/24/outline/chat-bubble-bottom-center-text.svg +3 -0
- data/vendor/heroicons/24/outline/chat-bubble-bottom-center.svg +3 -0
- data/vendor/heroicons/24/outline/chat-bubble-left-ellipsis.svg +3 -0
- data/vendor/heroicons/24/outline/chat-bubble-left-right.svg +3 -0
- data/vendor/heroicons/24/outline/chat-bubble-left.svg +3 -0
- data/vendor/heroicons/24/outline/chat-bubble-oval-left-ellipsis.svg +3 -0
- data/vendor/heroicons/24/outline/chat-bubble-oval-left.svg +3 -0
- data/vendor/heroicons/24/outline/check-badge.svg +3 -0
- data/vendor/heroicons/24/outline/check-circle.svg +3 -0
- data/vendor/heroicons/24/outline/check.svg +3 -0
- data/vendor/heroicons/24/outline/chevron-double-down.svg +3 -0
- data/vendor/heroicons/24/outline/chevron-double-left.svg +3 -0
- data/vendor/heroicons/24/outline/chevron-double-right.svg +3 -0
- data/vendor/heroicons/24/outline/chevron-double-up.svg +4 -0
- data/vendor/heroicons/24/outline/chevron-down.svg +3 -0
- data/vendor/heroicons/24/outline/chevron-left.svg +3 -0
- data/vendor/heroicons/24/outline/chevron-right.svg +3 -0
- data/vendor/heroicons/24/outline/chevron-up-down.svg +3 -0
- data/vendor/heroicons/24/outline/chevron-up.svg +3 -0
- data/vendor/heroicons/24/outline/circle-stack.svg +3 -0
- data/vendor/heroicons/24/outline/clipboard-document-check.svg +3 -0
- data/vendor/heroicons/24/outline/clipboard-document-list.svg +3 -0
- data/vendor/heroicons/24/outline/clipboard-document.svg +3 -0
- data/vendor/heroicons/24/outline/clipboard.svg +3 -0
- data/vendor/heroicons/24/outline/clock.svg +3 -0
- data/vendor/heroicons/24/outline/cloud-arrow-down.svg +3 -0
- data/vendor/heroicons/24/outline/cloud-arrow-up.svg +3 -0
- data/vendor/heroicons/24/outline/cloud.svg +3 -0
- data/vendor/heroicons/24/outline/code-bracket-square.svg +3 -0
- data/vendor/heroicons/24/outline/code-bracket.svg +3 -0
- data/vendor/heroicons/24/outline/cog-6-tooth.svg +4 -0
- data/vendor/heroicons/24/outline/cog-8-tooth.svg +4 -0
- data/vendor/heroicons/24/outline/cog.svg +3 -0
- data/vendor/heroicons/24/outline/command-line.svg +3 -0
- data/vendor/heroicons/24/outline/computer-desktop.svg +3 -0
- data/vendor/heroicons/24/outline/cpu-chip.svg +3 -0
- data/vendor/heroicons/24/outline/credit-card.svg +3 -0
- data/vendor/heroicons/24/outline/cube-transparent.svg +3 -0
- data/vendor/heroicons/24/outline/cube.svg +3 -0
- data/vendor/heroicons/24/outline/currency-bangladeshi.svg +3 -0
- data/vendor/heroicons/24/outline/currency-dollar.svg +3 -0
- data/vendor/heroicons/24/outline/currency-euro.svg +3 -0
- data/vendor/heroicons/24/outline/currency-pound.svg +3 -0
- data/vendor/heroicons/24/outline/currency-rupee.svg +3 -0
- data/vendor/heroicons/24/outline/currency-yen.svg +3 -0
- data/vendor/heroicons/24/outline/cursor-arrow-rays.svg +3 -0
- data/vendor/heroicons/24/outline/cursor-arrow-ripple.svg +3 -0
- data/vendor/heroicons/24/outline/device-phone-mobile.svg +3 -0
- data/vendor/heroicons/24/outline/device-tablet.svg +3 -0
- data/vendor/heroicons/24/outline/divide.svg +3 -0
- data/vendor/heroicons/24/outline/document-arrow-down.svg +3 -0
- data/vendor/heroicons/24/outline/document-arrow-up.svg +3 -0
- data/vendor/heroicons/24/outline/document-chart-bar.svg +3 -0
- data/vendor/heroicons/24/outline/document-check.svg +3 -0
- data/vendor/heroicons/24/outline/document-currency-bangladeshi.svg +3 -0
- data/vendor/heroicons/24/outline/document-currency-dollar.svg +3 -0
- data/vendor/heroicons/24/outline/document-currency-euro.svg +3 -0
- data/vendor/heroicons/24/outline/document-currency-pound.svg +3 -0
- data/vendor/heroicons/24/outline/document-currency-rupee.svg +3 -0
- data/vendor/heroicons/24/outline/document-currency-yen.svg +3 -0
- data/vendor/heroicons/24/outline/document-duplicate.svg +3 -0
- data/vendor/heroicons/24/outline/document-magnifying-glass.svg +3 -0
- data/vendor/heroicons/24/outline/document-minus.svg +3 -0
- data/vendor/heroicons/24/outline/document-plus.svg +3 -0
- data/vendor/heroicons/24/outline/document-text.svg +3 -0
- data/vendor/heroicons/24/outline/document.svg +3 -0
- data/vendor/heroicons/24/outline/ellipsis-horizontal-circle.svg +3 -0
- data/vendor/heroicons/24/outline/ellipsis-horizontal.svg +3 -0
- data/vendor/heroicons/24/outline/ellipsis-vertical.svg +3 -0
- data/vendor/heroicons/24/outline/envelope-open.svg +3 -0
- data/vendor/heroicons/24/outline/envelope.svg +3 -0
- data/vendor/heroicons/24/outline/equals.svg +3 -0
- data/vendor/heroicons/24/outline/exclamation-circle.svg +3 -0
- data/vendor/heroicons/24/outline/exclamation-triangle.svg +3 -0
- data/vendor/heroicons/24/outline/eye-dropper.svg +3 -0
- data/vendor/heroicons/24/outline/eye-slash.svg +3 -0
- data/vendor/heroicons/24/outline/eye.svg +4 -0
- data/vendor/heroicons/24/outline/face-frown.svg +3 -0
- data/vendor/heroicons/24/outline/face-smile.svg +3 -0
- data/vendor/heroicons/24/outline/film.svg +3 -0
- data/vendor/heroicons/24/outline/finger-print.svg +3 -0
- data/vendor/heroicons/24/outline/fire.svg +4 -0
- data/vendor/heroicons/24/outline/flag.svg +3 -0
- data/vendor/heroicons/24/outline/folder-arrow-down.svg +3 -0
- data/vendor/heroicons/24/outline/folder-minus.svg +3 -0
- data/vendor/heroicons/24/outline/folder-open.svg +3 -0
- data/vendor/heroicons/24/outline/folder-plus.svg +3 -0
- data/vendor/heroicons/24/outline/folder.svg +3 -0
- data/vendor/heroicons/24/outline/forward.svg +3 -0
- data/vendor/heroicons/24/outline/funnel.svg +3 -0
- data/vendor/heroicons/24/outline/gif.svg +3 -0
- data/vendor/heroicons/24/outline/gift-top.svg +3 -0
- data/vendor/heroicons/24/outline/gift.svg +3 -0
- data/vendor/heroicons/24/outline/globe-alt.svg +3 -0
- data/vendor/heroicons/24/outline/globe-americas.svg +3 -0
- data/vendor/heroicons/24/outline/globe-asia-australia.svg +3 -0
- data/vendor/heroicons/24/outline/globe-europe-africa.svg +3 -0
- data/vendor/heroicons/24/outline/h1.svg +3 -0
- data/vendor/heroicons/24/outline/h2.svg +3 -0
- data/vendor/heroicons/24/outline/h3.svg +3 -0
- data/vendor/heroicons/24/outline/hand-raised.svg +3 -0
- data/vendor/heroicons/24/outline/hand-thumb-down.svg +3 -0
- data/vendor/heroicons/24/outline/hand-thumb-up.svg +3 -0
- data/vendor/heroicons/24/outline/hashtag.svg +3 -0
- data/vendor/heroicons/24/outline/heart.svg +3 -0
- data/vendor/heroicons/24/outline/home-modern.svg +3 -0
- data/vendor/heroicons/24/outline/home.svg +3 -0
- data/vendor/heroicons/24/outline/identification.svg +3 -0
- data/vendor/heroicons/24/outline/inbox-arrow-down.svg +3 -0
- data/vendor/heroicons/24/outline/inbox-stack.svg +3 -0
- data/vendor/heroicons/24/outline/inbox.svg +3 -0
- data/vendor/heroicons/24/outline/information-circle.svg +3 -0
- data/vendor/heroicons/24/outline/italic.svg +3 -0
- data/vendor/heroicons/24/outline/key.svg +3 -0
- data/vendor/heroicons/24/outline/language.svg +3 -0
- data/vendor/heroicons/24/outline/lifebuoy.svg +3 -0
- data/vendor/heroicons/24/outline/light-bulb.svg +3 -0
- data/vendor/heroicons/24/outline/link-slash.svg +3 -0
- data/vendor/heroicons/24/outline/link.svg +3 -0
- data/vendor/heroicons/24/outline/list-bullet.svg +3 -0
- data/vendor/heroicons/24/outline/lock-closed.svg +3 -0
- data/vendor/heroicons/24/outline/lock-open.svg +3 -0
- data/vendor/heroicons/24/outline/magnifying-glass-circle.svg +3 -0
- data/vendor/heroicons/24/outline/magnifying-glass-minus.svg +3 -0
- data/vendor/heroicons/24/outline/magnifying-glass-plus.svg +3 -0
- data/vendor/heroicons/24/outline/magnifying-glass.svg +3 -0
- data/vendor/heroicons/24/outline/map-pin.svg +4 -0
- data/vendor/heroicons/24/outline/map.svg +3 -0
- data/vendor/heroicons/24/outline/megaphone.svg +3 -0
- data/vendor/heroicons/24/outline/microphone.svg +3 -0
- data/vendor/heroicons/24/outline/minus-circle.svg +3 -0
- data/vendor/heroicons/24/outline/minus-small.svg +3 -0
- data/vendor/heroicons/24/outline/minus.svg +3 -0
- data/vendor/heroicons/24/outline/moon.svg +3 -0
- data/vendor/heroicons/24/outline/musical-note.svg +3 -0
- data/vendor/heroicons/24/outline/newspaper.svg +3 -0
- data/vendor/heroicons/24/outline/no-symbol.svg +3 -0
- data/vendor/heroicons/24/outline/numbered-list.svg +3 -0
- data/vendor/heroicons/24/outline/paint-brush.svg +3 -0
- data/vendor/heroicons/24/outline/paper-airplane.svg +3 -0
- data/vendor/heroicons/24/outline/paper-clip.svg +3 -0
- data/vendor/heroicons/24/outline/pause-circle.svg +3 -0
- data/vendor/heroicons/24/outline/pause.svg +3 -0
- data/vendor/heroicons/24/outline/pencil-square.svg +3 -0
- data/vendor/heroicons/24/outline/pencil.svg +3 -0
- data/vendor/heroicons/24/outline/percent-badge.svg +3 -0
- data/vendor/heroicons/24/outline/phone-arrow-down-left.svg +3 -0
- data/vendor/heroicons/24/outline/phone-arrow-up-right.svg +3 -0
- data/vendor/heroicons/24/outline/phone-x-mark.svg +3 -0
- data/vendor/heroicons/24/outline/phone.svg +3 -0
- data/vendor/heroicons/24/outline/photo.svg +3 -0
- data/vendor/heroicons/24/outline/play-circle.svg +4 -0
- data/vendor/heroicons/24/outline/play-pause.svg +3 -0
- data/vendor/heroicons/24/outline/play.svg +3 -0
- data/vendor/heroicons/24/outline/plus-circle.svg +3 -0
- data/vendor/heroicons/24/outline/plus-small.svg +3 -0
- data/vendor/heroicons/24/outline/plus.svg +3 -0
- data/vendor/heroicons/24/outline/power.svg +3 -0
- data/vendor/heroicons/24/outline/presentation-chart-bar.svg +3 -0
- data/vendor/heroicons/24/outline/presentation-chart-line.svg +3 -0
- data/vendor/heroicons/24/outline/printer.svg +3 -0
- data/vendor/heroicons/24/outline/puzzle-piece.svg +3 -0
- data/vendor/heroicons/24/outline/qr-code.svg +4 -0
- data/vendor/heroicons/24/outline/question-mark-circle.svg +3 -0
- data/vendor/heroicons/24/outline/queue-list.svg +3 -0
- data/vendor/heroicons/24/outline/radio.svg +3 -0
- data/vendor/heroicons/24/outline/receipt-percent.svg +3 -0
- data/vendor/heroicons/24/outline/receipt-refund.svg +3 -0
- data/vendor/heroicons/24/outline/rectangle-group.svg +3 -0
- data/vendor/heroicons/24/outline/rectangle-stack.svg +3 -0
- data/vendor/heroicons/24/outline/rocket-launch.svg +3 -0
- data/vendor/heroicons/24/outline/rss.svg +3 -0
- data/vendor/heroicons/24/outline/scale.svg +3 -0
- data/vendor/heroicons/24/outline/scissors.svg +3 -0
- data/vendor/heroicons/24/outline/server-stack.svg +3 -0
- data/vendor/heroicons/24/outline/server.svg +3 -0
- data/vendor/heroicons/24/outline/share.svg +3 -0
- data/vendor/heroicons/24/outline/shield-check.svg +3 -0
- data/vendor/heroicons/24/outline/shield-exclamation.svg +3 -0
- data/vendor/heroicons/24/outline/shopping-bag.svg +3 -0
- data/vendor/heroicons/24/outline/shopping-cart.svg +3 -0
- data/vendor/heroicons/24/outline/signal-slash.svg +3 -0
- data/vendor/heroicons/24/outline/signal.svg +3 -0
- data/vendor/heroicons/24/outline/slash.svg +3 -0
- data/vendor/heroicons/24/outline/sparkles.svg +3 -0
- data/vendor/heroicons/24/outline/speaker-wave.svg +3 -0
- data/vendor/heroicons/24/outline/speaker-x-mark.svg +3 -0
- data/vendor/heroicons/24/outline/square-2-stack.svg +3 -0
- data/vendor/heroicons/24/outline/square-3-stack-3d.svg +3 -0
- data/vendor/heroicons/24/outline/squares-2x2.svg +3 -0
- data/vendor/heroicons/24/outline/squares-plus.svg +3 -0
- data/vendor/heroicons/24/outline/star.svg +3 -0
- data/vendor/heroicons/24/outline/stop-circle.svg +4 -0
- data/vendor/heroicons/24/outline/stop.svg +3 -0
- data/vendor/heroicons/24/outline/strikethrough.svg +3 -0
- data/vendor/heroicons/24/outline/sun.svg +3 -0
- data/vendor/heroicons/24/outline/swatch.svg +3 -0
- data/vendor/heroicons/24/outline/table-cells.svg +3 -0
- data/vendor/heroicons/24/outline/tag.svg +4 -0
- data/vendor/heroicons/24/outline/ticket.svg +3 -0
- data/vendor/heroicons/24/outline/trash.svg +3 -0
- data/vendor/heroicons/24/outline/trophy.svg +3 -0
- data/vendor/heroicons/24/outline/truck.svg +3 -0
- data/vendor/heroicons/24/outline/tv.svg +3 -0
- data/vendor/heroicons/24/outline/underline.svg +3 -0
- data/vendor/heroicons/24/outline/user-circle.svg +3 -0
- data/vendor/heroicons/24/outline/user-group.svg +3 -0
- data/vendor/heroicons/24/outline/user-minus.svg +3 -0
- data/vendor/heroicons/24/outline/user-plus.svg +3 -0
- data/vendor/heroicons/24/outline/user.svg +3 -0
- data/vendor/heroicons/24/outline/users.svg +3 -0
- data/vendor/heroicons/24/outline/variable.svg +3 -0
- data/vendor/heroicons/24/outline/video-camera-slash.svg +3 -0
- data/vendor/heroicons/24/outline/video-camera.svg +3 -0
- data/vendor/heroicons/24/outline/view-columns.svg +3 -0
- data/vendor/heroicons/24/outline/viewfinder-circle.svg +3 -0
- data/vendor/heroicons/24/outline/wallet.svg +3 -0
- data/vendor/heroicons/24/outline/wifi.svg +3 -0
- data/vendor/heroicons/24/outline/window.svg +3 -0
- data/vendor/heroicons/24/outline/wrench-screwdriver.svg +3 -0
- data/vendor/heroicons/24/outline/wrench.svg +4 -0
- data/vendor/heroicons/24/outline/x-circle.svg +3 -0
- data/vendor/heroicons/24/outline/x-mark.svg +3 -0
- data/vendor/heroicons/24/solid/academic-cap.svg +5 -0
- data/vendor/heroicons/24/solid/adjustments-horizontal.svg +3 -0
- data/vendor/heroicons/24/solid/adjustments-vertical.svg +3 -0
- data/vendor/heroicons/24/solid/archive-box-arrow-down.svg +4 -0
- data/vendor/heroicons/24/solid/archive-box-x-mark.svg +4 -0
- data/vendor/heroicons/24/solid/archive-box.svg +4 -0
- data/vendor/heroicons/24/solid/arrow-down-circle.svg +3 -0
- data/vendor/heroicons/24/solid/arrow-down-left.svg +3 -0
- data/vendor/heroicons/24/solid/arrow-down-on-square-stack.svg +4 -0
- data/vendor/heroicons/24/solid/arrow-down-on-square.svg +3 -0
- data/vendor/heroicons/24/solid/arrow-down-right.svg +3 -0
- data/vendor/heroicons/24/solid/arrow-down-tray.svg +3 -0
- data/vendor/heroicons/24/solid/arrow-down.svg +3 -0
- data/vendor/heroicons/24/solid/arrow-left-circle.svg +3 -0
- data/vendor/heroicons/24/solid/arrow-left-end-on-rectangle.svg +3 -0
- data/vendor/heroicons/24/solid/arrow-left-on-rectangle.svg +3 -0
- data/vendor/heroicons/24/solid/arrow-left-start-on-rectangle.svg +3 -0
- data/vendor/heroicons/24/solid/arrow-left.svg +3 -0
- data/vendor/heroicons/24/solid/arrow-long-down.svg +3 -0
- data/vendor/heroicons/24/solid/arrow-long-left.svg +3 -0
- data/vendor/heroicons/24/solid/arrow-long-right.svg +3 -0
- data/vendor/heroicons/24/solid/arrow-long-up.svg +3 -0
- data/vendor/heroicons/24/solid/arrow-path-rounded-square.svg +3 -0
- data/vendor/heroicons/24/solid/arrow-path.svg +3 -0
- data/vendor/heroicons/24/solid/arrow-right-circle.svg +3 -0
- data/vendor/heroicons/24/solid/arrow-right-end-on-rectangle.svg +3 -0
- data/vendor/heroicons/24/solid/arrow-right-on-rectangle.svg +3 -0
- data/vendor/heroicons/24/solid/arrow-right-start-on-rectangle.svg +3 -0
- data/vendor/heroicons/24/solid/arrow-right.svg +3 -0
- data/vendor/heroicons/24/solid/arrow-small-down.svg +3 -0
- data/vendor/heroicons/24/solid/arrow-small-left.svg +3 -0
- data/vendor/heroicons/24/solid/arrow-small-right.svg +3 -0
- data/vendor/heroicons/24/solid/arrow-small-up.svg +3 -0
- data/vendor/heroicons/24/solid/arrow-top-right-on-square.svg +3 -0
- data/vendor/heroicons/24/solid/arrow-trending-down.svg +3 -0
- data/vendor/heroicons/24/solid/arrow-trending-up.svg +3 -0
- data/vendor/heroicons/24/solid/arrow-turn-down-left.svg +3 -0
- data/vendor/heroicons/24/solid/arrow-turn-down-right.svg +3 -0
- data/vendor/heroicons/24/solid/arrow-turn-left-down.svg +3 -0
- data/vendor/heroicons/24/solid/arrow-turn-left-up.svg +3 -0
- data/vendor/heroicons/24/solid/arrow-turn-right-down.svg +3 -0
- data/vendor/heroicons/24/solid/arrow-turn-right-up.svg +3 -0
- data/vendor/heroicons/24/solid/arrow-turn-up-left.svg +3 -0
- data/vendor/heroicons/24/solid/arrow-turn-up-right.svg +3 -0
- data/vendor/heroicons/24/solid/arrow-up-circle.svg +3 -0
- data/vendor/heroicons/24/solid/arrow-up-left.svg +3 -0
- data/vendor/heroicons/24/solid/arrow-up-on-square-stack.svg +4 -0
- data/vendor/heroicons/24/solid/arrow-up-on-square.svg +3 -0
- data/vendor/heroicons/24/solid/arrow-up-right.svg +3 -0
- data/vendor/heroicons/24/solid/arrow-up-tray.svg +3 -0
- data/vendor/heroicons/24/solid/arrow-up.svg +3 -0
- data/vendor/heroicons/24/solid/arrow-uturn-down.svg +3 -0
- data/vendor/heroicons/24/solid/arrow-uturn-left.svg +3 -0
- data/vendor/heroicons/24/solid/arrow-uturn-right.svg +3 -0
- data/vendor/heroicons/24/solid/arrow-uturn-up.svg +3 -0
- data/vendor/heroicons/24/solid/arrows-pointing-in.svg +3 -0
- data/vendor/heroicons/24/solid/arrows-pointing-out.svg +3 -0
- data/vendor/heroicons/24/solid/arrows-right-left.svg +3 -0
- data/vendor/heroicons/24/solid/arrows-up-down.svg +3 -0
- data/vendor/heroicons/24/solid/at-symbol.svg +3 -0
- data/vendor/heroicons/24/solid/backspace.svg +3 -0
- data/vendor/heroicons/24/solid/backward.svg +3 -0
- data/vendor/heroicons/24/solid/banknotes.svg +5 -0
- data/vendor/heroicons/24/solid/bars-2.svg +3 -0
- data/vendor/heroicons/24/solid/bars-3-bottom-left.svg +3 -0
- data/vendor/heroicons/24/solid/bars-3-bottom-right.svg +3 -0
- data/vendor/heroicons/24/solid/bars-3-center-left.svg +3 -0
- data/vendor/heroicons/24/solid/bars-3.svg +3 -0
- data/vendor/heroicons/24/solid/bars-4.svg +3 -0
- data/vendor/heroicons/24/solid/bars-arrow-down.svg +3 -0
- data/vendor/heroicons/24/solid/bars-arrow-up.svg +3 -0
- data/vendor/heroicons/24/solid/battery-0.svg +3 -0
- data/vendor/heroicons/24/solid/battery-100.svg +3 -0
- data/vendor/heroicons/24/solid/battery-50.svg +4 -0
- data/vendor/heroicons/24/solid/beaker.svg +3 -0
- data/vendor/heroicons/24/solid/bell-alert.svg +4 -0
- data/vendor/heroicons/24/solid/bell-slash.svg +4 -0
- data/vendor/heroicons/24/solid/bell-snooze.svg +3 -0
- data/vendor/heroicons/24/solid/bell.svg +3 -0
- data/vendor/heroicons/24/solid/bold.svg +3 -0
- data/vendor/heroicons/24/solid/bolt-slash.svg +3 -0
- data/vendor/heroicons/24/solid/bolt.svg +3 -0
- data/vendor/heroicons/24/solid/book-open.svg +3 -0
- data/vendor/heroicons/24/solid/bookmark-slash.svg +3 -0
- data/vendor/heroicons/24/solid/bookmark-square.svg +3 -0
- data/vendor/heroicons/24/solid/bookmark.svg +3 -0
- data/vendor/heroicons/24/solid/briefcase.svg +4 -0
- data/vendor/heroicons/24/solid/bug-ant.svg +3 -0
- data/vendor/heroicons/24/solid/building-library.svg +5 -0
- data/vendor/heroicons/24/solid/building-office-2.svg +3 -0
- data/vendor/heroicons/24/solid/building-office.svg +3 -0
- data/vendor/heroicons/24/solid/building-storefront.svg +4 -0
- data/vendor/heroicons/24/solid/cake.svg +3 -0
- data/vendor/heroicons/24/solid/calculator.svg +3 -0
- data/vendor/heroicons/24/solid/calendar-date-range.svg +4 -0
- data/vendor/heroicons/24/solid/calendar-days.svg +4 -0
- data/vendor/heroicons/24/solid/calendar.svg +3 -0
- data/vendor/heroicons/24/solid/camera.svg +4 -0
- data/vendor/heroicons/24/solid/chart-bar-square.svg +3 -0
- data/vendor/heroicons/24/solid/chart-bar.svg +3 -0
- data/vendor/heroicons/24/solid/chart-pie.svg +4 -0
- data/vendor/heroicons/24/solid/chat-bubble-bottom-center-text.svg +3 -0
- data/vendor/heroicons/24/solid/chat-bubble-bottom-center.svg +3 -0
- data/vendor/heroicons/24/solid/chat-bubble-left-ellipsis.svg +3 -0
- data/vendor/heroicons/24/solid/chat-bubble-left-right.svg +4 -0
- data/vendor/heroicons/24/solid/chat-bubble-left.svg +3 -0
- data/vendor/heroicons/24/solid/chat-bubble-oval-left-ellipsis.svg +3 -0
- data/vendor/heroicons/24/solid/chat-bubble-oval-left.svg +3 -0
- data/vendor/heroicons/24/solid/check-badge.svg +3 -0
- data/vendor/heroicons/24/solid/check-circle.svg +3 -0
- data/vendor/heroicons/24/solid/check.svg +3 -0
- data/vendor/heroicons/24/solid/chevron-double-down.svg +4 -0
- data/vendor/heroicons/24/solid/chevron-double-left.svg +4 -0
- data/vendor/heroicons/24/solid/chevron-double-right.svg +4 -0
- data/vendor/heroicons/24/solid/chevron-double-up.svg +4 -0
- data/vendor/heroicons/24/solid/chevron-down.svg +3 -0
- data/vendor/heroicons/24/solid/chevron-left.svg +3 -0
- data/vendor/heroicons/24/solid/chevron-right.svg +3 -0
- data/vendor/heroicons/24/solid/chevron-up-down.svg +3 -0
- data/vendor/heroicons/24/solid/chevron-up.svg +3 -0
- data/vendor/heroicons/24/solid/circle-stack.svg +6 -0
- data/vendor/heroicons/24/solid/clipboard-document-check.svg +4 -0
- data/vendor/heroicons/24/solid/clipboard-document-list.svg +4 -0
- data/vendor/heroicons/24/solid/clipboard-document.svg +5 -0
- data/vendor/heroicons/24/solid/clipboard.svg +3 -0
- data/vendor/heroicons/24/solid/clock.svg +3 -0
- data/vendor/heroicons/24/solid/cloud-arrow-down.svg +3 -0
- data/vendor/heroicons/24/solid/cloud-arrow-up.svg +3 -0
- data/vendor/heroicons/24/solid/cloud.svg +3 -0
- data/vendor/heroicons/24/solid/code-bracket-square.svg +3 -0
- data/vendor/heroicons/24/solid/code-bracket.svg +3 -0
- data/vendor/heroicons/24/solid/cog-6-tooth.svg +3 -0
- data/vendor/heroicons/24/solid/cog-8-tooth.svg +3 -0
- data/vendor/heroicons/24/solid/cog.svg +4 -0
- data/vendor/heroicons/24/solid/command-line.svg +3 -0
- data/vendor/heroicons/24/solid/computer-desktop.svg +3 -0
- data/vendor/heroicons/24/solid/cpu-chip.svg +4 -0
- data/vendor/heroicons/24/solid/credit-card.svg +4 -0
- data/vendor/heroicons/24/solid/cube-transparent.svg +3 -0
- data/vendor/heroicons/24/solid/cube.svg +3 -0
- data/vendor/heroicons/24/solid/currency-bangladeshi.svg +3 -0
- data/vendor/heroicons/24/solid/currency-dollar.svg +4 -0
- data/vendor/heroicons/24/solid/currency-euro.svg +3 -0
- data/vendor/heroicons/24/solid/currency-pound.svg +3 -0
- data/vendor/heroicons/24/solid/currency-rupee.svg +3 -0
- data/vendor/heroicons/24/solid/currency-yen.svg +3 -0
- data/vendor/heroicons/24/solid/cursor-arrow-rays.svg +3 -0
- data/vendor/heroicons/24/solid/cursor-arrow-ripple.svg +3 -0
- data/vendor/heroicons/24/solid/device-phone-mobile.svg +4 -0
- data/vendor/heroicons/24/solid/device-tablet.svg +4 -0
- data/vendor/heroicons/24/solid/divide.svg +3 -0
- data/vendor/heroicons/24/solid/document-arrow-down.svg +4 -0
- data/vendor/heroicons/24/solid/document-arrow-up.svg +4 -0
- data/vendor/heroicons/24/solid/document-chart-bar.svg +4 -0
- data/vendor/heroicons/24/solid/document-check.svg +4 -0
- data/vendor/heroicons/24/solid/document-currency-bangladeshi.svg +3 -0
- data/vendor/heroicons/24/solid/document-currency-dollar.svg +3 -0
- data/vendor/heroicons/24/solid/document-currency-euro.svg +4 -0
- data/vendor/heroicons/24/solid/document-currency-pound.svg +3 -0
- data/vendor/heroicons/24/solid/document-currency-rupee.svg +3 -0
- data/vendor/heroicons/24/solid/document-currency-yen.svg +3 -0
- data/vendor/heroicons/24/solid/document-duplicate.svg +4 -0
- data/vendor/heroicons/24/solid/document-magnifying-glass.svg +5 -0
- data/vendor/heroicons/24/solid/document-minus.svg +4 -0
- data/vendor/heroicons/24/solid/document-plus.svg +4 -0
- data/vendor/heroicons/24/solid/document-text.svg +4 -0
- data/vendor/heroicons/24/solid/document.svg +4 -0
- data/vendor/heroicons/24/solid/ellipsis-horizontal-circle.svg +3 -0
- data/vendor/heroicons/24/solid/ellipsis-horizontal.svg +3 -0
- data/vendor/heroicons/24/solid/ellipsis-vertical.svg +3 -0
- data/vendor/heroicons/24/solid/envelope-open.svg +4 -0
- data/vendor/heroicons/24/solid/envelope.svg +4 -0
- data/vendor/heroicons/24/solid/equals.svg +3 -0
- data/vendor/heroicons/24/solid/exclamation-circle.svg +3 -0
- data/vendor/heroicons/24/solid/exclamation-triangle.svg +3 -0
- data/vendor/heroicons/24/solid/eye-dropper.svg +3 -0
- data/vendor/heroicons/24/solid/eye-slash.svg +5 -0
- data/vendor/heroicons/24/solid/eye.svg +4 -0
- data/vendor/heroicons/24/solid/face-frown.svg +3 -0
- data/vendor/heroicons/24/solid/face-smile.svg +3 -0
- data/vendor/heroicons/24/solid/film.svg +3 -0
- data/vendor/heroicons/24/solid/finger-print.svg +3 -0
- data/vendor/heroicons/24/solid/fire.svg +3 -0
- data/vendor/heroicons/24/solid/flag.svg +3 -0
- data/vendor/heroicons/24/solid/folder-arrow-down.svg +3 -0
- data/vendor/heroicons/24/solid/folder-minus.svg +3 -0
- data/vendor/heroicons/24/solid/folder-open.svg +3 -0
- data/vendor/heroicons/24/solid/folder-plus.svg +3 -0
- data/vendor/heroicons/24/solid/folder.svg +3 -0
- data/vendor/heroicons/24/solid/forward.svg +3 -0
- data/vendor/heroicons/24/solid/funnel.svg +3 -0
- data/vendor/heroicons/24/solid/gif.svg +3 -0
- data/vendor/heroicons/24/solid/gift-top.svg +4 -0
- data/vendor/heroicons/24/solid/gift.svg +3 -0
- data/vendor/heroicons/24/solid/globe-alt.svg +3 -0
- data/vendor/heroicons/24/solid/globe-americas.svg +3 -0
- data/vendor/heroicons/24/solid/globe-asia-australia.svg +4 -0
- data/vendor/heroicons/24/solid/globe-europe-africa.svg +3 -0
- data/vendor/heroicons/24/solid/h1.svg +3 -0
- data/vendor/heroicons/24/solid/h2.svg +3 -0
- data/vendor/heroicons/24/solid/h3.svg +3 -0
- data/vendor/heroicons/24/solid/hand-raised.svg +3 -0
- data/vendor/heroicons/24/solid/hand-thumb-down.svg +3 -0
- data/vendor/heroicons/24/solid/hand-thumb-up.svg +3 -0
- data/vendor/heroicons/24/solid/hashtag.svg +3 -0
- data/vendor/heroicons/24/solid/heart.svg +3 -0
- data/vendor/heroicons/24/solid/home-modern.svg +4 -0
- data/vendor/heroicons/24/solid/home.svg +4 -0
- data/vendor/heroicons/24/solid/identification.svg +3 -0
- data/vendor/heroicons/24/solid/inbox-arrow-down.svg +4 -0
- data/vendor/heroicons/24/solid/inbox-stack.svg +4 -0
- data/vendor/heroicons/24/solid/inbox.svg +3 -0
- data/vendor/heroicons/24/solid/information-circle.svg +3 -0
- data/vendor/heroicons/24/solid/italic.svg +3 -0
- data/vendor/heroicons/24/solid/key.svg +3 -0
- data/vendor/heroicons/24/solid/language.svg +3 -0
- data/vendor/heroicons/24/solid/lifebuoy.svg +3 -0
- data/vendor/heroicons/24/solid/light-bulb.svg +4 -0
- data/vendor/heroicons/24/solid/link-slash.svg +3 -0
- data/vendor/heroicons/24/solid/link.svg +3 -0
- data/vendor/heroicons/24/solid/list-bullet.svg +3 -0
- data/vendor/heroicons/24/solid/lock-closed.svg +3 -0
- data/vendor/heroicons/24/solid/lock-open.svg +3 -0
- data/vendor/heroicons/24/solid/magnifying-glass-circle.svg +4 -0
- data/vendor/heroicons/24/solid/magnifying-glass-minus.svg +3 -0
- data/vendor/heroicons/24/solid/magnifying-glass-plus.svg +3 -0
- data/vendor/heroicons/24/solid/magnifying-glass.svg +3 -0
- data/vendor/heroicons/24/solid/map-pin.svg +3 -0
- data/vendor/heroicons/24/solid/map.svg +3 -0
- data/vendor/heroicons/24/solid/megaphone.svg +3 -0
- data/vendor/heroicons/24/solid/microphone.svg +4 -0
- data/vendor/heroicons/24/solid/minus-circle.svg +3 -0
- data/vendor/heroicons/24/solid/minus-small.svg +3 -0
- data/vendor/heroicons/24/solid/minus.svg +3 -0
- data/vendor/heroicons/24/solid/moon.svg +3 -0
- data/vendor/heroicons/24/solid/musical-note.svg +3 -0
- data/vendor/heroicons/24/solid/newspaper.svg +4 -0
- data/vendor/heroicons/24/solid/no-symbol.svg +3 -0
- data/vendor/heroicons/24/solid/numbered-list.svg +3 -0
- data/vendor/heroicons/24/solid/paint-brush.svg +3 -0
- data/vendor/heroicons/24/solid/paper-airplane.svg +3 -0
- data/vendor/heroicons/24/solid/paper-clip.svg +3 -0
- data/vendor/heroicons/24/solid/pause-circle.svg +3 -0
- data/vendor/heroicons/24/solid/pause.svg +3 -0
- data/vendor/heroicons/24/solid/pencil-square.svg +4 -0
- data/vendor/heroicons/24/solid/pencil.svg +3 -0
- data/vendor/heroicons/24/solid/percent-badge.svg +3 -0
- data/vendor/heroicons/24/solid/phone-arrow-down-left.svg +4 -0
- data/vendor/heroicons/24/solid/phone-arrow-up-right.svg +4 -0
- data/vendor/heroicons/24/solid/phone-x-mark.svg +3 -0
- data/vendor/heroicons/24/solid/phone.svg +3 -0
- data/vendor/heroicons/24/solid/photo.svg +3 -0
- data/vendor/heroicons/24/solid/play-circle.svg +3 -0
- data/vendor/heroicons/24/solid/play-pause.svg +3 -0
- data/vendor/heroicons/24/solid/play.svg +3 -0
- data/vendor/heroicons/24/solid/plus-circle.svg +3 -0
- data/vendor/heroicons/24/solid/plus-small.svg +3 -0
- data/vendor/heroicons/24/solid/plus.svg +3 -0
- data/vendor/heroicons/24/solid/power.svg +3 -0
- data/vendor/heroicons/24/solid/presentation-chart-bar.svg +3 -0
- data/vendor/heroicons/24/solid/presentation-chart-line.svg +3 -0
- data/vendor/heroicons/24/solid/printer.svg +3 -0
- data/vendor/heroicons/24/solid/puzzle-piece.svg +3 -0
- data/vendor/heroicons/24/solid/qr-code.svg +3 -0
- data/vendor/heroicons/24/solid/question-mark-circle.svg +3 -0
- data/vendor/heroicons/24/solid/queue-list.svg +3 -0
- data/vendor/heroicons/24/solid/radio.svg +3 -0
- data/vendor/heroicons/24/solid/receipt-percent.svg +3 -0
- data/vendor/heroicons/24/solid/receipt-refund.svg +3 -0
- data/vendor/heroicons/24/solid/rectangle-group.svg +3 -0
- data/vendor/heroicons/24/solid/rectangle-stack.svg +3 -0
- data/vendor/heroicons/24/solid/rocket-launch.svg +4 -0
- data/vendor/heroicons/24/solid/rss.svg +3 -0
- data/vendor/heroicons/24/solid/scale.svg +3 -0
- data/vendor/heroicons/24/solid/scissors.svg +4 -0
- data/vendor/heroicons/24/solid/server-stack.svg +4 -0
- data/vendor/heroicons/24/solid/server.svg +4 -0
- data/vendor/heroicons/24/solid/share.svg +3 -0
- data/vendor/heroicons/24/solid/shield-check.svg +3 -0
- data/vendor/heroicons/24/solid/shield-exclamation.svg +3 -0
- data/vendor/heroicons/24/solid/shopping-bag.svg +3 -0
- data/vendor/heroicons/24/solid/shopping-cart.svg +3 -0
- data/vendor/heroicons/24/solid/signal-slash.svg +3 -0
- data/vendor/heroicons/24/solid/signal.svg +3 -0
- data/vendor/heroicons/24/solid/slash.svg +3 -0
- data/vendor/heroicons/24/solid/sparkles.svg +3 -0
- data/vendor/heroicons/24/solid/speaker-wave.svg +4 -0
- data/vendor/heroicons/24/solid/speaker-x-mark.svg +3 -0
- data/vendor/heroicons/24/solid/square-2-stack.svg +4 -0
- data/vendor/heroicons/24/solid/square-3-stack-3d.svg +5 -0
- data/vendor/heroicons/24/solid/squares-2x2.svg +3 -0
- data/vendor/heroicons/24/solid/squares-plus.svg +3 -0
- data/vendor/heroicons/24/solid/star.svg +3 -0
- data/vendor/heroicons/24/solid/stop-circle.svg +3 -0
- data/vendor/heroicons/24/solid/stop.svg +3 -0
- data/vendor/heroicons/24/solid/strikethrough.svg +3 -0
- data/vendor/heroicons/24/solid/sun.svg +3 -0
- data/vendor/heroicons/24/solid/swatch.svg +4 -0
- data/vendor/heroicons/24/solid/table-cells.svg +3 -0
- data/vendor/heroicons/24/solid/tag.svg +3 -0
- data/vendor/heroicons/24/solid/ticket.svg +3 -0
- data/vendor/heroicons/24/solid/trash.svg +3 -0
- data/vendor/heroicons/24/solid/trophy.svg +3 -0
- data/vendor/heroicons/24/solid/truck.svg +5 -0
- data/vendor/heroicons/24/solid/tv.svg +4 -0
- data/vendor/heroicons/24/solid/underline.svg +3 -0
- data/vendor/heroicons/24/solid/user-circle.svg +3 -0
- data/vendor/heroicons/24/solid/user-group.svg +4 -0
- data/vendor/heroicons/24/solid/user-minus.svg +3 -0
- data/vendor/heroicons/24/solid/user-plus.svg +3 -0
- data/vendor/heroicons/24/solid/user.svg +3 -0
- data/vendor/heroicons/24/solid/users.svg +3 -0
- data/vendor/heroicons/24/solid/variable.svg +3 -0
- data/vendor/heroicons/24/solid/video-camera-slash.svg +3 -0
- data/vendor/heroicons/24/solid/video-camera.svg +3 -0
- data/vendor/heroicons/24/solid/view-columns.svg +3 -0
- data/vendor/heroicons/24/solid/viewfinder-circle.svg +3 -0
- data/vendor/heroicons/24/solid/wallet.svg +3 -0
- data/vendor/heroicons/24/solid/wifi.svg +3 -0
- data/vendor/heroicons/24/solid/window.svg +3 -0
- data/vendor/heroicons/24/solid/wrench-screwdriver.svg +5 -0
- data/vendor/heroicons/24/solid/wrench.svg +3 -0
- data/vendor/heroicons/24/solid/x-circle.svg +3 -0
- data/vendor/heroicons/24/solid/x-mark.svg +3 -0
- data/vendor/heroicons/LICENSE +21 -0
- data/vendor/heroicons/VERSION +5 -0
- metadata +1664 -0
data/lib/abqari/site.rb
ADDED
|
@@ -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
|