@omega.js/web 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +98 -0
- package/README.md +640 -0
- package/bin/omega +2 -0
- package/bin/omega-web +2 -0
- package/bin/omg +2 -0
- package/core/_includes/admin/sections/sidebar.json +100 -0
- package/core/_includes/admin/sections/topbar.json +11 -0
- package/core/_includes/backend/sections/sidebar.json +39 -0
- package/core/_includes/backend/sections/topbar.json +16 -0
- package/core/_includes/core/body.html +102 -0
- package/core/_includes/core/foot.html +536 -0
- package/core/_includes/core/head.html +423 -0
- package/core/_includes/core/pricing/price-per-unit.html +33 -0
- package/core/_includes/core/showcase/entry-body.html +94 -0
- package/core/_includes/core/showcase/index-body.html +43 -0
- package/core/_includes/core/showcase/nav.html +60 -0
- package/core/_includes/frontend/sections/footer.json +74 -0
- package/core/_includes/frontend/sections/nav.json +70 -0
- package/core/_includes/global/sections/account.json +31 -0
- package/core/_includes/modules/engagement/giscus.html +26 -0
- package/core/_layouts/blueprint/404.html +10 -0
- package/core/_layouts/blueprint/about.html +10 -0
- package/core/_layouts/blueprint/account/index.html +11 -0
- package/core/_layouts/blueprint/admin/calendar/index.html +590 -0
- package/core/_layouts/blueprint/admin/dashboard/index.html +301 -0
- package/core/_layouts/blueprint/admin/firebase/index.html +214 -0
- package/core/_layouts/blueprint/admin/posts/editor.html +157 -0
- package/core/_layouts/blueprint/admin/posts/index.html +126 -0
- package/core/_layouts/blueprint/admin/stackblitz/index.html +30 -0
- package/core/_layouts/blueprint/admin/studio/index.html +85 -0
- package/core/_layouts/blueprint/admin/users/index.html +272 -0
- package/core/_layouts/blueprint/admin/users/new.html +82 -0
- package/core/_layouts/blueprint/admin/verts/index.html +204 -0
- package/core/_layouts/blueprint/alternatives/alternative.html +15 -0
- package/core/_layouts/blueprint/alternatives/index.html +10 -0
- package/core/_layouts/blueprint/app.html +10 -0
- package/core/_layouts/blueprint/auth/reset.html +19 -0
- package/core/_layouts/blueprint/auth/signin.html +19 -0
- package/core/_layouts/blueprint/auth/signup.html +19 -0
- package/core/_layouts/blueprint/auth/token.html +19 -0
- package/core/_layouts/blueprint/blog/categories/category.html +8 -0
- package/core/_layouts/blueprint/blog/categories/index.html +11 -0
- package/core/_layouts/blueprint/blog/index.html +10 -0
- package/core/_layouts/blueprint/blog/post.html +5 -0
- package/core/_layouts/blueprint/blog/tags/index.html +11 -0
- package/core/_layouts/blueprint/blog/tags/tag.html +8 -0
- package/core/_layouts/blueprint/careers.md +13 -0
- package/core/_layouts/blueprint/collection/category.html +9 -0
- package/core/_layouts/blueprint/collection/document.html +9 -0
- package/core/_layouts/blueprint/collection/index.html +9 -0
- package/core/_layouts/blueprint/connections/callback.html +11 -0
- package/core/_layouts/blueprint/contact.html +14 -0
- package/core/_layouts/blueprint/dashboard/index.html +10 -0
- package/core/_layouts/blueprint/download.html +20 -0
- package/core/_layouts/blueprint/extension/index.html +14 -0
- package/core/_layouts/blueprint/extension/installed.html +11 -0
- package/core/_layouts/blueprint/feedback.html +10 -0
- package/core/_layouts/blueprint/index.html +16 -0
- package/core/_layouts/blueprint/legal/cookies.md +57 -0
- package/core/_layouts/blueprint/legal/privacy.md +109 -0
- package/core/_layouts/blueprint/legal/terms.md +155 -0
- package/core/_layouts/blueprint/payment/checkout.html +15 -0
- package/core/_layouts/blueprint/payment/confirmation.html +14 -0
- package/core/_layouts/blueprint/portal/email-preferences.html +15 -0
- package/core/_layouts/blueprint/pricing.html +20 -0
- package/core/_layouts/blueprint/status.html +10 -0
- package/core/_layouts/blueprint/team/index.html +10 -0
- package/core/_layouts/blueprint/team/member.html +5 -0
- package/core/_layouts/blueprint/updates/index.html +10 -0
- package/core/_layouts/blueprint/updates/update.html +10 -0
- package/core/_layouts/core/root.html +45 -0
- package/core/_layouts/modules/utilities/redirect.html +129 -0
- package/core/css/_studio.scss +237 -0
- package/core/css/components/_index.scss +146 -0
- package/core/css/core/_.scss +0 -0
- package/core/css/core/_alert.scss +87 -0
- package/core/css/core/_animations.scss +343 -0
- package/core/css/core/_bindings.scss +116 -0
- package/core/css/core/_blog-search.scss +57 -0
- package/core/css/core/_chatsy.scss +61 -0
- package/core/css/core/_consent.scss +424 -0
- package/core/css/core/_custom-font-awesome.scss +146 -0
- package/core/css/core/_exit-popup.scss +42 -0
- package/core/css/core/_generated-badge.scss +33 -0
- package/core/css/core/_initialize.scss +29 -0
- package/core/css/core/_lazy-loading.scss +104 -0
- package/core/css/core/_social-sharing.scss +41 -0
- package/core/css/core/_tones.scss +32 -0
- package/core/css/core/_utilities.scss +157 -0
- package/core/css/main.scss +54 -0
- package/core/css/motion/_index.scss +368 -0
- package/core/css/pages/404/index.scss +0 -0
- package/core/css/pages/admin/calendar/index.scss +692 -0
- package/core/css/pages/admin/firebase/index.scss +33 -0
- package/core/css/pages/admin/index.scss +9 -0
- package/core/css/pages/admin/users/index.scss +9 -0
- package/core/css/pages/admin/verts/index.scss +9 -0
- package/core/css/pages/alternatives/[alternative]/index.scss +0 -0
- package/core/css/pages/blog/[slug].scss +55 -0
- package/core/css/pages/dashboard/account/index.scss +242 -0
- package/core/css/pages/download/index.scss +480 -0
- package/core/css/pages/extension/installed/index.scss +317 -0
- package/core/css/pages/feedback/index.scss +31 -0
- package/core/css/pages/payment/confirmation/index.scss +14 -0
- package/core/css/pages/pricing/index.scss +0 -0
- package/core/css/pages/status/index.scss +162 -0
- package/core/css/pages/test/libraries/layers/index.scss +28 -0
- package/core/css/pages/updates/[update].scss +46 -0
- package/core/css/pages/updates/index.scss +13 -0
- package/core/css/shell/_index.scss +207 -0
- package/core/css/tokens/_index.scss +166 -0
- package/core/icons/flags/ar.svg +1 -0
- package/core/icons/flags/bd.svg +1 -0
- package/core/icons/flags/ca.svg +1 -0
- package/core/icons/flags/ch.svg +1 -0
- package/core/icons/flags/cn.svg +1 -0
- package/core/icons/flags/co.svg +1 -0
- package/core/icons/flags/cw.svg +1 -0
- package/core/icons/flags/cz.svg +1 -0
- package/core/icons/flags/de.svg +1 -0
- package/core/icons/flags/dk.svg +1 -0
- package/core/icons/flags/eg.svg +1 -0
- package/core/icons/flags/es.svg +1 -0
- package/core/icons/flags/fi.svg +1 -0
- package/core/icons/flags/fr.svg +1 -0
- package/core/icons/flags/gb.svg +1 -0
- package/core/icons/flags/gq.svg +1 -0
- package/core/icons/flags/gr.svg +1 -0
- package/core/icons/flags/gt.svg +1 -0
- package/core/icons/flags/hn.svg +1 -0
- package/core/icons/flags/id.svg +1 -0
- package/core/icons/flags/ie.svg +1 -0
- package/core/icons/flags/in.svg +1 -0
- package/core/icons/flags/ir.svg +1 -0
- package/core/icons/flags/it.svg +1 -0
- package/core/icons/flags/jp.svg +1 -0
- package/core/icons/flags/kp.svg +1 -0
- package/core/icons/flags/kr.svg +1 -0
- package/core/icons/flags/ly.svg +1 -0
- package/core/icons/flags/ma.svg +1 -0
- package/core/icons/flags/mu.svg +1 -0
- package/core/icons/flags/mx.svg +1 -0
- package/core/icons/flags/ng.svg +1 -0
- package/core/icons/flags/pa.svg +1 -0
- package/core/icons/flags/ph.svg +1 -0
- package/core/icons/flags/pk.svg +1 -0
- package/core/icons/flags/pt.svg +1 -0
- package/core/icons/flags/ru.svg +1 -0
- package/core/icons/flags/sa.svg +1 -0
- package/core/icons/flags/sd.svg +1 -0
- package/core/icons/flags/se.svg +1 -0
- package/core/icons/flags/th.svg +1 -0
- package/core/icons/flags/tm.svg +1 -0
- package/core/icons/flags/tr.svg +1 -0
- package/core/icons/flags/us.svg +1 -0
- package/core/icons/flags/uy.svg +1 -0
- package/core/icons/flags/vn.svg +1 -0
- package/core/icons/flags/za.svg +1 -0
- package/core/images/exit-popup/subscriber-1.jpg +0 -0
- package/core/images/exit-popup/subscriber-2.jpg +0 -0
- package/core/images/exit-popup/subscriber-3.jpg +0 -0
- package/core/images/exit-popup/subscriber-4.jpg +0 -0
- package/core/images/placeholder/photo-1.jpg +0 -0
- package/core/images/placeholder/photo-2.jpg +0 -0
- package/core/images/placeholder/photo-3.jpg +0 -0
- package/core/js/core/analytics-loader.js +253 -0
- package/core/js/core/app-shell.js +136 -0
- package/core/js/core/appearance.js +195 -0
- package/core/js/core/auth.js +457 -0
- package/core/js/core/complete.js +72 -0
- package/core/js/core/consent.js +384 -0
- package/core/js/core/dev-icon-audit.js +63 -0
- package/core/js/core/dev-palette.js +670 -0
- package/core/js/core/dev-sections.js +53 -0
- package/core/js/core/exit-popup.js +276 -0
- package/core/js/core/initialize.js +8 -0
- package/core/js/core/language-switcher.js +167 -0
- package/core/js/core/lazy-loading.js +479 -0
- package/core/js/core/motion.js +28 -0
- package/core/js/core/query-strings.js +146 -0
- package/core/js/core/service-worker.js +28 -0
- package/core/js/core/social-sharing.js +293 -0
- package/core/js/first-paint.js +35 -0
- package/core/js/layouts/modules/utilities/redirect.js +122 -0
- package/core/js/libs/admin-helpers.js +62 -0
- package/core/js/libs/alert-dismiss.js +35 -0
- package/core/js/libs/analytics.js +368 -0
- package/core/js/libs/auth/email.js +144 -0
- package/core/js/libs/auth/errors.js +119 -0
- package/core/js/libs/auth/forms.js +206 -0
- package/core/js/libs/auth/index.js +181 -0
- package/core/js/libs/auth/oauth.js +394 -0
- package/core/js/libs/auth/orphan.js +110 -0
- package/core/js/libs/auth/password-toggle.js +44 -0
- package/core/js/libs/auth/session-params.js +266 -0
- package/core/js/libs/auth/tracking.js +41 -0
- package/core/js/libs/charts.js +516 -0
- package/core/js/libs/consent-region.js +127 -0
- package/core/js/libs/dev.js +150 -0
- package/core/js/libs/graph.js +201 -0
- package/core/js/libs/initialize-tooltips.js +31 -0
- package/core/js/libs/logger.js +38 -0
- package/core/js/libs/omega-copy.js +89 -0
- package/core/js/libs/path-prefix.js +44 -0
- package/core/js/libs/payment-config.js +76 -0
- package/core/js/libs/recaptcha.js +94 -0
- package/core/js/libs/sale-name.js +295 -0
- package/core/js/libs/showcase-frames.js +37 -0
- package/core/js/libs/srcset.js +69 -0
- package/core/js/libs/tracking-consent.js +161 -0
- package/core/js/main.js +144 -0
- package/core/js/pages/404/index.js +57 -0
- package/core/js/pages/admin/calendar/calendar-core.js +701 -0
- package/core/js/pages/admin/calendar/calendar-events.js +853 -0
- package/core/js/pages/admin/calendar/calendar-renderer.js +807 -0
- package/core/js/pages/admin/calendar/campaign-preview.js +105 -0
- package/core/js/pages/admin/calendar/index.js +40 -0
- package/core/js/pages/admin/firebase/index.js +727 -0
- package/core/js/pages/admin/index.js +531 -0
- package/core/js/pages/admin/posts/editor/index.js +230 -0
- package/core/js/pages/admin/posts/index.js +237 -0
- package/core/js/pages/admin/studio/index.js +538 -0
- package/core/js/pages/admin/users/index.js +669 -0
- package/core/js/pages/admin/users/new/index.js +65 -0
- package/core/js/pages/admin/verts/index.js +407 -0
- package/core/js/pages/alternatives/[alternative]/index.js +17 -0
- package/core/js/pages/app/index.js +135 -0
- package/core/js/pages/blog/[slug].js +132 -0
- package/core/js/pages/blog/_search.mjs +108 -0
- package/core/js/pages/blog/index.js +193 -0
- package/core/js/pages/blog/page/[num]/index.js +7 -0
- package/core/js/pages/connections/callback/index.js +148 -0
- package/core/js/pages/contact/index.js +170 -0
- package/core/js/pages/cookies.js +2 -0
- package/core/js/pages/dashboard/account/index.js +366 -0
- package/core/js/pages/dashboard/account/modules/orders.js +82 -0
- package/core/js/pages/dashboard/account/sections/api-keys.js +149 -0
- package/core/js/pages/dashboard/account/sections/billing.js +1667 -0
- package/core/js/pages/dashboard/account/sections/connections.js +333 -0
- package/core/js/pages/dashboard/account/sections/data-request.js +225 -0
- package/core/js/pages/dashboard/account/sections/delete.js +80 -0
- package/core/js/pages/dashboard/account/sections/notifications.js +167 -0
- package/core/js/pages/dashboard/account/sections/orders.js +151 -0
- package/core/js/pages/dashboard/account/sections/profile.js +200 -0
- package/core/js/pages/dashboard/account/sections/referrals.js +217 -0
- package/core/js/pages/dashboard/account/sections/refund.js +253 -0
- package/core/js/pages/dashboard/account/sections/security.js +726 -0
- package/core/js/pages/dashboard/account/sections/team.js +247 -0
- package/core/js/pages/download/index.js +418 -0
- package/core/js/pages/extension/index.js +164 -0
- package/core/js/pages/extension/installed/index.js +135 -0
- package/core/js/pages/feedback/index.js +193 -0
- package/core/js/pages/legal/_document.js +91 -0
- package/core/js/pages/payment/checkout/index.js +420 -0
- package/core/js/pages/payment/checkout/modules/api.js +139 -0
- package/core/js/pages/payment/checkout/modules/dev-section.js +175 -0
- package/core/js/pages/payment/checkout/modules/discount.js +69 -0
- package/core/js/pages/payment/checkout/modules/pricing.js +73 -0
- package/core/js/pages/payment/checkout/modules/state.js +339 -0
- package/core/js/pages/payment/checkout/modules/tracking.js +54 -0
- package/core/js/pages/payment/confirmation/index.js +91 -0
- package/core/js/pages/payment/confirmation/modules/celebration.js +45 -0
- package/core/js/pages/payment/confirmation/modules/state.js +112 -0
- package/core/js/pages/payment/confirmation/modules/tracking.js +133 -0
- package/core/js/pages/payment/confirmation/modules/verify.js +142 -0
- package/core/js/pages/portal/email-preferences/index.js +183 -0
- package/core/js/pages/pricing/index.js +425 -0
- package/core/js/pages/privacy.js +2 -0
- package/core/js/pages/reset/index.js +12 -0
- package/core/js/pages/signin/index.js +22 -0
- package/core/js/pages/signup/index.js +23 -0
- package/core/js/pages/status/index.js +687 -0
- package/core/js/pages/terms.js +2 -0
- package/core/js/pages/test/components/[category]/[name]/index.js +26 -0
- package/core/js/pages/test/libraries/appearance/index.js +220 -0
- package/core/js/pages/test/libraries/form-manager/index.js +328 -0
- package/core/js/pages/test/libraries/layers/index.js +16 -0
- package/core/js/pages/test/libraries/verts/index.js +68 -0
- package/core/js/pages/test/sections/[category]/[name]/index.js +28 -0
- package/core/js/pages/test/styleguide/index.js +35 -0
- package/core/js/pages/token/index.js +203 -0
- package/core/logos/brandmarks/original/apple-app-store.svg +1 -0
- package/core/logos/brandmarks/original/apple.svg +6 -0
- package/core/logos/brandmarks/original/bitbucket.svg +14 -0
- package/core/logos/brandmarks/original/bitcoin.svg +1 -0
- package/core/logos/brandmarks/original/bluesky.svg +7 -0
- package/core/logos/brandmarks/original/bootstrap.svg +43 -0
- package/core/logos/brandmarks/original/brave.svg +1 -0
- package/core/logos/brandmarks/original/chrome.svg +1 -0
- package/core/logos/brandmarks/original/discord.svg +1 -0
- package/core/logos/brandmarks/original/dropbox.svg +10 -0
- package/core/logos/brandmarks/original/edge.svg +1 -0
- package/core/logos/brandmarks/original/facebook-f.svg +1 -0
- package/core/logos/brandmarks/original/facebook.svg +8 -0
- package/core/logos/brandmarks/original/figma.svg +10 -0
- package/core/logos/brandmarks/original/firefox.svg +1 -0
- package/core/logos/brandmarks/original/github.svg +6 -0
- package/core/logos/brandmarks/original/gitlab.svg +17 -0
- package/core/logos/brandmarks/original/google-a-s.svg +1 -0
- package/core/logos/brandmarks/original/google-chrome-webstore.svg +49 -0
- package/core/logos/brandmarks/original/google-play-store.svg +1 -0
- package/core/logos/brandmarks/original/google-web-search.svg +1 -0
- package/core/logos/brandmarks/original/google.svg +1 -0
- package/core/logos/brandmarks/original/gulp.svg +4 -0
- package/core/logos/brandmarks/original/html-5.svg +1 -0
- package/core/logos/brandmarks/original/instagram.svg +1 -0
- package/core/logos/brandmarks/original/javascript.svg +1 -0
- package/core/logos/brandmarks/original/jira.svg +18 -0
- package/core/logos/brandmarks/original/kick.svg +7 -0
- package/core/logos/brandmarks/original/linkedin.svg +1 -0
- package/core/logos/brandmarks/original/linux.svg +28 -0
- package/core/logos/brandmarks/original/messenger.svg +16 -0
- package/core/logos/brandmarks/original/microsoft.svg +1 -0
- package/core/logos/brandmarks/original/npm.svg +8 -0
- package/core/logos/brandmarks/original/opera.svg +1 -0
- package/core/logos/brandmarks/original/patreon.svg +6 -0
- package/core/logos/brandmarks/original/pinterest.svg +6 -0
- package/core/logos/brandmarks/original/reddit.svg +1 -0
- package/core/logos/brandmarks/original/safari.svg +31 -0
- package/core/logos/brandmarks/original/sass.svg +3 -0
- package/core/logos/brandmarks/original/signal.svg +6 -0
- package/core/logos/brandmarks/original/skype.svg +47 -0
- package/core/logos/brandmarks/original/slack.svg +33 -0
- package/core/logos/brandmarks/original/soundcloud.svg +1 -0
- package/core/logos/brandmarks/original/spotify.svg +5 -0
- package/core/logos/brandmarks/original/steam.svg +6 -0
- package/core/logos/brandmarks/original/telegram.svg +14 -0
- package/core/logos/brandmarks/original/tiktok.svg +1 -0
- package/core/logos/brandmarks/original/trello.svg +16 -0
- package/core/logos/brandmarks/original/tumblr.svg +1 -0
- package/core/logos/brandmarks/original/twitch.svg +6 -0
- package/core/logos/brandmarks/original/twitter.svg +6 -0
- package/core/logos/brandmarks/original/unity.svg +6 -0
- package/core/logos/brandmarks/original/x.svg +7 -0
- package/core/logos/brandmarks/original/yahoo-y.svg +1 -0
- package/core/logos/brandmarks/original/youtube-square.svg +1 -0
- package/core/logos/brandmarks/original/youtube.svg +1 -0
- package/core/logos/combomarks/dark/airbnb.svg +30 -0
- package/core/logos/combomarks/dark/slack.svg +38 -0
- package/core/logos/combomarks/dark/spotify.svg +35 -0
- package/core/logos/combomarks/dark/twilio.svg +26 -0
- package/core/logos/combomarks/dark/weebly.svg +35 -0
- package/core/logos/combomarks/gray/airbnb.svg +33 -0
- package/core/logos/combomarks/gray/alphabet.svg +23 -0
- package/core/logos/combomarks/gray/amazon.svg +38 -0
- package/core/logos/combomarks/gray/boring-company.svg +91 -0
- package/core/logos/combomarks/gray/burberry.svg +239 -0
- package/core/logos/combomarks/gray/embark.svg +21 -0
- package/core/logos/combomarks/gray/fitbit.svg +61 -0
- package/core/logos/combomarks/gray/fred-perry.svg +94 -0
- package/core/logos/combomarks/gray/google.svg +27 -0
- package/core/logos/combomarks/gray/hollister.svg +34 -0
- package/core/logos/combomarks/gray/hubspot.svg +27 -0
- package/core/logos/combomarks/gray/kaplan.svg +33 -0
- package/core/logos/combomarks/gray/lenovo.svg +27 -0
- package/core/logos/combomarks/gray/levis.svg +25 -0
- package/core/logos/combomarks/gray/mapbox.svg +37 -0
- package/core/logos/combomarks/gray/netflix.svg +15 -0
- package/core/logos/combomarks/gray/new-balance.svg +32 -0
- package/core/logos/combomarks/gray/nike.svg +17 -0
- package/core/logos/combomarks/gray/paypal.svg +41 -0
- package/core/logos/combomarks/gray/puma.svg +82 -0
- package/core/logos/combomarks/gray/samsung.svg +26 -0
- package/core/logos/combomarks/gray/shopify.svg +36 -0
- package/core/logos/combomarks/gray/slack.svg +42 -0
- package/core/logos/combomarks/gray/spotify.svg +38 -0
- package/core/logos/combomarks/gray/stripe.svg +24 -0
- package/core/logos/combomarks/gray/tnf.svg +30 -0
- package/core/logos/combomarks/gray/twilio.svg +29 -0
- package/core/logos/combomarks/gray/uber.svg +24 -0
- package/core/logos/combomarks/gray/weebly.svg +38 -0
- package/core/logos/combomarks/original/airbnb.svg +33 -0
- package/core/logos/combomarks/original/alphabet.svg +23 -0
- package/core/logos/combomarks/original/amazon.svg +38 -0
- package/core/logos/combomarks/original/asana.svg +8 -0
- package/core/logos/combomarks/original/boring-company.svg +91 -0
- package/core/logos/combomarks/original/discord.svg +6 -0
- package/core/logos/combomarks/original/embark.svg +24 -0
- package/core/logos/combomarks/original/fitbit.svg +60 -0
- package/core/logos/combomarks/original/github.svg +6 -0
- package/core/logos/combomarks/original/gitlab.svg +20 -0
- package/core/logos/combomarks/original/google.svg +28 -0
- package/core/logos/combomarks/original/hubspot.svg +29 -0
- package/core/logos/combomarks/original/instagram.svg +7 -0
- package/core/logos/combomarks/original/kickstarter.svg +6 -0
- package/core/logos/combomarks/original/lenovo.svg +24 -0
- package/core/logos/combomarks/original/linkedin.svg +6 -0
- package/core/logos/combomarks/original/mapbox.svg +39 -0
- package/core/logos/combomarks/original/mastodon.svg +7 -0
- package/core/logos/combomarks/original/medium.svg +6 -0
- package/core/logos/combomarks/original/meta.svg +22 -0
- package/core/logos/combomarks/original/microsoft.svg +13 -0
- package/core/logos/combomarks/original/monday.svg +12 -0
- package/core/logos/combomarks/original/netflix.svg +15 -0
- package/core/logos/combomarks/original/notion.svg +9 -0
- package/core/logos/combomarks/original/paypal.svg +41 -0
- package/core/logos/combomarks/original/reddit.svg +13 -0
- package/core/logos/combomarks/original/samsung.svg +25 -0
- package/core/logos/combomarks/original/shopify.svg +35 -0
- package/core/logos/combomarks/original/slack.svg +47 -0
- package/core/logos/combomarks/original/spotify.svg +37 -0
- package/core/logos/combomarks/original/stackoverflow.svg +28 -0
- package/core/logos/combomarks/original/stripe.svg +24 -0
- package/core/logos/combomarks/original/tiktok.svg +12 -0
- package/core/logos/combomarks/original/tumblr.svg +6 -0
- package/core/logos/combomarks/original/uber.svg +24 -0
- package/core/logos/combomarks/original/weebly.svg +34 -0
- package/core/logos/combomarks/original/whatsapp.svg +20 -0
- package/core/logos/combomarks/original/youtube.svg +10 -0
- package/core/logos/combomarks/original/zoom.svg +7 -0
- package/core/logos/combomarks/white/airbnb.svg +33 -0
- package/core/logos/combomarks/white/alphabet.svg +23 -0
- package/core/logos/combomarks/white/amazon.svg +38 -0
- package/core/logos/combomarks/white/boring-company.svg +91 -0
- package/core/logos/combomarks/white/embark.svg +21 -0
- package/core/logos/combomarks/white/fitbit.svg +61 -0
- package/core/logos/combomarks/white/google.svg +27 -0
- package/core/logos/combomarks/white/hubspot.svg +27 -0
- package/core/logos/combomarks/white/kaplan.svg +33 -0
- package/core/logos/combomarks/white/lenovo.svg +27 -0
- package/core/logos/combomarks/white/mapbox.svg +37 -0
- package/core/logos/combomarks/white/netflix.svg +15 -0
- package/core/logos/combomarks/white/paypal.svg +40 -0
- package/core/logos/combomarks/white/samsung.svg +26 -0
- package/core/logos/combomarks/white/shopify.svg +36 -0
- package/core/logos/combomarks/white/slack.svg +42 -0
- package/core/logos/combomarks/white/spotify.svg +38 -0
- package/core/logos/combomarks/white/stripe.svg +24 -0
- package/core/logos/combomarks/white/twilio.svg +29 -0
- package/core/logos/combomarks/white/uber.svg +24 -0
- package/core/logos/combomarks/white/weebly.svg +38 -0
- package/defaults/pages/404.md +4 -0
- package/defaults/pages/about.md +4 -0
- package/defaults/pages/admin/calendar/index.html +4 -0
- package/defaults/pages/admin/firebase/index.html +4 -0
- package/defaults/pages/admin/index.md +4 -0
- package/defaults/pages/admin/posts/editor.html +4 -0
- package/defaults/pages/admin/posts/index.html +4 -0
- package/defaults/pages/admin/stackblitz/index.html +4 -0
- package/defaults/pages/admin/studio/index.html +4 -0
- package/defaults/pages/admin/users/index.html +4 -0
- package/defaults/pages/admin/users/new.html +4 -0
- package/defaults/pages/admin/verts/index.html +4 -0
- package/defaults/pages/ads-txt.html +11 -0
- package/defaults/pages/alternatives/index.md +4 -0
- package/defaults/pages/app.md +4 -0
- package/defaults/pages/auth/reset.md +4 -0
- package/defaults/pages/auth/signin.md +4 -0
- package/defaults/pages/auth/signup.md +4 -0
- package/defaults/pages/auth/token.md +4 -0
- package/defaults/pages/blog/categories/category.html +21 -0
- package/defaults/pages/blog/categories.md +4 -0
- package/defaults/pages/blog/index-json.html +27 -0
- package/defaults/pages/blog/tags/tag.html +21 -0
- package/defaults/pages/blog/tags.md +4 -0
- package/defaults/pages/blog.md +22 -0
- package/defaults/pages/careers.md +4 -0
- package/defaults/pages/connections/callback.md +4 -0
- package/defaults/pages/contact.md +4 -0
- package/defaults/pages/dashboard/account.md +4 -0
- package/defaults/pages/dashboard/index.md +12 -0
- package/defaults/pages/download.md +4 -0
- package/defaults/pages/extension/index.html +4 -0
- package/defaults/pages/extension/installed.html +4 -0
- package/defaults/pages/feedback.md +4 -0
- package/defaults/pages/feeds/posts-json.html +40 -0
- package/defaults/pages/feeds/posts-xml.html +38 -0
- package/defaults/pages/humans.html +25 -0
- package/defaults/pages/index.md +4 -0
- package/defaults/pages/legal/cookies.md +4 -0
- package/defaults/pages/legal/privacy.md +4 -0
- package/defaults/pages/legal/terms.md +4 -0
- package/defaults/pages/llms-txt.html +46 -0
- package/defaults/pages/opensearch.html +16 -0
- package/defaults/pages/pages-json.html +42 -0
- package/defaults/pages/payment/checkout.md +4 -0
- package/defaults/pages/payment/confirmation.md +4 -0
- package/defaults/pages/portal/email-preferences.md +4 -0
- package/defaults/pages/pricing.md +4 -0
- package/defaults/pages/redirects/account.md +12 -0
- package/defaults/pages/redirects/admin/dashboard.md +11 -0
- package/defaults/pages/redirects/auth/change-password.md +9 -0
- package/defaults/pages/redirects/auth/forgot.md +9 -0
- package/defaults/pages/redirects/auth/join.md +9 -0
- package/defaults/pages/redirects/auth/login.md +9 -0
- package/defaults/pages/redirects/auth/recover.md +9 -0
- package/defaults/pages/redirects/auth/register.md +9 -0
- package/defaults/pages/redirects/auth/reset-password.md +9 -0
- package/defaults/pages/redirects/billing/cancel.md +9 -0
- package/defaults/pages/redirects/billing/refund.md +9 -0
- package/defaults/pages/robots.html +36 -0
- package/defaults/pages/security-txt.html +11 -0
- package/defaults/pages/sitemap.html +37 -0
- package/defaults/pages/status.md +4 -0
- package/defaults/pages/team/index.md +4 -0
- package/defaults/pages/test/account/dashboard.html +16 -0
- package/defaults/pages/test/index.md +12 -0
- package/defaults/pages/test/libraries/appearance.html +268 -0
- package/defaults/pages/test/libraries/cover.html +50 -0
- package/defaults/pages/test/libraries/error.html +30 -0
- package/defaults/pages/test/libraries/firestore.html +202 -0
- package/defaults/pages/test/libraries/form-manager.html +374 -0
- package/defaults/pages/test/libraries/layers.html +52 -0
- package/defaults/pages/test/libraries/lazy-loading.html +450 -0
- package/defaults/pages/test/libraries/verts.html +149 -0
- package/defaults/pages/test/redirect/external.md +13 -0
- package/defaults/pages/test/redirect/internal.md +13 -0
- package/defaults/pages/test/styleguide/index.html +588 -0
- package/defaults/pages/test/translation/index.md +50 -0
- package/defaults/pages/updates/index.md +4 -0
- package/defaults/sample-posts/2026-01-12-welcome-to-the-blog.md +26 -0
- package/defaults/sample-posts/2026-02-03-a-field-guide-to-good-defaults.md +50 -0
- package/defaults/sample-posts/2026-02-24-shipping-week-notes.md +37 -0
- package/defaults/sample-posts/2026-03-17-the-case-for-one-config.md +36 -0
- package/defaults/sample-posts/2026-04-09-write-release-notes-people-read.md +34 -0
- package/defaults/sample-posts/2026-05-21-dark-mode-done-properly.md +38 -0
- package/defaults/sample-posts/2026-06-02-the-boring-deploy-is-the-good-deploy.md +30 -0
- package/defaults/sample-posts/2026-06-11-naming-things-a-survival-guide.md +30 -0
- package/defaults/sample-posts/2026-06-19-your-pricing-page-is-a-product.md +28 -0
- package/defaults/sample-posts/2026-06-30-email-is-an-api-with-feelings.md +28 -0
- package/defaults/sample-posts/2026-07-08-ship-the-docs-with-the-diff.md +30 -0
- package/defaults/sample-team/avery-quinn.md +22 -0
- package/defaults/sample-team/jordan-reyes.md +25 -0
- package/defaults/sample-team/riley-nakamura.md +22 -0
- package/defaults/sample-team/sam-okafor.md +22 -0
- package/defaults/sample-updates/v1.0.0.md +28 -0
- package/defaults/sample-updates/v1.1.0.md +27 -0
- package/defaults/sample-updates/v1.2.0.md +27 -0
- package/defaults/sample-updates/v1.3.0.md +28 -0
- package/defaults/showcase/components.html +62 -0
- package/defaults/showcase/entry.html +76 -0
- package/defaults/showcase/frame.html +62 -0
- package/defaults/showcase/index.html +59 -0
- package/dist/assets.js +1349 -0
- package/dist/brand-tokens.js +195 -0
- package/dist/build.js +192 -0
- package/dist/cachebreak-html.js +71 -0
- package/dist/cli-run.js +25 -0
- package/dist/cli.js +47 -0
- package/dist/collections.js +183 -0
- package/dist/commands/audit.js +470 -0
- package/dist/commands/build.js +197 -0
- package/dist/commands/clean.js +18 -0
- package/dist/commands/customize.js +125 -0
- package/dist/commands/deploy.js +441 -0
- package/dist/commands/dev.js +1067 -0
- package/dist/commands/install.js +31 -0
- package/dist/commands/lib/deploy-precheck.js +43 -0
- package/dist/commands/lib/ensure-target.js +115 -0
- package/dist/commands/migrate.js +86 -0
- package/dist/commands/purge.js +31 -0
- package/dist/commands/test.js +237 -0
- package/dist/commands/translate.js +57 -0
- package/dist/commands/update.js +22 -0
- package/dist/commands/version.js +11 -0
- package/dist/config-sections.js +245 -0
- package/dist/consumer-scan.js +118 -0
- package/dist/consumer.js +49 -0
- package/dist/customize.js +328 -0
- package/dist/decisions.js +153 -0
- package/dist/dist-audit.js +417 -0
- package/dist/dynamic-pages.js +357 -0
- package/dist/engine.js +1402 -0
- package/dist/firebase-auth-helpers.js +198 -0
- package/dist/font-metrics.js +420 -0
- package/dist/frontmatter-liquid.js +253 -0
- package/dist/github-secrets.js +80 -0
- package/dist/hero-animations.js +170 -0
- package/dist/imagemin.js +261 -0
- package/dist/index.js +41 -0
- package/dist/inline-icons.js +65 -0
- package/dist/language-flags.js +55 -0
- package/dist/layers.js +80 -0
- package/dist/layouts.js +44 -0
- package/dist/limit-collections.js +199 -0
- package/dist/link-resolver.js +303 -0
- package/dist/markdown-images.js +85 -0
- package/dist/merge.js +20 -0
- package/dist/migrate/codemod.js +172 -0
- package/dist/migrate/config-convert.js +448 -0
- package/dist/migrate/consumer-assets.js +130 -0
- package/dist/migrate/index.js +223 -0
- package/dist/migrate/lint.js +108 -0
- package/dist/migrate/rules.js +1929 -0
- package/dist/minify-html.js +148 -0
- package/dist/mode-helpers.js +96 -0
- package/dist/omega-bin.js +7 -0
- package/dist/overrides.js +190 -0
- package/dist/path-prefix.js +167 -0
- package/dist/paths.js +37 -0
- package/dist/pricing.js +301 -0
- package/dist/purge.js +95 -0
- package/dist/redirect-page.js +45 -0
- package/dist/sample-content.js +210 -0
- package/dist/scaffold.js +123 -0
- package/dist/sections.js +810 -0
- package/dist/service-worker.js +200 -0
- package/dist/social-pages.js +142 -0
- package/dist/srcset.js +67 -0
- package/dist/static-assets.js +154 -0
- package/dist/target-shortlinks.js +123 -0
- package/dist/theme-vocabulary.js +76 -0
- package/dist/translate/collect-text-nodes.js +93 -0
- package/dist/translate/default-routes.js +152 -0
- package/dist/translate/generate-defaults.js +297 -0
- package/dist/translate/index.js +568 -0
- package/dist/translate/packaged-defaults.js +127 -0
- package/dist/translate/sitemap.js +108 -0
- package/dist/vendor/account/engine.js +182 -0
- package/dist/vendor/account/features.js +220 -0
- package/dist/vendor/account/index.js +53 -0
- package/dist/vendor/account/schema.js +272 -0
- package/dist/vendor/account/subscription.js +38 -0
- package/dist/vendor/config/company.js +31 -0
- package/dist/vendor/config/defaults.js +173 -0
- package/dist/vendor/config/demo.js +18 -0
- package/dist/vendor/config/desktop-artifacts.js +110 -0
- package/dist/vendor/config/edit.js +769 -0
- package/dist/vendor/config/env-delivery.js +145 -0
- package/dist/vendor/config/env-rules.js +93 -0
- package/dist/vendor/config/env-schema.js +1078 -0
- package/dist/vendor/config/env.js +445 -0
- package/dist/vendor/config/hooks.js +97 -0
- package/dist/vendor/config/index.js +237 -0
- package/dist/vendor/config/instances.js +208 -0
- package/dist/vendor/config/load.js +490 -0
- package/dist/vendor/config/merge.js +68 -0
- package/dist/vendor/config/order.js +139 -0
- package/dist/vendor/config/ports.js +374 -0
- package/dist/vendor/config/providers.js +32 -0
- package/dist/vendor/config/repo.js +142 -0
- package/dist/vendor/config/retired-keys.js +430 -0
- package/dist/vendor/config/schema.js +1610 -0
- package/dist/vendor/config/secrets.js +50 -0
- package/dist/vendor/config/seed.js +34 -0
- package/dist/vendor/config/site-global.js +205 -0
- package/dist/vendor/config/validate.js +554 -0
- package/dist/vendor/config/winback.js +61 -0
- package/dist/vendor/devkit/actions-secrets.js +145 -0
- package/dist/vendor/devkit/attach-log-file.js +262 -0
- package/dist/vendor/devkit/bare-requires.js +153 -0
- package/dist/vendor/devkit/bundle.js +292 -0
- package/dist/vendor/devkit/ci-workflows.js +520 -0
- package/dist/vendor/devkit/cli-router.js +156 -0
- package/dist/vendor/devkit/command-path.js +46 -0
- package/dist/vendor/devkit/defaults-engine.js +372 -0
- package/dist/vendor/devkit/deploy-precheck.js +54 -0
- package/dist/vendor/devkit/deploy-record.js +180 -0
- package/dist/vendor/devkit/deploy.js +286 -0
- package/dist/vendor/devkit/env-watch.js +132 -0
- package/dist/vendor/devkit/framework-deps.js +46 -0
- package/dist/vendor/devkit/icons.js +178 -0
- package/dist/vendor/devkit/license.js +155 -0
- package/dist/vendor/devkit/local-https.js +360 -0
- package/dist/vendor/devkit/local.js +1905 -0
- package/dist/vendor/devkit/logger.js +128 -0
- package/dist/vendor/devkit/merge-line-files.js +296 -0
- package/dist/vendor/devkit/omega-bin.js +345 -0
- package/dist/vendor/devkit/reads.js +274 -0
- package/dist/vendor/devkit/safe-install.js +18 -0
- package/dist/vendor/devkit/scaffold-guard.js +96 -0
- package/dist/vendor/devkit/stop-signals.js +28 -0
- package/dist/vendor/devkit/strip-dev-blocks-plugin.js +29 -0
- package/dist/vendor/devkit/strip-dev-blocks.js +32 -0
- package/dist/vendor/devkit/target-secrets.js +165 -0
- package/dist/vendor/devkit/test/scope.js +162 -0
- package/dist/vendor/devkit/translate/cache.js +84 -0
- package/dist/vendor/devkit/translate/engine.js +243 -0
- package/dist/vendor/devkit/translate/index.js +49 -0
- package/dist/vendor/devkit/translate/languages.js +134 -0
- package/dist/vendor/devkit/translate/providers.js +188 -0
- package/dist/vendor/devkit/update.js +569 -0
- package/dist/vendor/template-kit/data/language-flags.js +54 -0
- package/dist/vendor/template-kit/data/languages.js +195 -0
- package/dist/vendor/template-kit/data/social-urls.js +26 -0
- package/dist/vendor/template-kit/filters.js +227 -0
- package/dist/vendor/template-kit/index.js +28 -0
- package/dist/vendor/template-kit/jekyll-compat.js +268 -0
- package/dist/vendor/template-kit/register-liquid.js +0 -0
- package/dist/vendor/template-kit/tags/collections.js +191 -0
- package/dist/vendor/template-kit/tags/conditionals.js +101 -0
- package/dist/vendor/template-kit/tags/content.js +175 -0
- package/dist/vendor/template-kit/tags/index.js +33 -0
- package/dist/vendor/template-kit/tags/media.js +376 -0
- package/dist/vendor/template-kit/variable-resolver.js +163 -0
- package/docs/ads-system.md +109 -0
- package/docs/classy-v2/DIRECTION.md +92 -0
- package/docs/classy-v2/draft-1.html +1932 -0
- package/docs/classy-v2/draft-2.html +1956 -0
- package/docs/frontmatter.md +153 -0
- package/docs/index.md +254 -0
- package/docs/libs.md +298 -0
- package/docs/omega-sections-spec.md +159 -0
- package/docs/page-contract.md +112 -0
- package/docs/sections.md +845 -0
- package/docs/shared/agent-docs.md +89 -0
- package/docs/shared/analytics.md +612 -0
- package/docs/shared/brands.md +51 -0
- package/docs/shared/breaking-changes.md +497 -0
- package/docs/shared/config.md +1387 -0
- package/docs/shared/deploys.md +215 -0
- package/docs/shared/icons.md +201 -0
- package/docs/shared/local-dev.md +147 -0
- package/docs/shared/logging.md +202 -0
- package/docs/shared/monitoring.md +153 -0
- package/docs/shared/publishing.md +183 -0
- package/docs/shared/rulings.md +34 -0
- package/docs/shared/testing.md +147 -0
- package/docs/shared/theming.md +604 -0
- package/docs/shared/translation.md +291 -0
- package/docs/shared/updates.md +61 -0
- package/docs/template-kit.md +128 -0
- package/docs/test-framework.md +163 -0
- package/package.json +122 -0
- package/runtime/boot.js +149 -0
- package/runtime/icons.js +77 -0
- package/runtime/manager.js +36 -0
- package/scaffold/.github/workflows/build.yml +139 -0
- package/scaffold/.nvmrc +1 -0
- package/scaffold/AGENTS.md +55 -0
- package/scaffold/CLAUDE.md +1 -0
- package/scaffold/_.gitattributes +4 -0
- package/scaffold/_.gitignore +27 -0
- package/scaffold/config/omega.json5 +20 -0
- package/scaffold/src/assets/css/pages/.gitkeep +0 -0
- package/scaffold/src/assets/images/.gitkeep +0 -0
- package/scaffold/src/assets/js/pages/.gitkeep +0 -0
- package/scaffold/src/pages/.gitkeep +0 -0
- package/scaffold/src/pages/example.md.txt +94 -0
- package/scaffold/src/service-worker.js +16 -0
- package/sw/entry.js +19 -0
- package/sw/manager.js +281 -0
- package/themes/_template/README.md +115 -0
- package/themes/_template/_config.scss +60 -0
- package/themes/_template/_theme.js +14 -0
- package/themes/_template/_theme.scss +28 -0
- package/themes/_template/css/base/_root.scss +19 -0
- package/themes/_template/css/components/_components.scss +23 -0
- package/themes/base/README.md +5 -0
- package/themes/base/_components/data/org-chart/component.html +33 -0
- package/themes/base/_components/data/org-chart/component.json5 +33 -0
- package/themes/base/_components/data/org-chart/component.scss +183 -0
- package/themes/base/_components/heading/masthead/component.html +22 -0
- package/themes/base/_components/heading/masthead/component.json5 +30 -0
- package/themes/base/_components/heading/section-head/component.html +18 -0
- package/themes/base/_components/heading/section-head/component.json5 +27 -0
- package/themes/base/_components/pricing/features/component.html +29 -0
- package/themes/base/_components/pricing/features/component.json5 +30 -0
- package/themes/base/_hero/orbit/index.html +30 -0
- package/themes/base/_hero/orbit/script.js +33 -0
- package/themes/base/_hero/orbit/style.scss +133 -0
- package/themes/base/_includes/admin/sections/sidebar.html +3 -0
- package/themes/base/_includes/admin/sections/topbar.html +3 -0
- package/themes/base/_includes/backend/sections/sidebar.html +3 -0
- package/themes/base/_includes/backend/sections/topbar.html +3 -0
- package/themes/base/_includes/frontend/components/connection-card.html +49 -0
- package/themes/base/_includes/frontend/components/post-card.html +54 -0
- package/themes/base/_includes/frontend/sections/account-connections.html +42 -0
- package/themes/base/_includes/frontend/sections/account-section-header.html +11 -0
- package/themes/base/_includes/frontend/sections/footer.html +154 -0
- package/themes/base/_includes/frontend/sections/nav.html +276 -0
- package/themes/base/_includes/global/sections/account.html +72 -0
- package/themes/base/_includes/global/sections/app-sidebar.html +248 -0
- package/themes/base/_includes/global/sections/app-topbar.html +228 -0
- package/themes/base/_includes/global/sections/page-header.html +99 -0
- package/themes/base/_layouts/admin/core/minimal-viewport-locked.html +22 -0
- package/themes/base/_layouts/admin/core/minimal.html +23 -0
- package/themes/base/_layouts/backend/core/base.html +57 -0
- package/themes/base/_layouts/backend/core/minimal-viewport-locked.html +32 -0
- package/themes/base/_layouts/backend/core/minimal.html +32 -0
- package/themes/base/_layouts/backend/pages/dashboard/index.html +230 -0
- package/themes/base/_layouts/frontend/core/base.html +31 -0
- package/themes/base/_layouts/frontend/core/cover.html +40 -0
- package/themes/base/_layouts/frontend/core/minimal.html +47 -0
- package/themes/base/_layouts/frontend/pages/404.html +54 -0
- package/themes/base/_layouts/frontend/pages/about.html +144 -0
- package/themes/base/_layouts/frontend/pages/account/index.html +2104 -0
- package/themes/base/_layouts/frontend/pages/alternatives/alternative.html +319 -0
- package/themes/base/_layouts/frontend/pages/alternatives/index.html +186 -0
- package/themes/base/_layouts/frontend/pages/app.html +142 -0
- package/themes/base/_layouts/frontend/pages/auth/reset.html +53 -0
- package/themes/base/_layouts/frontend/pages/auth/signin.html +90 -0
- package/themes/base/_layouts/frontend/pages/auth/signup.html +141 -0
- package/themes/base/_layouts/frontend/pages/auth/token.html +44 -0
- package/themes/base/_layouts/frontend/pages/blog/categories/category.html +88 -0
- package/themes/base/_layouts/frontend/pages/blog/categories/index.html +88 -0
- package/themes/base/_layouts/frontend/pages/blog/index.html +255 -0
- package/themes/base/_layouts/frontend/pages/blog/post.html +261 -0
- package/themes/base/_layouts/frontend/pages/blog/tags/index.html +84 -0
- package/themes/base/_layouts/frontend/pages/blog/tags/tag.html +88 -0
- package/themes/base/_layouts/frontend/pages/collection/category.html +72 -0
- package/themes/base/_layouts/frontend/pages/collection/document.html +54 -0
- package/themes/base/_layouts/frontend/pages/collection/index.html +84 -0
- package/themes/base/_layouts/frontend/pages/connections/callback.html +55 -0
- package/themes/base/_layouts/frontend/pages/contact.html +214 -0
- package/themes/base/_layouts/frontend/pages/download.html +793 -0
- package/themes/base/_layouts/frontend/pages/extension/index.html +253 -0
- package/themes/base/_layouts/frontend/pages/extension/installed.html +198 -0
- package/themes/base/_layouts/frontend/pages/feedback.html +171 -0
- package/themes/base/_layouts/frontend/pages/index.html +66 -0
- package/themes/base/_layouts/frontend/pages/legal/document.html +78 -0
- package/themes/base/_layouts/frontend/pages/payment/checkout.html +459 -0
- package/themes/base/_layouts/frontend/pages/payment/confirmation.html +131 -0
- package/themes/base/_layouts/frontend/pages/portal/email-preferences.html +104 -0
- package/themes/base/_layouts/frontend/pages/pricing.html +596 -0
- package/themes/base/_layouts/frontend/pages/status.html +361 -0
- package/themes/base/_layouts/frontend/pages/team/index.html +210 -0
- package/themes/base/_layouts/frontend/pages/team/member.html +125 -0
- package/themes/base/_layouts/frontend/pages/updates/index.html +119 -0
- package/themes/base/_layouts/frontend/pages/updates/update.html +118 -0
- package/themes/base/_sections/about/hero/section.html +68 -0
- package/themes/base/_sections/about/hero/section.json5 +58 -0
- package/themes/base/_sections/about/letter/section.html +60 -0
- package/themes/base/_sections/about/letter/section.json5 +56 -0
- package/themes/base/_sections/about/photo-band/section.html +24 -0
- package/themes/base/_sections/about/photo-band/section.json5 +23 -0
- package/themes/base/_sections/about/principles/section.html +17 -0
- package/themes/base/_sections/about/principles/section.json5 +34 -0
- package/themes/base/_sections/about/timeline/section.html +20 -0
- package/themes/base/_sections/about/timeline/section.json5 +34 -0
- package/themes/base/_sections/marketing/bento/section.html +91 -0
- package/themes/base/_sections/marketing/bento/section.json5 +152 -0
- package/themes/base/_sections/marketing/cta/section.html +44 -0
- package/themes/base/_sections/marketing/cta/section.json5 +47 -0
- package/themes/base/_sections/marketing/faq/section.html +52 -0
- package/themes/base/_sections/marketing/faq/section.json5 +68 -0
- package/themes/base/_sections/marketing/hero/section.html +349 -0
- package/themes/base/_sections/marketing/hero/section.json5 +335 -0
- package/themes/base/_sections/marketing/newsletter-cta/section.html +38 -0
- package/themes/base/_sections/marketing/newsletter-cta/section.js +86 -0
- package/themes/base/_sections/marketing/newsletter-cta/section.json5 +29 -0
- package/themes/base/_sections/marketing/pricing-cards/section.html +115 -0
- package/themes/base/_sections/marketing/pricing-cards/section.json5 +72 -0
- package/themes/base/_sections/marketing/product-demo/section.html +62 -0
- package/themes/base/_sections/marketing/product-demo/section.js +44 -0
- package/themes/base/_sections/marketing/product-demo/section.json5 +52 -0
- package/themes/base/_sections/marketing/prose/section.html +22 -0
- package/themes/base/_sections/marketing/prose/section.json5 +41 -0
- package/themes/base/_sections/marketing/showcase/section.html +35 -0
- package/themes/base/_sections/marketing/showcase/section.json5 +52 -0
- package/themes/base/_sections/marketing/stats/section.html +32 -0
- package/themes/base/_sections/marketing/stats/section.json5 +44 -0
- package/themes/base/_sections/marketing/testimonials/section.html +54 -0
- package/themes/base/_sections/marketing/testimonials/section.json5 +70 -0
- package/themes/base/_sections/marketing/trusted-by/section.html +30 -0
- package/themes/base/_sections/marketing/trusted-by/section.json5 +38 -0
- package/themes/base/_sections/verts/unit/section.html +7 -0
- package/themes/base/_sections/verts/unit/section.js +22 -0
- package/themes/base/_sections/verts/unit/section.json5 +24 -0
- package/themes/base/_sections/verts/unit/section.scss +24 -0
- package/themes/base/_theme.js +13 -0
- package/themes/base/_theme.scss +4 -0
- package/themes/bootstrap/_theme.js +16 -0
- package/themes/bootstrap/_theme.scss +11 -0
- package/themes/bootstrap/js/index.esm.js +19 -0
- package/themes/bootstrap/js/index.umd.js +34 -0
- package/themes/bootstrap/js/src/alert.js +87 -0
- package/themes/bootstrap/js/src/base-component.js +86 -0
- package/themes/bootstrap/js/src/button.js +72 -0
- package/themes/bootstrap/js/src/carousel.js +474 -0
- package/themes/bootstrap/js/src/collapse.js +297 -0
- package/themes/bootstrap/js/src/dom/data.js +55 -0
- package/themes/bootstrap/js/src/dom/event-handler.js +317 -0
- package/themes/bootstrap/js/src/dom/manipulator.js +71 -0
- package/themes/bootstrap/js/src/dom/selector-engine.js +126 -0
- package/themes/bootstrap/js/src/dropdown.js +458 -0
- package/themes/bootstrap/js/src/modal.js +378 -0
- package/themes/bootstrap/js/src/offcanvas.js +282 -0
- package/themes/bootstrap/js/src/popover.js +97 -0
- package/themes/bootstrap/js/src/scrollspy.js +296 -0
- package/themes/bootstrap/js/src/tab.js +315 -0
- package/themes/bootstrap/js/src/toast.js +224 -0
- package/themes/bootstrap/js/src/tooltip.js +632 -0
- package/themes/bootstrap/js/src/util/backdrop.js +151 -0
- package/themes/bootstrap/js/src/util/component-functions.js +35 -0
- package/themes/bootstrap/js/src/util/config.js +65 -0
- package/themes/bootstrap/js/src/util/focustrap.js +115 -0
- package/themes/bootstrap/js/src/util/index.js +306 -0
- package/themes/bootstrap/js/src/util/sanitizer.js +117 -0
- package/themes/bootstrap/js/src/util/scrollbar.js +114 -0
- package/themes/bootstrap/js/src/util/swipe.js +146 -0
- package/themes/bootstrap/js/src/util/template-factory.js +160 -0
- package/themes/bootstrap/overrides/_accordion.scss +21 -0
- package/themes/bootstrap/overrides/_avatars.scss +51 -0
- package/themes/bootstrap/overrides/_blog-images.scss +45 -0
- package/themes/bootstrap/overrides/_buttons-adaptive.scss +141 -0
- package/themes/bootstrap/overrides/_color-shades.scss +25 -0
- package/themes/bootstrap/overrides/_cursor-utilities.scss +13 -0
- package/themes/bootstrap/overrides/_index.scss +30 -0
- package/themes/bootstrap/overrides/_links.scss +26 -0
- package/themes/bootstrap/overrides/_soft-colors.scss +99 -0
- package/themes/bootstrap/overrides/_spacing-extended.scss +74 -0
- package/themes/bootstrap/overrides/_spinners.scss +22 -0
- package/themes/bootstrap/overrides/_typography-utilities.scss +40 -0
- package/themes/bootstrap/scss/_accordion.scss +153 -0
- package/themes/bootstrap/scss/_alert.scss +68 -0
- package/themes/bootstrap/scss/_badge.scss +38 -0
- package/themes/bootstrap/scss/_breadcrumb.scss +40 -0
- package/themes/bootstrap/scss/_button-group.scss +147 -0
- package/themes/bootstrap/scss/_buttons.scss +216 -0
- package/themes/bootstrap/scss/_card.scss +238 -0
- package/themes/bootstrap/scss/_carousel.scss +226 -0
- package/themes/bootstrap/scss/_close.scss +66 -0
- package/themes/bootstrap/scss/_containers.scss +41 -0
- package/themes/bootstrap/scss/_dropdown.scss +250 -0
- package/themes/bootstrap/scss/_forms.scss +9 -0
- package/themes/bootstrap/scss/_functions.scss +302 -0
- package/themes/bootstrap/scss/_grid.scss +39 -0
- package/themes/bootstrap/scss/_helpers.scss +12 -0
- package/themes/bootstrap/scss/_images.scss +42 -0
- package/themes/bootstrap/scss/_list-group.scss +199 -0
- package/themes/bootstrap/scss/_maps.scss +174 -0
- package/themes/bootstrap/scss/_mixins.scss +42 -0
- package/themes/bootstrap/scss/_modal.scss +240 -0
- package/themes/bootstrap/scss/_nav.scss +197 -0
- package/themes/bootstrap/scss/_navbar.scss +289 -0
- package/themes/bootstrap/scss/_offcanvas.scss +147 -0
- package/themes/bootstrap/scss/_pagination.scss +109 -0
- package/themes/bootstrap/scss/_placeholders.scss +51 -0
- package/themes/bootstrap/scss/_popover.scss +196 -0
- package/themes/bootstrap/scss/_progress.scss +68 -0
- package/themes/bootstrap/scss/_reboot.scss +611 -0
- package/themes/bootstrap/scss/_root.scss +187 -0
- package/themes/bootstrap/scss/_spinners.scss +85 -0
- package/themes/bootstrap/scss/_tables.scss +171 -0
- package/themes/bootstrap/scss/_toasts.scss +73 -0
- package/themes/bootstrap/scss/_tooltip.scss +119 -0
- package/themes/bootstrap/scss/_transitions.scss +27 -0
- package/themes/bootstrap/scss/_type.scss +106 -0
- package/themes/bootstrap/scss/_utilities.scss +806 -0
- package/themes/bootstrap/scss/_variables-dark.scss +102 -0
- package/themes/bootstrap/scss/_variables.scss +1753 -0
- package/themes/bootstrap/scss/bootstrap-grid.scss +62 -0
- package/themes/bootstrap/scss/bootstrap-reboot.scss +10 -0
- package/themes/bootstrap/scss/bootstrap-utilities.scss +19 -0
- package/themes/bootstrap/scss/bootstrap.scss +52 -0
- package/themes/bootstrap/scss/forms/_floating-labels.scss +97 -0
- package/themes/bootstrap/scss/forms/_form-check.scss +189 -0
- package/themes/bootstrap/scss/forms/_form-control.scss +214 -0
- package/themes/bootstrap/scss/forms/_form-range.scss +91 -0
- package/themes/bootstrap/scss/forms/_form-select.scss +80 -0
- package/themes/bootstrap/scss/forms/_form-text.scss +11 -0
- package/themes/bootstrap/scss/forms/_input-group.scss +132 -0
- package/themes/bootstrap/scss/forms/_labels.scss +36 -0
- package/themes/bootstrap/scss/forms/_validation.scss +12 -0
- package/themes/bootstrap/scss/helpers/_clearfix.scss +3 -0
- package/themes/bootstrap/scss/helpers/_color-bg.scss +7 -0
- package/themes/bootstrap/scss/helpers/_colored-links.scss +30 -0
- package/themes/bootstrap/scss/helpers/_focus-ring.scss +5 -0
- package/themes/bootstrap/scss/helpers/_icon-link.scss +25 -0
- package/themes/bootstrap/scss/helpers/_position.scss +36 -0
- package/themes/bootstrap/scss/helpers/_ratio.scss +26 -0
- package/themes/bootstrap/scss/helpers/_stacks.scss +15 -0
- package/themes/bootstrap/scss/helpers/_stretched-link.scss +15 -0
- package/themes/bootstrap/scss/helpers/_text-truncation.scss +7 -0
- package/themes/bootstrap/scss/helpers/_visually-hidden.scss +8 -0
- package/themes/bootstrap/scss/helpers/_vr.scss +8 -0
- package/themes/bootstrap/scss/mixins/_alert.scss +18 -0
- package/themes/bootstrap/scss/mixins/_backdrop.scss +14 -0
- package/themes/bootstrap/scss/mixins/_banner.scss +7 -0
- package/themes/bootstrap/scss/mixins/_border-radius.scss +78 -0
- package/themes/bootstrap/scss/mixins/_box-shadow.scss +18 -0
- package/themes/bootstrap/scss/mixins/_breakpoints.scss +127 -0
- package/themes/bootstrap/scss/mixins/_buttons.scss +70 -0
- package/themes/bootstrap/scss/mixins/_caret.scss +69 -0
- package/themes/bootstrap/scss/mixins/_clearfix.scss +9 -0
- package/themes/bootstrap/scss/mixins/_color-mode.scss +21 -0
- package/themes/bootstrap/scss/mixins/_color-scheme.scss +7 -0
- package/themes/bootstrap/scss/mixins/_container.scss +11 -0
- package/themes/bootstrap/scss/mixins/_deprecate.scss +10 -0
- package/themes/bootstrap/scss/mixins/_forms.scss +163 -0
- package/themes/bootstrap/scss/mixins/_gradients.scss +47 -0
- package/themes/bootstrap/scss/mixins/_grid.scss +151 -0
- package/themes/bootstrap/scss/mixins/_image.scss +16 -0
- package/themes/bootstrap/scss/mixins/_list-group.scss +26 -0
- package/themes/bootstrap/scss/mixins/_lists.scss +7 -0
- package/themes/bootstrap/scss/mixins/_pagination.scss +10 -0
- package/themes/bootstrap/scss/mixins/_reset-text.scss +17 -0
- package/themes/bootstrap/scss/mixins/_resize.scss +6 -0
- package/themes/bootstrap/scss/mixins/_table-variants.scss +24 -0
- package/themes/bootstrap/scss/mixins/_text-truncate.scss +8 -0
- package/themes/bootstrap/scss/mixins/_transition.scss +26 -0
- package/themes/bootstrap/scss/mixins/_utilities.scss +97 -0
- package/themes/bootstrap/scss/mixins/_visually-hidden.scss +38 -0
- package/themes/bootstrap/scss/tests/jasmine.js +16 -0
- package/themes/bootstrap/scss/tests/mixins/_auto-import-of-variables-dark.test.scss +7 -0
- package/themes/bootstrap/scss/tests/mixins/_color-modes.test.scss +69 -0
- package/themes/bootstrap/scss/tests/mixins/_media-query-color-mode-full.test.scss +8 -0
- package/themes/bootstrap/scss/tests/mixins/_utilities.test.scss +393 -0
- package/themes/bootstrap/scss/tests/sass-true/register.js +14 -0
- package/themes/bootstrap/scss/tests/sass-true/runner.js +17 -0
- package/themes/bootstrap/scss/tests/utilities/_api.test.scss +75 -0
- package/themes/bootstrap/scss/utilities/_api.scss +47 -0
- package/themes/bootstrap/scss/vendor/_rfs.scss +348 -0
- package/themes/classy/README.md +89 -0
- package/themes/classy/_config.scss +245 -0
- package/themes/classy/_theme.js +31 -0
- package/themes/classy/_theme.scss +57 -0
- package/themes/classy/css/app/_panels.scss +183 -0
- package/themes/classy/css/base/_fonts.scss +79 -0
- package/themes/classy/css/base/_no-raise.scss +49 -0
- package/themes/classy/css/base/_root.scss +113 -0
- package/themes/classy/css/base/_typography.scss +154 -0
- package/themes/classy/css/base/_utilities.scss +284 -0
- package/themes/classy/css/components/_alerts.scss +51 -0
- package/themes/classy/css/components/_badges.scss +46 -0
- package/themes/classy/css/components/_buttons.scss +175 -0
- package/themes/classy/css/components/_cards.scss +41 -0
- package/themes/classy/css/components/_dropdowns.scss +48 -0
- package/themes/classy/css/components/_forms.scss +171 -0
- package/themes/classy/css/components/_receipt.scss +45 -0
- package/themes/classy/css/layout/_footer.scss +298 -0
- package/themes/classy/css/layout/_general.scss +209 -0
- package/themes/classy/css/layout/_nav.scss +154 -0
- package/themes/classy/css/layout/_shell.scss +458 -0
- package/themes/classy/css/marketing/_bento.scss +238 -0
- package/themes/classy/css/marketing/_content.scss +1328 -0
- package/themes/classy/css/marketing/_downloads.scss +246 -0
- package/themes/classy/css/marketing/_hero.scss +311 -0
- package/themes/classy/css/marketing/_sections.scss +649 -0
- package/themes/classy/css/pages/404/index.scss +67 -0
- package/themes/classy/css/pages/_auth.scss +235 -0
- package/themes/classy/css/pages/admin/firebase/index.scss +22 -0
- package/themes/classy/css/pages/blog/[slug].scss +56 -0
- package/themes/classy/css/pages/cookies.scss +2 -0
- package/themes/classy/css/pages/dashboard/account/index.scss +31 -0
- package/themes/classy/css/pages/feedback/index.scss +39 -0
- package/themes/classy/css/pages/legal/_document.scss +192 -0
- package/themes/classy/css/pages/payment/checkout/index.scss +585 -0
- package/themes/classy/css/pages/payment/confirmation/index.scss +9 -0
- package/themes/classy/css/pages/privacy.scss +2 -0
- package/themes/classy/css/pages/status/index.scss +164 -0
- package/themes/classy/css/pages/terms.scss +2 -0
- package/themes/classy/css/pages/updates/index.scss +128 -0
- package/themes/classy/fonts/inter-italic-latin-ext.woff2 +0 -0
- package/themes/classy/fonts/inter-italic-latin.woff2 +0 -0
- package/themes/classy/fonts/inter-normal-latin-ext.woff2 +0 -0
- package/themes/classy/fonts/inter-normal-latin.woff2 +0 -0
- package/themes/classy/fonts/newsreader-italic-latin-ext.woff2 +0 -0
- package/themes/classy/fonts/newsreader-italic-latin.woff2 +0 -0
- package/themes/classy/fonts/newsreader-normal-latin-ext.woff2 +0 -0
- package/themes/classy/fonts/newsreader-normal-latin.woff2 +0 -0
- package/themes/classy/js/hero-demo-form.js +56 -0
- package/themes/neobrutalism/README.md +118 -0
- package/themes/neobrutalism/_config.scss +139 -0
- package/themes/neobrutalism/_layouts/frontend/core/base.html +30 -0
- package/themes/neobrutalism/_layouts/frontend/pages/index.html +275 -0
- package/themes/neobrutalism/_theme.js +24 -0
- package/themes/neobrutalism/_theme.scss +61 -0
- package/themes/neobrutalism/css/base/_mixins.scss +46 -0
- package/themes/neobrutalism/css/base/_root.scss +169 -0
- package/themes/neobrutalism/css/base/_typography.scss +61 -0
- package/themes/neobrutalism/css/base/_utilities.scss +89 -0
- package/themes/neobrutalism/css/components/_billing-toggle.scss +74 -0
- package/themes/neobrutalism/css/components/_buttons.scss +148 -0
- package/themes/neobrutalism/css/components/_cards.scss +47 -0
- package/themes/neobrutalism/css/components/_forms.scss +88 -0
- package/themes/neobrutalism/css/components/_marketing.scss +244 -0
- package/themes/neobrutalism/css/layout/_general.scss +213 -0
- package/themes/neobrutalism/css/layout/_navigation.scss +171 -0
- package/themes/neobrutalism/css/pages/index.scss +203 -0
- package/themes/neobrutalism/css/pages/pricing/index.scss +58 -0
- package/themes/neobrutalism/css/pages/test/libraries/layers/index.scss +7 -0
- package/themes/neobrutalism/js/pages/test/libraries/layers/index.js +9 -0
- package/themes/newsflash/README.md +117 -0
- package/themes/newsflash/_components/heading/lede/component.html +14 -0
- package/themes/newsflash/_components/heading/lede/component.json5 +23 -0
- package/themes/newsflash/_components/heading/rule-head/component.html +17 -0
- package/themes/newsflash/_components/heading/rule-head/component.json5 +23 -0
- package/themes/newsflash/_components/news/byline/component.html +12 -0
- package/themes/newsflash/_components/news/byline/component.json5 +18 -0
- package/themes/newsflash/_components/news/story-card/component.html +25 -0
- package/themes/newsflash/_components/news/story-card/component.json5 +21 -0
- package/themes/newsflash/_config.scss +147 -0
- package/themes/newsflash/_layouts/frontend/core/base.html +51 -0
- package/themes/newsflash/_layouts/frontend/pages/blog/index.html +299 -0
- package/themes/newsflash/_layouts/frontend/pages/blog/post.html +235 -0
- package/themes/newsflash/_layouts/frontend/pages/index.html +328 -0
- package/themes/newsflash/_sections/marketing/desks/section.html +39 -0
- package/themes/newsflash/_sections/marketing/desks/section.json5 +49 -0
- package/themes/newsflash/_sections/marketing/newsletter-cta/section.html +103 -0
- package/themes/newsflash/_sections/marketing/newsletter-cta/section.json5 +50 -0
- package/themes/newsflash/_sections/marketing/rundown/section.html +28 -0
- package/themes/newsflash/_sections/marketing/rundown/section.json5 +40 -0
- package/themes/newsflash/_theme.js +24 -0
- package/themes/newsflash/_theme.scss +70 -0
- package/themes/newsflash/css/base/_fonts.scss +80 -0
- package/themes/newsflash/css/base/_mixins.scss +51 -0
- package/themes/newsflash/css/base/_root.scss +257 -0
- package/themes/newsflash/css/base/_typography.scss +49 -0
- package/themes/newsflash/css/base/_utilities.scss +122 -0
- package/themes/newsflash/css/components/_badges.scss +65 -0
- package/themes/newsflash/css/components/_billing-toggle.scss +61 -0
- package/themes/newsflash/css/components/_buttons.scss +139 -0
- package/themes/newsflash/css/components/_cards.scss +47 -0
- package/themes/newsflash/css/components/_editorial.scss +173 -0
- package/themes/newsflash/css/components/_forms.scss +75 -0
- package/themes/newsflash/css/components/_infinite-scroll.scss +102 -0
- package/themes/newsflash/css/components/_panels.scss +156 -0
- package/themes/newsflash/css/components/_ticker.scss +67 -0
- package/themes/newsflash/css/layout/_general.scss +330 -0
- package/themes/newsflash/css/layout/_navigation.scss +168 -0
- package/themes/newsflash/css/pages/404/index.scss +79 -0
- package/themes/newsflash/css/pages/blog/[slug].scss +186 -0
- package/themes/newsflash/css/pages/blog/index.scss +17 -0
- package/themes/newsflash/css/pages/index.scss +157 -0
- package/themes/newsflash/css/pages/pricing/index.scss +55 -0
- package/themes/newsflash/css/pages/test/libraries/layers/index.scss +7 -0
- package/themes/newsflash/fonts/fraunces-italic-latin-ext.woff2 +0 -0
- package/themes/newsflash/fonts/fraunces-italic-latin.woff2 +0 -0
- package/themes/newsflash/fonts/fraunces-normal-latin-ext.woff2 +0 -0
- package/themes/newsflash/fonts/fraunces-normal-latin.woff2 +0 -0
- package/themes/newsflash/fonts/schibsted-grotesk-italic-latin-ext.woff2 +0 -0
- package/themes/newsflash/fonts/schibsted-grotesk-italic-latin.woff2 +0 -0
- package/themes/newsflash/fonts/schibsted-grotesk-normal-latin-ext.woff2 +0 -0
- package/themes/newsflash/fonts/schibsted-grotesk-normal-latin.woff2 +0 -0
- package/themes/newsflash/js/pages/blog/[slug].js +29 -0
- package/themes/newsflash/js/pages/test/libraries/layers/index.js +9 -0
- package/translations/es/pages/404.json +86 -0
- package/translations/es/pages/account.json +36 -0
- package/translations/es/pages/app.json +44 -0
- package/translations/es/pages/cancel.json +36 -0
- package/translations/es/pages/change-password.json +36 -0
- package/translations/es/pages/connections/callback.json +41 -0
- package/translations/es/pages/dashboard/account.json +475 -0
- package/translations/es/pages/dashboard.json +36 -0
- package/translations/es/pages/forgot.json +36 -0
- package/translations/es/pages/join.json +36 -0
- package/translations/es/pages/login.json +36 -0
- package/translations/es/pages/payment/checkout.json +83 -0
- package/translations/es/pages/payment/confirmation.json +62 -0
- package/translations/es/pages/portal/email-preferences.json +46 -0
- package/translations/es/pages/recover.json +36 -0
- package/translations/es/pages/refund.json +36 -0
- package/translations/es/pages/register.json +36 -0
- package/translations/es/pages/reset-password.json +36 -0
- package/translations/es/pages/reset.json +42 -0
- package/translations/es/pages/signin.json +45 -0
- package/translations/es/pages/signup.json +60 -0
- package/translations/es/pages/token.json +39 -0
- package/translations/fa/pages/404.json +86 -0
- package/translations/fa/pages/account.json +36 -0
- package/translations/fa/pages/app.json +44 -0
- package/translations/fa/pages/cancel.json +36 -0
- package/translations/fa/pages/change-password.json +36 -0
- package/translations/fa/pages/connections/callback.json +41 -0
- package/translations/fa/pages/dashboard/account.json +475 -0
- package/translations/fa/pages/dashboard.json +36 -0
- package/translations/fa/pages/forgot.json +36 -0
- package/translations/fa/pages/join.json +36 -0
- package/translations/fa/pages/login.json +36 -0
- package/translations/fa/pages/payment/checkout.json +83 -0
- package/translations/fa/pages/payment/confirmation.json +62 -0
- package/translations/fa/pages/portal/email-preferences.json +46 -0
- package/translations/fa/pages/recover.json +36 -0
- package/translations/fa/pages/refund.json +36 -0
- package/translations/fa/pages/register.json +36 -0
- package/translations/fa/pages/reset-password.json +36 -0
- package/translations/fa/pages/reset.json +42 -0
- package/translations/fa/pages/signin.json +45 -0
- package/translations/fa/pages/signup.json +60 -0
- package/translations/fa/pages/token.json +39 -0
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Content collections for the OMEGA engine: posts, alternatives, team, and
|
|
3
|
+
* the blog taxonomy aggregated from posts' `post.categories`/`post.tags`
|
|
4
|
+
* (jekyll-uj-powertools' blog-taxonomy generator equivalent), plus the
|
|
5
|
+
* URL-sorted `allByUrl` view the meta-files iterate. Every content
|
|
6
|
+
* collection is mirrored into the template-kit holder so omega_* tags
|
|
7
|
+
* (omega_member) can read it mid-render.
|
|
8
|
+
*
|
|
9
|
+
* A brand's OWN collections (#207, `targets.web.collections`) ride the same
|
|
10
|
+
* registration: one collection keyed by name plus a `<name>Categories`
|
|
11
|
+
* taxonomy over the configured frontmatter field, which is what the
|
|
12
|
+
* synthesized listing/category pages paginate (src/dynamic-pages.js).
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
// Jekyll-default slugify — taxonomy slugs must match what templates' slugify
|
|
16
|
+
// filter produces, so both come from the same template-kit implementation.
|
|
17
|
+
const { slugify } = require('./vendor/template-kit/jekyll-compat.js');
|
|
18
|
+
|
|
19
|
+
// Deterministic post order shared by the posts collection AND taxonomy
|
|
20
|
+
// aggregation: date desc, slug asc tie-break — same-date posts must order
|
|
21
|
+
// identically across builds (proven engine-identical in the bake-off).
|
|
22
|
+
const byDateThenSlug = (a, b) => (b.date - a.date) || a.page.fileSlug.localeCompare(b.page.fileSlug);
|
|
23
|
+
|
|
24
|
+
// The URL sorts of the dateless collections. A brand's own collection uses
|
|
25
|
+
// the ascending one: an arbitrary document carries no reliable date (Eleventy
|
|
26
|
+
// falls back to the file's mtime, which differs per machine and per clone),
|
|
27
|
+
// so URL order is the only order that reproduces across builds.
|
|
28
|
+
const byUrlAsc = (a, b) => a.url.localeCompare(b.url);
|
|
29
|
+
const byUrlDesc = (a, b) => b.url.localeCompare(a.url);
|
|
30
|
+
|
|
31
|
+
// The framework's own collections: the consumer dir each one's documents live
|
|
32
|
+
// in, the URL base their permalinks and pages hang off (posts publish under
|
|
33
|
+
// /blog), and the order the collection lists them in. The engine's directory
|
|
34
|
+
// tagging and permalink conventions read this list, and a brand collection
|
|
35
|
+
// may not take one of these names (src/dynamic-pages.js).
|
|
36
|
+
const BUILT_IN_COLLECTIONS = [
|
|
37
|
+
{ name: 'posts', dir: '_posts', base: '/blog', order: byDateThenSlug },
|
|
38
|
+
{ name: 'alternatives', dir: '_alternatives', base: '/alternatives', order: byUrlAsc },
|
|
39
|
+
{ name: 'team', dir: '_team', base: '/team', order: byUrlAsc },
|
|
40
|
+
{ name: 'updates', dir: '_updates', base: '/updates', order: byUrlDesc },
|
|
41
|
+
];
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Register the OMEGA collections on an Eleventy config.
|
|
45
|
+
* @param {object} eleventyConfig
|
|
46
|
+
* @param {Map<string, object[]>} collectionsHolder - template-kit's collection view
|
|
47
|
+
* @param {Array<object>} [dynamicCollections] - the brand's own collections (readCollections' output)
|
|
48
|
+
*/
|
|
49
|
+
function registerCollections(eleventyConfig, collectionsHolder, dynamicCollections) {
|
|
50
|
+
// Jekyll-style doc id ('/team/ian', '/blog/slug') — the shape the omega_member
|
|
51
|
+
// and omega_post tags match on and derive asset paths from. inputPath only as
|
|
52
|
+
// a fallback for url-less docs.
|
|
53
|
+
//
|
|
54
|
+
// `templateContent` rides along LAZY and non-enumerable (#711), which is what
|
|
55
|
+
// lets the engine flatten these holder docs with the same `jekyllDoc` the
|
|
56
|
+
// paginator uses: a `site.<name>` doc's `content` reads through to the
|
|
57
|
+
// Eleventy item's rendered body at RENDER time. Eager or enumerable would
|
|
58
|
+
// throw Eleventy's premature-use error — the holder fills while collections
|
|
59
|
+
// compute, and every data walk that copies a doc would touch it.
|
|
60
|
+
const toDoc = (item) => {
|
|
61
|
+
const doc = {
|
|
62
|
+
id: String(item.url || '').replace(/\/+$/, '') || item.inputPath,
|
|
63
|
+
url: item.url,
|
|
64
|
+
date: item.date,
|
|
65
|
+
data: item.data,
|
|
66
|
+
};
|
|
67
|
+
Object.defineProperty(doc, 'templateContent', {
|
|
68
|
+
get: () => item.templateContent,
|
|
69
|
+
enumerable: false,
|
|
70
|
+
configurable: true,
|
|
71
|
+
});
|
|
72
|
+
return doc;
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
// One registration shape for every collection: the documents the directory
|
|
76
|
+
// tagging marked, in the collection's own order, mirrored into the holder.
|
|
77
|
+
const addContentCollection = ({ name, order }) => {
|
|
78
|
+
eleventyConfig.addCollection(name, (api) => {
|
|
79
|
+
const docs = api.getFilteredByTag(name).sort(order);
|
|
80
|
+
collectionsHolder.set(name, docs.map(toDoc));
|
|
81
|
+
return docs;
|
|
82
|
+
});
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
for (const collection of BUILT_IN_COLLECTIONS) addContentCollection(collection);
|
|
86
|
+
|
|
87
|
+
// Deterministic meta-file emission (sitemap.xml, pages.json): Eleventy's
|
|
88
|
+
// collections.all order varies run-to-run (render/discovery concurrency),
|
|
89
|
+
// so two builds of the SAME tree listed URLs in different orders. The meta
|
|
90
|
+
// templates iterate this URL-sorted copy instead. Byte-order compare (not
|
|
91
|
+
// localeCompare) so the order can never drift across machines/ICU builds.
|
|
92
|
+
eleventyConfig.addCollection('allByUrl', (api) => {
|
|
93
|
+
return api.getAll().sort((a, b) => {
|
|
94
|
+
const au = a.url || '';
|
|
95
|
+
const bu = b.url || '';
|
|
96
|
+
return au < bu ? -1 : au > bu ? 1 : 0;
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
eleventyConfig.addCollection('postCategories', (api) => aggregateTaxonomy(api, { tag: 'posts', field: 'post.categories', order: byDateThenSlug }));
|
|
101
|
+
eleventyConfig.addCollection('postTags', (api) => aggregateTaxonomy(api, { tag: 'posts', field: 'post.tags', order: byDateThenSlug }));
|
|
102
|
+
|
|
103
|
+
// The brand's own collections (#207): the documents, plus the taxonomy the
|
|
104
|
+
// synthesized category pages paginate over.
|
|
105
|
+
for (const collection of dynamicCollections || []) {
|
|
106
|
+
addContentCollection({ name: collection.name, order: byUrlAsc });
|
|
107
|
+
eleventyConfig.addCollection(collection.taxonomy, (api) => aggregateTaxonomy(api, {
|
|
108
|
+
tag: collection.name,
|
|
109
|
+
field: collection.field,
|
|
110
|
+
order: byUrlAsc,
|
|
111
|
+
}));
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* The DISPLAY name of a taxonomy term. Legacy UJM titleized every term it
|
|
117
|
+
* named a page after — hyphens and underscores are word breaks, then each
|
|
118
|
+
* word capitalizes Ruby-style (first char up, rest down) — so
|
|
119
|
+
* `time-tracking-tools` reads "Time Tracking Tools" in its page's title, h1
|
|
120
|
+
* and description. Keeping the corpus's own spelling drifted every migrating
|
|
121
|
+
* brand's taxonomy SEO titles (#457); the SLUG is untouched, so no URL moves.
|
|
122
|
+
*
|
|
123
|
+
* Runs of separators COLLAPSE. Legacy shipped two spellings of this transform
|
|
124
|
+
* and they disagree only there (blog-taxonomy.rb's `split(/[\s_-]/)` left a
|
|
125
|
+
* double space where dynamic-pages.rb's `split(/[\s_-]+/)` did not), and a
|
|
126
|
+
* double space in a <title> is an artifact, not a contract.
|
|
127
|
+
* @param {string} name - the term as the corpus spelled it
|
|
128
|
+
* @returns {string}
|
|
129
|
+
*/
|
|
130
|
+
function humanizeTerm(name) {
|
|
131
|
+
return String(name)
|
|
132
|
+
.split(/[\s_-]+/)
|
|
133
|
+
.filter(Boolean)
|
|
134
|
+
.map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())
|
|
135
|
+
.join(' ');
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Aggregate a collection's taxonomy from a dotted frontmatter field
|
|
140
|
+
* (`post.categories` for the blog, whatever `targets.web.collections.<name>.field`
|
|
141
|
+
* names for a brand collection). Terms are keyed by SLUG — real corpora mix
|
|
142
|
+
* spellings ("Marketing" ×673 vs "marketing" ×11 in somiibo) and case variants
|
|
143
|
+
* would generate duplicate taxonomy pages at the same permalink (Jekyll
|
|
144
|
+
* silently last-write-won; Eleventy hard-errors). The most frequent spelling
|
|
145
|
+
* becomes the display name, humanized (humanizeTerm); a document never lands
|
|
146
|
+
* in the same term twice.
|
|
147
|
+
* @param {object} api - Eleventy collection API
|
|
148
|
+
* @param {object} options
|
|
149
|
+
* @param {string} options.tag - the collection tag to aggregate
|
|
150
|
+
* @param {string} options.field - dotted frontmatter path (a list, or one value)
|
|
151
|
+
* @param {function} options.order - the collection's document order
|
|
152
|
+
* @returns {Array<{ name: string, slug: string, posts: object[] }>}
|
|
153
|
+
*/
|
|
154
|
+
function aggregateTaxonomy(api, { tag, field, order }) {
|
|
155
|
+
const groups = new Map();
|
|
156
|
+
const posts = api.getFilteredByTag(tag).sort(order);
|
|
157
|
+
|
|
158
|
+
for (const item of posts) {
|
|
159
|
+
// A field holding ONE value (legacy UJM's `recipe.cuisine`) is that
|
|
160
|
+
// document's single term — the list form is the blog's.
|
|
161
|
+
const value = field.split('.').reduce((node, key) => (node == null ? node : node[key]), item.data);
|
|
162
|
+
const names = Array.isArray(value) ? value : (typeof value === 'string' ? [value] : []);
|
|
163
|
+
const seen = new Set();
|
|
164
|
+
for (const name of names) {
|
|
165
|
+
const slug = slugify(name);
|
|
166
|
+
if (!slug || seen.has(slug)) continue;
|
|
167
|
+
seen.add(slug);
|
|
168
|
+
if (!groups.has(slug)) groups.set(slug, { name, slug, posts: [], spellings: new Map() });
|
|
169
|
+
const group = groups.get(slug);
|
|
170
|
+
group.spellings.set(name, (group.spellings.get(name) || 0) + 1);
|
|
171
|
+
group.posts.push(item);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
return [...groups.values()]
|
|
176
|
+
.map(({ spellings, ...group }) => ({
|
|
177
|
+
...group,
|
|
178
|
+
name: humanizeTerm([...spellings.entries()].sort((a, b) => b[1] - a[1])[0][0]),
|
|
179
|
+
}))
|
|
180
|
+
.sort((a, b) => a.name.localeCompare(b.name));
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
module.exports = { registerCollections, BUILT_IN_COLLECTIONS };
|
|
@@ -0,0 +1,470 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `omega audit` — Lighthouse over a production build (the UJM audit port's
|
|
3
|
+
* Lighthouse half). The site builds FULL through the same `omega build`
|
|
4
|
+
* plumbing a deploy runs, dist/ is served on an ephemeral loopback port, and
|
|
5
|
+
* Lighthouse scores the home page plus every page path passed as an argument.
|
|
6
|
+
*
|
|
7
|
+
* Every page also reports its LCP and CLS, and the form factor the run used
|
|
8
|
+
* (Lighthouse's default preset is mobile emulation on Slow 4G, the same shape
|
|
9
|
+
* PageSpeed Insights reports for mobile).
|
|
10
|
+
*
|
|
11
|
+
* Report-only by default (legacy UJM parity: the scores print, the command
|
|
12
|
+
* exits 0). A `--min-<category>` flag ARMS the gate for that category, and
|
|
13
|
+
* `--max-lcp=<ms>` arms the perceived-usability bar (#467) — any page under a
|
|
14
|
+
* stated minimum, or over the stated LCP, fails loudly and exits non-zero.
|
|
15
|
+
*
|
|
16
|
+
* omega audit # home page, report only
|
|
17
|
+
* omega audit /pricing /blog # home + two more pages
|
|
18
|
+
* omega audit --min-performance=90 --min-seo=95 # gated: under = exit 1
|
|
19
|
+
* omega audit --max-lcp=1300 # gated: LCP over 1.3s = exit 1
|
|
20
|
+
*/
|
|
21
|
+
const http = require('node:http');
|
|
22
|
+
const fs = require('node:fs');
|
|
23
|
+
const path = require('node:path');
|
|
24
|
+
const jetpack = require('fs-jetpack');
|
|
25
|
+
const Logger = require('../vendor/devkit/logger.js');
|
|
26
|
+
const { consumerPaths } = require('../consumer.js');
|
|
27
|
+
|
|
28
|
+
const logger = new Logger('audit');
|
|
29
|
+
|
|
30
|
+
// Lighthouse's own category ids, in report order. Each one's threshold flag is
|
|
31
|
+
// `--min-<id>` — one source for the flags, the printout and the gate.
|
|
32
|
+
const CATEGORIES = ['performance', 'accessibility', 'best-practices', 'seo'];
|
|
33
|
+
|
|
34
|
+
const LABELS = {
|
|
35
|
+
performance: 'Performance',
|
|
36
|
+
accessibility: 'Accessibility',
|
|
37
|
+
'best-practices': 'Best Practices',
|
|
38
|
+
seo: 'SEO',
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
// The two field metrics the perceived-usability bar is read from: LCP is the
|
|
42
|
+
// #467 gate (`--max-lcp`), CLS rides along because a late shift is the other
|
|
43
|
+
// half of "usable", and both come free with the performance category.
|
|
44
|
+
const METRIC_AUDITS = {
|
|
45
|
+
lcp: 'largest-contentful-paint',
|
|
46
|
+
cls: 'cumulative-layout-shift',
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const CONTENT_TYPES = {
|
|
50
|
+
'.html': 'text/html; charset=utf-8',
|
|
51
|
+
'.css': 'text/css; charset=utf-8',
|
|
52
|
+
'.js': 'text/javascript; charset=utf-8',
|
|
53
|
+
'.mjs': 'text/javascript; charset=utf-8',
|
|
54
|
+
'.json': 'application/json; charset=utf-8',
|
|
55
|
+
'.xml': 'application/xml; charset=utf-8',
|
|
56
|
+
'.txt': 'text/plain; charset=utf-8',
|
|
57
|
+
'.svg': 'image/svg+xml',
|
|
58
|
+
'.png': 'image/png',
|
|
59
|
+
'.jpg': 'image/jpeg',
|
|
60
|
+
'.jpeg': 'image/jpeg',
|
|
61
|
+
'.gif': 'image/gif',
|
|
62
|
+
'.webp': 'image/webp',
|
|
63
|
+
'.avif': 'image/avif',
|
|
64
|
+
'.ico': 'image/x-icon',
|
|
65
|
+
'.woff': 'font/woff',
|
|
66
|
+
'.woff2': 'font/woff2',
|
|
67
|
+
'.ttf': 'font/ttf',
|
|
68
|
+
'.webmanifest': 'application/manifest+json',
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
module.exports = async function (options) {
|
|
72
|
+
options = options || {};
|
|
73
|
+
|
|
74
|
+
// Parse before building — a typo'd flag must not cost a full build first
|
|
75
|
+
const thresholds = parseThresholds(options);
|
|
76
|
+
const maxLcp = parseMaxLcp(options);
|
|
77
|
+
const pages = parsePages(options);
|
|
78
|
+
const paths = consumerPaths();
|
|
79
|
+
|
|
80
|
+
// FULL production build, never an incremental dev artifact: an audit that
|
|
81
|
+
// does not measure what deploys measures nothing
|
|
82
|
+
await require('./build.js')(options);
|
|
83
|
+
|
|
84
|
+
const missing = pages.filter((page) => !resolveFile(paths.out, page));
|
|
85
|
+
if (missing.length) {
|
|
86
|
+
throw new Error(`No built page for ${missing.join(', ')} — check the paths against ${path.relative(paths.root, paths.out)}/`);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const server = await serveDist(paths.out);
|
|
90
|
+
logger.log(`Serving ${path.relative(paths.root, paths.out)}/ on ${server.origin}`);
|
|
91
|
+
|
|
92
|
+
const results = [];
|
|
93
|
+
let chrome = null;
|
|
94
|
+
try {
|
|
95
|
+
chrome = await launchChrome();
|
|
96
|
+
for (const page of pages) {
|
|
97
|
+
logger.log(`Auditing ${page}...`);
|
|
98
|
+
const { scores, metrics } = await auditPage(`${server.origin}${page}`, chrome.port);
|
|
99
|
+
results.push({ page, scores, metrics });
|
|
100
|
+
logger.log(`${page} — ${formatSummary(scores, metrics)}`);
|
|
101
|
+
}
|
|
102
|
+
} finally {
|
|
103
|
+
if (chrome) {
|
|
104
|
+
await chrome.kill();
|
|
105
|
+
}
|
|
106
|
+
await server.close();
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if (!Object.keys(thresholds).length && maxLcp === null) {
|
|
110
|
+
logger.log('Report only — pass --min-<category> (e.g. --min-performance=90) or --max-lcp=1300 to gate the exit code');
|
|
111
|
+
return results;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const scoreFailures = evaluateScores(results, thresholds);
|
|
115
|
+
const lcpFailures = evaluateLcp(results, maxLcp);
|
|
116
|
+
if (scoreFailures.length || lcpFailures.length) {
|
|
117
|
+
for (const failure of scoreFailures) {
|
|
118
|
+
logger.error(`${failure.page}: ${LABELS[failure.category]} ${formatScore(failure.score)} is under --min-${failure.category}=${failure.min}`);
|
|
119
|
+
}
|
|
120
|
+
for (const failure of lcpFailures) {
|
|
121
|
+
logger.error(`${failure.page}: LCP ${formatMs(failure.value)} is over --max-lcp=${failure.max}`);
|
|
122
|
+
}
|
|
123
|
+
logger.error(`Audit FAILED — ${scoreFailures.length + lcpFailures.length} gate(s) missed`);
|
|
124
|
+
process.exitCode = 1;
|
|
125
|
+
return results;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
logger.log(`Audit passed — every armed gate is met across ${results.length} page(s)`);
|
|
129
|
+
return results;
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* The armed thresholds: `--min-<category>` for each Lighthouse category, in
|
|
134
|
+
* both the dashed and yargs' camelized form. An absent flag leaves its
|
|
135
|
+
* category ungated (report-only is the default, legacy UJM parity).
|
|
136
|
+
* @param {object} options - the parsed CLI options
|
|
137
|
+
* @returns {Object<string, number>} category id → minimum score
|
|
138
|
+
*/
|
|
139
|
+
function parseThresholds(options) {
|
|
140
|
+
const thresholds = {};
|
|
141
|
+
|
|
142
|
+
for (const category of CATEGORIES) {
|
|
143
|
+
const flag = `min-${category}`;
|
|
144
|
+
const camel = flag.replace(/-([a-z])/g, (m, letter) => letter.toUpperCase());
|
|
145
|
+
const raw = options[flag] !== undefined ? options[flag] : options[camel];
|
|
146
|
+
|
|
147
|
+
if (raw === undefined || raw === null || raw === '' || raw === false) {
|
|
148
|
+
continue;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
const value = Number(raw);
|
|
152
|
+
if (!Number.isFinite(value) || value < 0 || value > 100) {
|
|
153
|
+
throw new Error(`--${flag} must be a score between 0 and 100 (got "${raw}")`);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
thresholds[category] = value;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
return thresholds;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* The perceived-usability bar: `--max-lcp=<ms>` in both the dashed and yargs'
|
|
164
|
+
* camelized form, null when the flag is absent (report-only, same default as
|
|
165
|
+
* the category thresholds). Ian's bar is 1s to usable (#467).
|
|
166
|
+
* @param {object} options - the parsed CLI options
|
|
167
|
+
* @returns {number|null} the maximum acceptable LCP in milliseconds
|
|
168
|
+
*/
|
|
169
|
+
function parseMaxLcp(options) {
|
|
170
|
+
const raw = options['max-lcp'] !== undefined ? options['max-lcp'] : options.maxLcp;
|
|
171
|
+
|
|
172
|
+
if (raw === undefined || raw === null || raw === '' || raw === false) {
|
|
173
|
+
return null;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
const value = Number(raw);
|
|
177
|
+
if (!Number.isFinite(value) || value <= 0) {
|
|
178
|
+
throw new Error(`--max-lcp must be a duration in milliseconds above 0 (got "${raw}")`);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
return value;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* The pages to audit: the home page ALWAYS, plus every path argument, in the
|
|
186
|
+
* order given and de-duplicated.
|
|
187
|
+
* @param {object} options - the parsed CLI options (`_[0]` is the command name)
|
|
188
|
+
* @returns {string[]} site-root-relative page paths
|
|
189
|
+
*/
|
|
190
|
+
function parsePages(options) {
|
|
191
|
+
const args = (options._ || []).slice(1).map(String);
|
|
192
|
+
const pages = ['/'];
|
|
193
|
+
|
|
194
|
+
for (const arg of args) {
|
|
195
|
+
if (arg.includes('://')) {
|
|
196
|
+
throw new Error(`Page arguments are site paths, not URLs — pass "${new URL(arg).pathname}" instead of "${arg}"`);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
const page = `/${arg.replace(/^\/+/, '').replace(/\/+$/, '')}`;
|
|
200
|
+
if (page !== '/' && !pages.includes(page)) {
|
|
201
|
+
pages.push(page);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
return pages;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* The built file a request path serves, or null when nothing does. Clean-URL
|
|
210
|
+
* resolution mirrors the dev server's contract (`/pricing` → `pricing.html`)
|
|
211
|
+
* so an audit measures the same URLs a browser walks in dev and on Pages.
|
|
212
|
+
* @param {string} outDir - the build output directory
|
|
213
|
+
* @param {string} pathname - the request path (no query string)
|
|
214
|
+
* @returns {string|null} absolute file path
|
|
215
|
+
*/
|
|
216
|
+
function resolveFile(outDir, pathname) {
|
|
217
|
+
const root = path.resolve(outDir);
|
|
218
|
+
|
|
219
|
+
// A malformed percent-escape is not a candidate for anything
|
|
220
|
+
let decoded;
|
|
221
|
+
try {
|
|
222
|
+
decoded = decodeURIComponent(pathname);
|
|
223
|
+
} catch (e) {
|
|
224
|
+
return null;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
const clean = decoded.replace(/\/+$/, '');
|
|
228
|
+
const candidates = clean ? [clean, `${clean}.html`, `${clean}/index.html`] : ['/index.html'];
|
|
229
|
+
|
|
230
|
+
for (const candidate of candidates) {
|
|
231
|
+
const resolved = path.resolve(root, `.${candidate}`);
|
|
232
|
+
if (!resolved.startsWith(root + path.sep)) {
|
|
233
|
+
continue;
|
|
234
|
+
}
|
|
235
|
+
if (jetpack.exists(resolved) === 'file') {
|
|
236
|
+
return resolved;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
return null;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* Serve a built site on an ephemeral loopback port. Files stream (a sync read
|
|
245
|
+
* would block the loop and skew the very performance numbers being measured).
|
|
246
|
+
* @param {string} outDir - the build output directory
|
|
247
|
+
* @returns {Promise<{ origin: string, port: number, close: function }>}
|
|
248
|
+
*/
|
|
249
|
+
function serveDist(outDir) {
|
|
250
|
+
const server = http.createServer((req, res) => {
|
|
251
|
+
const file = resolveFile(outDir, (req.url || '/').split('?')[0]);
|
|
252
|
+
|
|
253
|
+
if (!file) {
|
|
254
|
+
res.statusCode = 404;
|
|
255
|
+
res.setHeader('content-type', 'text/plain; charset=utf-8');
|
|
256
|
+
res.end('Not found');
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
res.statusCode = 200;
|
|
261
|
+
res.setHeader('content-type', CONTENT_TYPES[path.extname(file).toLowerCase()] || 'application/octet-stream');
|
|
262
|
+
fs.createReadStream(file).pipe(res);
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
return new Promise((resolve, reject) => {
|
|
266
|
+
server.on('error', reject);
|
|
267
|
+
server.listen(0, '127.0.0.1', () => {
|
|
268
|
+
const { port } = server.address();
|
|
269
|
+
resolve({
|
|
270
|
+
origin: `http://127.0.0.1:${port}`,
|
|
271
|
+
port,
|
|
272
|
+
close: () => new Promise((done) => server.close(done)),
|
|
273
|
+
});
|
|
274
|
+
});
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
/**
|
|
279
|
+
* Headless Chrome, found the way every browser lane in this repo finds it:
|
|
280
|
+
* puppeteer's downloaded Chrome for Testing (scripts/e2e-flows.js,
|
|
281
|
+
* packages/extension's chromium runner), with CHROME_PATH — chrome-launcher's
|
|
282
|
+
* own convention — winning when set. Null means "let chrome-launcher find a
|
|
283
|
+
* system Chrome"; nothing here hardcodes a path.
|
|
284
|
+
* @returns {string|null} absolute Chrome executable path
|
|
285
|
+
*/
|
|
286
|
+
function resolveChromePath() {
|
|
287
|
+
if (process.env.CHROME_PATH) {
|
|
288
|
+
return process.env.CHROME_PATH;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
// puppeteer is not a dependency of this framework — it is the repo's test
|
|
292
|
+
// browser, present in dev and absent in a consumer install. Missing is an
|
|
293
|
+
// expected external condition, not a bug: fall through to system Chrome.
|
|
294
|
+
try {
|
|
295
|
+
const executable = require('puppeteer').executablePath();
|
|
296
|
+
return jetpack.exists(executable) === 'file' ? executable : null;
|
|
297
|
+
} catch (e) {
|
|
298
|
+
return null;
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/**
|
|
303
|
+
* Launch headless Chrome for Lighthouse to drive.
|
|
304
|
+
* @returns {Promise<object>} the chrome-launcher instance (`.port`, `.kill()`)
|
|
305
|
+
*/
|
|
306
|
+
async function launchChrome() {
|
|
307
|
+
const { launch } = await import('chrome-launcher');
|
|
308
|
+
|
|
309
|
+
try {
|
|
310
|
+
return await launch({
|
|
311
|
+
chromePath: resolveChromePath() || undefined,
|
|
312
|
+
chromeFlags: ['--headless', '--disable-gpu', '--no-sandbox'],
|
|
313
|
+
});
|
|
314
|
+
} catch (error) {
|
|
315
|
+
throw new Error(`Could not launch headless Chrome (${error.message}) — install one with \`npx puppeteer browsers install chrome\`, or point CHROME_PATH at an executable`);
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
/**
|
|
320
|
+
* Run Lighthouse against one URL through an already-launched Chrome.
|
|
321
|
+
* @param {string} url - the absolute URL to audit
|
|
322
|
+
* @param {number} chromePort - the launched Chrome's debugging port
|
|
323
|
+
* @returns {Promise<{ scores: object, metrics: object }>} the category scores and the field metrics
|
|
324
|
+
*/
|
|
325
|
+
async function auditPage(url, chromePort) {
|
|
326
|
+
// Lighthouse is ESM-only from v10 — dynamic import is how CJS reaches it
|
|
327
|
+
const lighthouse = (await import('lighthouse')).default;
|
|
328
|
+
|
|
329
|
+
const result = await lighthouse(url, {
|
|
330
|
+
port: chromePort,
|
|
331
|
+
output: 'json',
|
|
332
|
+
logLevel: 'error',
|
|
333
|
+
onlyCategories: CATEGORIES,
|
|
334
|
+
// A local static server is HTTP/1.1 by definition — docking the page for
|
|
335
|
+
// it would measure this command, not the site
|
|
336
|
+
skipAudits: ['uses-http2'],
|
|
337
|
+
});
|
|
338
|
+
|
|
339
|
+
return { scores: categoryScores(result.lhr), metrics: pageMetrics(result.lhr) };
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
/**
|
|
343
|
+
* The four category scores out of 100 from a Lighthouse result.
|
|
344
|
+
* @param {object} lhr - the Lighthouse result object
|
|
345
|
+
* @returns {Object<string, number|null>} null when a category produced no score
|
|
346
|
+
*/
|
|
347
|
+
function categoryScores(lhr) {
|
|
348
|
+
const scores = {};
|
|
349
|
+
|
|
350
|
+
for (const category of CATEGORIES) {
|
|
351
|
+
const score = lhr.categories && lhr.categories[category] && lhr.categories[category].score;
|
|
352
|
+
scores[category] = typeof score === 'number' ? Math.round(score * 100) : null;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
return scores;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
/**
|
|
359
|
+
* The field metrics beside the scores: LCP in whole milliseconds, CLS as
|
|
360
|
+
* Lighthouse scored it, and the form factor the run emulated (so a printed
|
|
361
|
+
* number is never mistaken for the other device class). A metric Lighthouse
|
|
362
|
+
* did not produce reads null, never 0 — an unmeasured page is not a fast one.
|
|
363
|
+
* @param {object} lhr - the Lighthouse result object
|
|
364
|
+
* @returns {{ lcp: number|null, cls: number|null, formFactor: string|null }}
|
|
365
|
+
*/
|
|
366
|
+
function pageMetrics(lhr) {
|
|
367
|
+
const audits = lhr.audits || {};
|
|
368
|
+
|
|
369
|
+
const numeric = (id) => {
|
|
370
|
+
const value = audits[id] && audits[id].numericValue;
|
|
371
|
+
return typeof value === 'number' ? value : null;
|
|
372
|
+
};
|
|
373
|
+
|
|
374
|
+
const lcp = numeric(METRIC_AUDITS.lcp);
|
|
375
|
+
|
|
376
|
+
return {
|
|
377
|
+
lcp: lcp === null ? null : Math.round(lcp),
|
|
378
|
+
cls: numeric(METRIC_AUDITS.cls),
|
|
379
|
+
formFactor: (lhr.configSettings && lhr.configSettings.formFactor) || null,
|
|
380
|
+
};
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
/**
|
|
384
|
+
* The gate: every page/category pair that came in under its threshold. A
|
|
385
|
+
* category with no threshold is never gated; a MISSING score under an armed
|
|
386
|
+
* threshold is a failure (an audit that did not run has not passed).
|
|
387
|
+
* @param {Array<{ page: string, scores: object }>} results - the per-page scores
|
|
388
|
+
* @param {Object<string, number>} thresholds - category id → minimum score
|
|
389
|
+
* @returns {Array<{ page: string, category: string, score: number|null, min: number }>}
|
|
390
|
+
*/
|
|
391
|
+
function evaluateScores(results, thresholds) {
|
|
392
|
+
const failures = [];
|
|
393
|
+
|
|
394
|
+
for (const { page, scores } of results) {
|
|
395
|
+
for (const [category, min] of Object.entries(thresholds)) {
|
|
396
|
+
const score = scores[category];
|
|
397
|
+
if (typeof score !== 'number' || score < min) {
|
|
398
|
+
failures.push({ page, category, score: typeof score === 'number' ? score : null, min });
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
return failures;
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
/**
|
|
407
|
+
* The LCP gate: every page whose largest contentful paint came in over the
|
|
408
|
+
* bar. No bar = no gate; a MISSING LCP under an armed bar is a failure (same
|
|
409
|
+
* doctrine as the scores — a run that measured nothing has not passed).
|
|
410
|
+
* @param {Array<{ page: string, metrics: object }>} results - the per-page results
|
|
411
|
+
* @param {number|null} maxLcp - the maximum acceptable LCP in milliseconds
|
|
412
|
+
* @returns {Array<{ page: string, metric: string, value: number|null, max: number }>}
|
|
413
|
+
*/
|
|
414
|
+
function evaluateLcp(results, maxLcp) {
|
|
415
|
+
if (typeof maxLcp !== 'number') {
|
|
416
|
+
return [];
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
const failures = [];
|
|
420
|
+
|
|
421
|
+
for (const { page, metrics } of results) {
|
|
422
|
+
const lcp = metrics && metrics.lcp;
|
|
423
|
+
if (typeof lcp !== 'number' || lcp > maxLcp) {
|
|
424
|
+
failures.push({ page, metric: 'lcp', value: typeof lcp === 'number' ? lcp : null, max: maxLcp });
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
return failures;
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
/**
|
|
432
|
+
* One page's printed line: the four scores, then the metrics, then the form
|
|
433
|
+
* factor the run emulated.
|
|
434
|
+
* @param {Object<string, number|null>} scores - category id → score out of 100
|
|
435
|
+
* @param {object} metrics - the page's LCP/CLS/form factor
|
|
436
|
+
* @returns {string} the summary, without the page path
|
|
437
|
+
*/
|
|
438
|
+
function formatSummary(scores, metrics) {
|
|
439
|
+
const parts = CATEGORIES.map((category) => `${LABELS[category]} ${formatScore(scores[category])}`);
|
|
440
|
+
parts.push(`LCP ${formatMs(metrics.lcp)}`, `CLS ${formatCls(metrics.cls)}`);
|
|
441
|
+
|
|
442
|
+
return `${parts.join(' · ')} (${metrics.formFactor || 'unknown'} emulation)`;
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
function formatScore(score) {
|
|
446
|
+
return typeof score === 'number' ? `${score}/100` : 'n/a';
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
function formatMs(ms) {
|
|
450
|
+
return typeof ms === 'number' ? `${Math.round(ms)} ms` : 'n/a';
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
function formatCls(cls) {
|
|
454
|
+
return typeof cls === 'number' ? cls.toFixed(3) : 'n/a';
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
// Exposed for tests (the command function stays the main export)
|
|
458
|
+
module.exports.parseThresholds = parseThresholds;
|
|
459
|
+
module.exports.parseMaxLcp = parseMaxLcp;
|
|
460
|
+
module.exports.parsePages = parsePages;
|
|
461
|
+
module.exports.evaluateScores = evaluateScores;
|
|
462
|
+
module.exports.evaluateLcp = evaluateLcp;
|
|
463
|
+
module.exports.categoryScores = categoryScores;
|
|
464
|
+
module.exports.pageMetrics = pageMetrics;
|
|
465
|
+
module.exports.formatSummary = formatSummary;
|
|
466
|
+
module.exports.resolveFile = resolveFile;
|
|
467
|
+
module.exports.serveDist = serveDist;
|
|
468
|
+
module.exports.resolveChromePath = resolveChromePath;
|
|
469
|
+
module.exports.launchChrome = launchChrome;
|
|
470
|
+
module.exports.auditPage = auditPage;
|