diff --git a/.env.example b/.env.example index 6323273a..8cc9cc70 100644 --- a/.env.example +++ b/.env.example @@ -52,6 +52,14 @@ NUXT_PUBLIC_STATINATOR_COOKIE_DOMAIN=.doxa.life DEEPL_API_KEY=your-deepl-api-key DEEPL_API_URL=https://api.deepl.com +# Cloudflare cache purge on deploy (server/plugins/cloudflare-purge.ts). +# On container boot the edge cache is purged so stale prerendered HTML can't +# reference content-hashed assets the new deploy replaced. Leave both blank to +# disable (e.g. in dev). Token: My Profile → API Tokens → Custom Token with +# Zone → Cache Purge for the doxa.life zone. Zone ID: zone Overview page. +CF_API_TOKEN= +CF_ZONE_ID= + # OAuth 2.1 server # Issuer is derived from NUXT_PUBLIC_SITE_URL; resource is `${siteUrl}/mcp`. # Generate with: openssl rand -hex 32 diff --git a/app/assets/styles/base/_globals.scss b/app/assets/styles/base/_globals.scss index 18ccab23..d5374a3e 100644 --- a/app/assets/styles/base/_globals.scss +++ b/app/assets/styles/base/_globals.scss @@ -84,6 +84,12 @@ img { object-fit: cover; } +/* wraps for AVIF/WebP fallback; display:contents removes its + box so the inner stays the effective flex/layout child. */ +picture { + display: contents; +} + .bg-image { background-size: cover; background-position: center; diff --git a/app/components/FeedbackWidget.vue b/app/components/FeedbackWidget.vue index cf368d0e..b8eb13fb 100644 --- a/app/components/FeedbackWidget.vue +++ b/app/components/FeedbackWidget.vue @@ -16,4 +16,26 @@ const profileConfig = computed(() => JSON.stringify({ instanceId: 'fb-doxa-life-parent', projectId: pub.feedbackProjectId })) + +// The feedback widget is a ~95 KB third-party script that is not needed for +// first paint. Load it once the browser is idle so it stays off the initial +// load critical path. The below upgrades in place +// when the definition arrives. +const FEEDBACK_SCRIPT = 'https://support.gospelambition.org/js/feedback-web-component.iife.js' + +function loadFeedbackScript() { + if (document.querySelector(`script[src="${FEEDBACK_SCRIPT}"]`)) return + const script = document.createElement('script') + script.src = FEEDBACK_SCRIPT + script.async = true + document.head.appendChild(script) +} + +onMounted(() => { + if ('requestIdleCallback' in window) { + requestIdleCallback(loadFeedbackScript, { timeout: 3000 }) + } else { + setTimeout(loadFeedbackScript, 2000) + } +}) diff --git a/app/layouts/default.vue b/app/layouts/default.vue index 949c2182..796b8117 100644 --- a/app/layouts/default.vue +++ b/app/layouts/default.vue @@ -5,6 +5,23 @@ // routes — admin pages declare their own typography in admin.css. const { locale, locales } = useI18n() +const { public: pub } = useRuntimeConfig() + +// Warm DNS+TCP+TLS for the cross-origin services these pages hit: the prayer +// data API (people-group components) and the idle-loaded analytics + feedback +// widget scripts. Deriving from runtime config keeps these correct per env. +const preconnectOrigins = computed(() => { + const origins = new Set() + for (const url of [pub.prayBaseUrl, pub.statinatorUrl, pub.feedbackApiBase]) { + if (!url) continue + try { + origins.add(new URL(String(url)).origin) + } catch { + // ignore malformed/empty url + } + } + return [...origins] +}) // Direction attribute per locale (Arabic = rtl) const currentLocale = computed(() => @@ -21,6 +38,10 @@ useHead(() => ({ dir: dir.value }, link: [ + ...preconnectOrigins.value.map(origin => ({ rel: 'preconnect', href: origin })), + // Preload the heading font (Bebas Neue) — it renders the above-the-fold + // h1/h2 (the LCP text), so fetching it early avoids a swap flash. + { rel: 'preload', as: 'font', type: 'font/woff2', href: '/assets/fonts/BebasNeue/BebasNeue-Regular.woff2', crossorigin: '' }, { rel: 'stylesheet', href: '/assets/fonts/BebasNeue/stylesheet.css' }, { rel: 'stylesheet', href: '/assets/fonts/Brandon_Grotesque/stylesheet.css' }, { rel: 'stylesheet', href: '/assets/fonts/Poppins/stylesheet.css' } diff --git a/app/pages/adopt/index.vue b/app/pages/adopt/index.vue index 0aa6fa0b..dc5a6947 100644 --- a/app/pages/adopt/index.vue +++ b/app/pages/adopt/index.vue @@ -55,7 +55,7 @@ useTextHighlight()
@@ -106,7 +106,24 @@ useTextHighlight()
- + + + + +
@@ -118,7 +135,23 @@ useTextHighlight()

{{ t('Why adoption matters') }}

- + + + + +

{{ t('They have no gospel access') }}

@@ -127,7 +160,23 @@ useTextHighlight()
- + + + + +

{{ t('Prayer opens the door for engagement') }}

@@ -136,7 +185,23 @@ useTextHighlight()
- + + + + +

{{ t("Churches become active partners in God's mission") }}

@@ -174,7 +239,23 @@ useTextHighlight()
- {{ t('Jesus') }}
- + + + + +
diff --git a/app/pages/index.vue b/app/pages/index.vue index 29bed269..f9fe266e 100644 --- a/app/pages/index.vue +++ b/app/pages/index.vue @@ -36,11 +36,24 @@ useTextHighlight() - + + + + +

{{ t('The DOXA Vision: Click image to watch the video') }} @@ -95,7 +108,7 @@ useTextHighlight()

@@ -156,12 +169,25 @@ useTextHighlight()
- + + + + +
@@ -191,10 +217,23 @@ useTextHighlight()

{{ t('Engagement starts with prayer') }}

- + + + + +
@@ -210,7 +249,7 @@ useTextHighlight()

{{ t('What does "DOXA" mean?') }}

@@ -219,11 +258,24 @@ useTextHighlight()
- + + + + +
diff --git a/app/pages/pray.vue b/app/pages/pray.vue index 2f87c1b4..fc8ce348 100644 --- a/app/pages/pray.vue +++ b/app/pages/pray.vue @@ -57,7 +57,7 @@ useTextHighlight()
@@ -109,11 +109,24 @@ useTextHighlight()
- + + + + +
@@ -125,7 +138,23 @@ useTextHighlight()

{{ t('Why prayer matters') }}

- + + + + +

{{ t('They have no one praying for them') }}

@@ -134,7 +163,23 @@ useTextHighlight()
- + + + + +

{{ t('Prayer prepares the way for the gospel') }}

@@ -143,7 +188,23 @@ useTextHighlight()
- + + + + +

{{ t('Prayer unites the global church') }}

@@ -193,7 +254,23 @@ useTextHighlight()
- {{ t('Jesus') }}
- + + + + +
diff --git a/app/plugins/statinator.client.ts b/app/plugins/statinator.client.ts index de0338f8..219b59e9 100644 --- a/app/plugins/statinator.client.ts +++ b/app/plugins/statinator.client.ts @@ -66,7 +66,16 @@ export default defineNuxtPlugin(() => { injectScript().then(() => window.goStats?.pageview()).catch(() => {}) } - if (!isExcluded(useRoute().path)) firePageview() + // Defer the initial pageview's script injection until the browser is idle so + // the analytics bundle stays off the initial load critical path. SPA route + // changes (below) still fire immediately — they happen after load. + if (!isExcluded(useRoute().path)) { + if ('requestIdleCallback' in window) { + requestIdleCallback(() => firePageview(), { timeout: 3000 }) + } else { + setTimeout(firePageview, 2000) + } + } const router = useRouter() router.afterEach((to, from) => { diff --git a/nuxt.config.ts b/nuxt.config.ts index 91fb154d..da0a30d7 100644 --- a/nuxt.config.ts +++ b/nuxt.config.ts @@ -1,7 +1,7 @@ // https://nuxt.com/docs/api/configuration/nuxt-config import { existsSync, readdirSync, rmSync } from 'node:fs' import { join } from 'node:path' -import { generateI18nLocales } from './config/languages' +import { generateI18nLocales, ENABLED_LANGUAGE_CODES } from './config/languages' const LAYERS_DIR = '.layers' @@ -20,6 +20,24 @@ function stripLayerTsconfigs() { stripLayerTsconfigs() +// Prerendered marketing pages are served as edge-cacheable HTML so first paint +// comes from Cloudflare rather than the origin. `max-age=0` keeps browsers +// revalidating (a deploy is visible immediately); `s-maxage` is the edge TTL; +// `stale-while-revalidate` lets the edge serve instantly while it refreshes. The +// deploy purge (server/plugins/cloudflare-purge.ts) evicts stale HTML so it can +// never reference content-hashed /_nuxt assets the new build replaced. +const MARKETING_HTML_CACHE = 'public, max-age=0, s-maxage=86400, stale-while-revalidate=86400' +const MARKETING_PAGES = ['', '/adopt', '/pray', '/research', '/contact-us'] +const MARKETING_LOCALE_PREFIXES = ['', ...ENABLED_LANGUAGE_CODES.filter(code => code !== 'en').map(code => `/${code}`)] +const marketingRouteRules = Object.fromEntries( + MARKETING_LOCALE_PREFIXES.flatMap(prefix => + MARKETING_PAGES.map(page => [ + `${prefix}${page}` || '/', + { prerender: true, headers: { 'cache-control': MARKETING_HTML_CACHE } } + ]) + ) +) + export default defineNuxtConfig({ extends: [ process.env.OAUTH_LAYER_PATH || ['github:corsacca/nuxt-blueprints/layers/oauth#master', { @@ -102,9 +120,6 @@ export default defineNuxtConfig({ { rel: 'icon', type: 'image/png', sizes: '192x192', href: '/favicon/cropped-Favicon-light-doxa-01-192x192.png' }, { rel: 'apple-touch-icon', href: '/favicon/cropped-Favicon-light-doxa-01-180x180.png' } ], - script: [ - { src: 'https://support.gospelambition.org/js/feedback-web-component.iife.js', defer: true } - ], meta: [ { name: 'msapplication-TileImage', content: '/favicon/cropped-Favicon-light-doxa-01-270x270.png' } ] @@ -112,11 +127,13 @@ export default defineNuxtConfig({ }, routeRules: { - '/': { prerender: true }, - '/adopt': { prerender: true }, - '/pray': { prerender: true }, - '/research': { prerender: true }, - '/contact-us': { prerender: true }, + // Content-hashed build assets never change under the same URL — cache forever. + '/_nuxt/**': { headers: { 'cache-control': 'public, max-age=31536000, immutable' } }, + // Fonts/images use stable filenames, so avoid `immutable`: a 7-day cache + // still lets an overwritten asset propagate within a week. + '/assets/**': { headers: { 'cache-control': 'public, max-age=604800' } }, + // Prerendered marketing pages (all enabled locales) — edge-cacheable HTML. + ...marketingRouteRules, '/login': { ssr: false, prerender: false }, '/register': { ssr: false, prerender: false }, '/reset-password': { ssr: false, prerender: false }, @@ -135,6 +152,9 @@ export default defineNuxtConfig({ // server crashes on boot. The bun preset builds the output for Bun's own // resolver. Run it with `bun run ./.output/server/index.mjs`. preset: 'bun', + // Precompress public assets (JS/CSS/HTML/SVG/JSON) to .br and .gz at build + // time; the server serves the compressed variant when the client supports it. + compressPublicAssets: { brotli: true, gzip: true }, // Dev-only: use in-memory cache for the payload mount. The default fs // driver can't represent both a leaf route ("/fr") and children of that // route ("/fr/adopt") simultaneously — the first visit writes a file at @@ -211,6 +231,10 @@ export default defineNuxtConfig({ prayBaseUrl: process.env.NUXT_PRAY_BASE_URL || 'https://pray.doxa.life', deeplApiKey: process.env.DEEPL_API_KEY || '', deeplApiUrl: process.env.DEEPL_API_URL || 'https://api.deepl.com', + // Cloudflare cache purge on deploy (server/plugins/cloudflare-purge.ts). + // Token needs only Zone → Cache Purge for the doxa.life zone. + cfApiToken: process.env.CF_API_TOKEN || '', + cfZoneId: process.env.CF_ZONE_ID || '', public: { appName: process.env.APP_TITLE || 'My App', nodeEnv: process.env.NODE_ENV || '', diff --git a/public/assets/fonts/BebasKai/BebasKai.eot b/public/assets/fonts/BebasKai/BebasKai.eot deleted file mode 100644 index 451e25f5..00000000 Binary files a/public/assets/fonts/BebasKai/BebasKai.eot and /dev/null differ diff --git a/public/assets/fonts/BebasKai/BebasKai.svg b/public/assets/fonts/BebasKai/BebasKai.svg deleted file mode 100644 index 3e923ea9..00000000 --- a/public/assets/fonts/BebasKai/BebasKai.svg +++ /dev/null @@ -1,2232 +0,0 @@ - - - - -Created by FontForge 20170731 at Thu May 25 19:52:30 2023 - By Aleksey,,, -Copyright (c) 2014 by Dharma Type. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/public/assets/fonts/BebasKai/BebasKai.ttf b/public/assets/fonts/BebasKai/BebasKai.ttf deleted file mode 100644 index 1e4e6295..00000000 Binary files a/public/assets/fonts/BebasKai/BebasKai.ttf and /dev/null differ diff --git a/public/assets/fonts/BebasKai/BebasKai.woff b/public/assets/fonts/BebasKai/BebasKai.woff deleted file mode 100644 index c31d334a..00000000 Binary files a/public/assets/fonts/BebasKai/BebasKai.woff and /dev/null differ diff --git a/public/assets/fonts/BebasKai/BebasKai.woff2 b/public/assets/fonts/BebasKai/BebasKai.woff2 deleted file mode 100644 index 799a4727..00000000 Binary files a/public/assets/fonts/BebasKai/BebasKai.woff2 and /dev/null differ diff --git a/public/assets/fonts/BebasKai/demo.html b/public/assets/fonts/BebasKai/demo.html deleted file mode 100644 index 4185f681..00000000 --- a/public/assets/fonts/BebasKai/demo.html +++ /dev/null @@ -1,192 +0,0 @@ - - - - - - - - - Transfonter demo - - - - -
-
-

Bebas Kai

-
.your-style {
-    font-family: 'Bebas Kai';
-    font-weight: normal;
-    font-style: normal;
-}
-
-<link rel="preload" href="BebasKai.woff2" as="font" type="font/woff2" crossorigin>
-
-

- abcdefghijklmnopqrstuvwxyz
-ABCDEFGHIJKLMNOPQRSTUVWXYZ
- 0123456789.:,;()*!?'@#<>$%&^+-=~ -

-

The quick brown fox jumps over the lazy dog.

-

The quick brown fox jumps over the lazy dog.

-

The quick brown fox jumps over the lazy dog.

-

The quick brown fox jumps over the lazy dog.

-

The quick brown fox jumps over the lazy dog.

-

The quick brown fox jumps over the lazy dog.

-

The quick brown fox jumps over the lazy dog.

-

The quick brown fox jumps over the lazy dog.

-

The quick brown fox jumps over the lazy dog.

-

The quick brown fox jumps over the lazy dog.

-

The quick brown fox jumps over the lazy dog.

-
-
- -
- - diff --git a/public/assets/fonts/BebasKai/stylesheet.css b/public/assets/fonts/BebasKai/stylesheet.css deleted file mode 100644 index 42a8b76d..00000000 --- a/public/assets/fonts/BebasKai/stylesheet.css +++ /dev/null @@ -1,12 +0,0 @@ -@font-face { - font-family: 'Bebas Kai'; - src: url('BebasKai.eot'); - src: url('BebasKai.eot?#iefix') format('embedded-opentype'), - url('BebasKai.woff2') format('woff2'), - url('BebasKai.woff') format('woff'), - url('BebasKai.ttf') format('truetype'), - url('BebasKai.svg#BebasKai') format('svg'); - font-weight: normal; - font-style: normal; - font-display: swap; -} \ No newline at end of file diff --git a/public/assets/fonts/BebasNeue/BebasNeue-Regular.woff2 b/public/assets/fonts/BebasNeue/BebasNeue-Regular.woff2 new file mode 100644 index 00000000..60aa3eb6 Binary files /dev/null and b/public/assets/fonts/BebasNeue/BebasNeue-Regular.woff2 differ diff --git a/public/assets/fonts/BebasNeue/stylesheet.css b/public/assets/fonts/BebasNeue/stylesheet.css index 39282ed7..f343d096 100644 --- a/public/assets/fonts/BebasNeue/stylesheet.css +++ b/public/assets/fonts/BebasNeue/stylesheet.css @@ -1,6 +1,7 @@ @font-face { font-family: 'Bebas Neue'; - src: url('BebasNeue-Regular.ttf') format('truetype'); + src: url('BebasNeue-Regular.woff2') format('woff2'), + url('BebasNeue-Regular.ttf') format('truetype'); font-weight: 400; font-style: normal; font-display: swap; diff --git a/public/assets/fonts/Brandon_Grotesque/Brandon_Grotesque_medium.woff2 b/public/assets/fonts/Brandon_Grotesque/Brandon_Grotesque_medium.woff2 new file mode 100644 index 00000000..c47e84bf Binary files /dev/null and b/public/assets/fonts/Brandon_Grotesque/Brandon_Grotesque_medium.woff2 differ diff --git a/public/assets/fonts/Brandon_Grotesque/stylesheet.css b/public/assets/fonts/Brandon_Grotesque/stylesheet.css index f4218c11..193f646f 100644 --- a/public/assets/fonts/Brandon_Grotesque/stylesheet.css +++ b/public/assets/fonts/Brandon_Grotesque/stylesheet.css @@ -1,6 +1,7 @@ @font-face { font-family: 'Brandon Grotesque'; - src: url('Brandon_Grotesque_medium.otf') format('opentype'); + src: url('Brandon_Grotesque_medium.woff2') format('woff2'), + url('Brandon_Grotesque_medium.otf') format('opentype'); font-weight: 500; font-style: normal; font-display: swap; diff --git a/public/assets/fonts/Poppins/Poppins-Black.ttf b/public/assets/fonts/Poppins/Poppins-Black.ttf deleted file mode 100644 index 71c0f995..00000000 Binary files a/public/assets/fonts/Poppins/Poppins-Black.ttf and /dev/null differ diff --git a/public/assets/fonts/Poppins/Poppins-BlackItalic.ttf b/public/assets/fonts/Poppins/Poppins-BlackItalic.ttf deleted file mode 100644 index 7aeb58bd..00000000 Binary files a/public/assets/fonts/Poppins/Poppins-BlackItalic.ttf and /dev/null differ diff --git a/public/assets/fonts/Poppins/Poppins-Bold.woff2 b/public/assets/fonts/Poppins/Poppins-Bold.woff2 new file mode 100644 index 00000000..8a2eb83d Binary files /dev/null and b/public/assets/fonts/Poppins/Poppins-Bold.woff2 differ diff --git a/public/assets/fonts/Poppins/Poppins-BoldItalic.woff2 b/public/assets/fonts/Poppins/Poppins-BoldItalic.woff2 new file mode 100644 index 00000000..968d41c3 Binary files /dev/null and b/public/assets/fonts/Poppins/Poppins-BoldItalic.woff2 differ diff --git a/public/assets/fonts/Poppins/Poppins-ExtraBold.ttf b/public/assets/fonts/Poppins/Poppins-ExtraBold.ttf deleted file mode 100644 index df709360..00000000 Binary files a/public/assets/fonts/Poppins/Poppins-ExtraBold.ttf and /dev/null differ diff --git a/public/assets/fonts/Poppins/Poppins-ExtraBoldItalic.ttf b/public/assets/fonts/Poppins/Poppins-ExtraBoldItalic.ttf deleted file mode 100644 index 14d2b375..00000000 Binary files a/public/assets/fonts/Poppins/Poppins-ExtraBoldItalic.ttf and /dev/null differ diff --git a/public/assets/fonts/Poppins/Poppins-ExtraLight.ttf b/public/assets/fonts/Poppins/Poppins-ExtraLight.ttf deleted file mode 100644 index e76ec69a..00000000 Binary files a/public/assets/fonts/Poppins/Poppins-ExtraLight.ttf and /dev/null differ diff --git a/public/assets/fonts/Poppins/Poppins-ExtraLightItalic.ttf b/public/assets/fonts/Poppins/Poppins-ExtraLightItalic.ttf deleted file mode 100644 index 89513d94..00000000 Binary files a/public/assets/fonts/Poppins/Poppins-ExtraLightItalic.ttf and /dev/null differ diff --git a/public/assets/fonts/Poppins/Poppins-Italic.woff2 b/public/assets/fonts/Poppins/Poppins-Italic.woff2 new file mode 100644 index 00000000..248df973 Binary files /dev/null and b/public/assets/fonts/Poppins/Poppins-Italic.woff2 differ diff --git a/public/assets/fonts/Poppins/Poppins-Light.ttf b/public/assets/fonts/Poppins/Poppins-Light.ttf deleted file mode 100644 index bc36bcc2..00000000 Binary files a/public/assets/fonts/Poppins/Poppins-Light.ttf and /dev/null differ diff --git a/public/assets/fonts/Poppins/Poppins-LightItalic.ttf b/public/assets/fonts/Poppins/Poppins-LightItalic.ttf deleted file mode 100644 index 9e70be6a..00000000 Binary files a/public/assets/fonts/Poppins/Poppins-LightItalic.ttf and /dev/null differ diff --git a/public/assets/fonts/Poppins/Poppins-Medium.woff2 b/public/assets/fonts/Poppins/Poppins-Medium.woff2 new file mode 100644 index 00000000..d9957d0a Binary files /dev/null and b/public/assets/fonts/Poppins/Poppins-Medium.woff2 differ diff --git a/public/assets/fonts/Poppins/Poppins-MediumItalic.woff2 b/public/assets/fonts/Poppins/Poppins-MediumItalic.woff2 new file mode 100644 index 00000000..58bb29d7 Binary files /dev/null and b/public/assets/fonts/Poppins/Poppins-MediumItalic.woff2 differ diff --git a/public/assets/fonts/Poppins/Poppins-Regular.woff2 b/public/assets/fonts/Poppins/Poppins-Regular.woff2 new file mode 100644 index 00000000..c2975a86 Binary files /dev/null and b/public/assets/fonts/Poppins/Poppins-Regular.woff2 differ diff --git a/public/assets/fonts/Poppins/Poppins-SemiBold.ttf b/public/assets/fonts/Poppins/Poppins-SemiBold.ttf deleted file mode 100644 index 74c726e3..00000000 Binary files a/public/assets/fonts/Poppins/Poppins-SemiBold.ttf and /dev/null differ diff --git a/public/assets/fonts/Poppins/Poppins-SemiBoldItalic.ttf b/public/assets/fonts/Poppins/Poppins-SemiBoldItalic.ttf deleted file mode 100644 index 3e6c9422..00000000 Binary files a/public/assets/fonts/Poppins/Poppins-SemiBoldItalic.ttf and /dev/null differ diff --git a/public/assets/fonts/Poppins/Poppins-Thin.ttf b/public/assets/fonts/Poppins/Poppins-Thin.ttf deleted file mode 100644 index 03e73661..00000000 Binary files a/public/assets/fonts/Poppins/Poppins-Thin.ttf and /dev/null differ diff --git a/public/assets/fonts/Poppins/Poppins-ThinItalic.ttf b/public/assets/fonts/Poppins/Poppins-ThinItalic.ttf deleted file mode 100644 index e26db5dd..00000000 Binary files a/public/assets/fonts/Poppins/Poppins-ThinItalic.ttf and /dev/null differ diff --git a/public/assets/fonts/Poppins/stylesheet.css b/public/assets/fonts/Poppins/stylesheet.css index 3678c3e3..65c45ebc 100644 --- a/public/assets/fonts/Poppins/stylesheet.css +++ b/public/assets/fonts/Poppins/stylesheet.css @@ -1,6 +1,7 @@ @font-face { font-family: 'Poppins'; - src: url('Poppins-Regular.ttf') format('truetype'); + src: url('Poppins-Regular.woff2') format('woff2'), + url('Poppins-Regular.ttf') format('truetype'); font-weight: 400; font-style: normal; font-display: swap; @@ -8,7 +9,8 @@ @font-face { font-family: 'Poppins'; - src: url('Poppins-Italic.ttf') format('truetype'); + src: url('Poppins-Italic.woff2') format('woff2'), + url('Poppins-Italic.ttf') format('truetype'); font-weight: 400; font-style: italic; font-display: swap; @@ -16,7 +18,8 @@ @font-face { font-family: 'Poppins'; - src: url('Poppins-Medium.ttf') format('truetype'); + src: url('Poppins-Medium.woff2') format('woff2'), + url('Poppins-Medium.ttf') format('truetype'); font-weight: 500; font-style: normal; font-display: swap; @@ -24,7 +27,8 @@ @font-face { font-family: 'Poppins'; - src: url('Poppins-MediumItalic.ttf') format('truetype'); + src: url('Poppins-MediumItalic.woff2') format('woff2'), + url('Poppins-MediumItalic.ttf') format('truetype'); font-weight: 500; font-style: italic; font-display: swap; @@ -32,7 +36,8 @@ @font-face { font-family: 'Poppins'; - src: url('Poppins-Bold.ttf') format('truetype'); + src: url('Poppins-Bold.woff2') format('woff2'), + url('Poppins-Bold.ttf') format('truetype'); font-weight: 700; font-style: normal; font-display: swap; @@ -40,7 +45,8 @@ @font-face { font-family: 'Poppins'; - src: url('Poppins-BoldItalic.ttf') format('truetype'); + src: url('Poppins-BoldItalic.woff2') format('woff2'), + url('Poppins-BoldItalic.ttf') format('truetype'); font-weight: 700; font-style: italic; font-display: swap; diff --git a/public/assets/images/Adopt-03-DurbetInMongolia.avif b/public/assets/images/Adopt-03-DurbetInMongolia.avif new file mode 100644 index 00000000..ef18c208 Binary files /dev/null and b/public/assets/images/Adopt-03-DurbetInMongolia.avif differ diff --git a/public/assets/images/Adopt-03-DurbetInMongolia.webp b/public/assets/images/Adopt-03-DurbetInMongolia.webp new file mode 100644 index 00000000..c428bc22 Binary files /dev/null and b/public/assets/images/Adopt-03-DurbetInMongolia.webp differ diff --git a/public/assets/images/Adopt-04-Maha-Brahmin-in-India.avif b/public/assets/images/Adopt-04-Maha-Brahmin-in-India.avif new file mode 100644 index 00000000..84cf5476 Binary files /dev/null and b/public/assets/images/Adopt-04-Maha-Brahmin-in-India.avif differ diff --git a/public/assets/images/Adopt-04-Maha-Brahmin-in-India.webp b/public/assets/images/Adopt-04-Maha-Brahmin-in-India.webp new file mode 100644 index 00000000..a74878e4 Binary files /dev/null and b/public/assets/images/Adopt-04-Maha-Brahmin-in-India.webp differ diff --git a/public/assets/images/Adopt-05-KamaraInGhana.avif b/public/assets/images/Adopt-05-KamaraInGhana.avif new file mode 100644 index 00000000..7c7017e3 Binary files /dev/null and b/public/assets/images/Adopt-05-KamaraInGhana.avif differ diff --git a/public/assets/images/Adopt-05-KamaraInGhana.webp b/public/assets/images/Adopt-05-KamaraInGhana.webp new file mode 100644 index 00000000..25483b65 Binary files /dev/null and b/public/assets/images/Adopt-05-KamaraInGhana.webp differ diff --git a/public/assets/images/Pray-04-Doxa.avif b/public/assets/images/Pray-04-Doxa.avif new file mode 100644 index 00000000..df8eb2a9 Binary files /dev/null and b/public/assets/images/Pray-04-Doxa.avif differ diff --git a/public/assets/images/Pray-04-Doxa.webp b/public/assets/images/Pray-04-Doxa.webp new file mode 100644 index 00000000..81c2f3aa Binary files /dev/null and b/public/assets/images/Pray-04-Doxa.webp differ diff --git a/public/assets/images/Pray-05-Doxa.avif b/public/assets/images/Pray-05-Doxa.avif new file mode 100644 index 00000000..9b531e54 Binary files /dev/null and b/public/assets/images/Pray-05-Doxa.avif differ diff --git a/public/assets/images/Pray-05-Doxa.webp b/public/assets/images/Pray-05-Doxa.webp new file mode 100644 index 00000000..473bc9d6 Binary files /dev/null and b/public/assets/images/Pray-05-Doxa.webp differ diff --git a/public/assets/images/Pray-06-Doxa.avif b/public/assets/images/Pray-06-Doxa.avif new file mode 100644 index 00000000..05ac79bb Binary files /dev/null and b/public/assets/images/Pray-06-Doxa.avif differ diff --git a/public/assets/images/Pray-06-Doxa.webp b/public/assets/images/Pray-06-Doxa.webp new file mode 100644 index 00000000..d599534d Binary files /dev/null and b/public/assets/images/Pray-06-Doxa.webp differ diff --git a/public/assets/images/adopt-01-africa-4women.avif b/public/assets/images/adopt-01-africa-4women.avif new file mode 100644 index 00000000..7f980c86 Binary files /dev/null and b/public/assets/images/adopt-01-africa-4women.avif differ diff --git a/public/assets/images/adopt-01-africa-4women.webp b/public/assets/images/adopt-01-africa-4women.webp new file mode 100644 index 00000000..ce2f84fb Binary files /dev/null and b/public/assets/images/adopt-01-africa-4women.webp differ diff --git a/public/assets/images/adopt-02-ipad-mockup.avif b/public/assets/images/adopt-02-ipad-mockup.avif new file mode 100644 index 00000000..0d46c7cc Binary files /dev/null and b/public/assets/images/adopt-02-ipad-mockup.avif differ diff --git a/public/assets/images/adopt-02-ipad-mockup.webp b/public/assets/images/adopt-02-ipad-mockup.webp new file mode 100644 index 00000000..bbc0450b Binary files /dev/null and b/public/assets/images/adopt-02-ipad-mockup.webp differ diff --git a/public/assets/images/adopt-bottom-banner.avif b/public/assets/images/adopt-bottom-banner.avif new file mode 100644 index 00000000..04b290e6 Binary files /dev/null and b/public/assets/images/adopt-bottom-banner.avif differ diff --git a/public/assets/images/adopt-bottom-banner.webp b/public/assets/images/adopt-bottom-banner.webp new file mode 100644 index 00000000..2806d47e Binary files /dev/null and b/public/assets/images/adopt-bottom-banner.webp differ diff --git a/public/assets/images/home-01-hero.avif b/public/assets/images/home-01-hero.avif new file mode 100644 index 00000000..d844bcce Binary files /dev/null and b/public/assets/images/home-01-hero.avif differ diff --git a/public/assets/images/home-01-hero.webp b/public/assets/images/home-01-hero.webp new file mode 100644 index 00000000..8ed9ac61 Binary files /dev/null and b/public/assets/images/home-01-hero.webp differ diff --git a/public/assets/images/home-02-WhoAreTheUnreached-new.avif b/public/assets/images/home-02-WhoAreTheUnreached-new.avif new file mode 100644 index 00000000..1cc9fa18 Binary files /dev/null and b/public/assets/images/home-02-WhoAreTheUnreached-new.avif differ diff --git a/public/assets/images/home-02-WhoAreTheUnreached-new.webp b/public/assets/images/home-02-WhoAreTheUnreached-new.webp new file mode 100644 index 00000000..fac575ed Binary files /dev/null and b/public/assets/images/home-02-WhoAreTheUnreached-new.webp differ diff --git a/public/assets/images/home-03-Vision-2033.avif b/public/assets/images/home-03-Vision-2033.avif new file mode 100644 index 00000000..40969a3d Binary files /dev/null and b/public/assets/images/home-03-Vision-2033.avif differ diff --git a/public/assets/images/home-03-Vision-2033.webp b/public/assets/images/home-03-Vision-2033.webp new file mode 100644 index 00000000..71bc8b48 Binary files /dev/null and b/public/assets/images/home-03-Vision-2033.webp differ diff --git a/public/assets/images/home-04-EngagementStartsWithPrayer.avif b/public/assets/images/home-04-EngagementStartsWithPrayer.avif new file mode 100644 index 00000000..33994905 Binary files /dev/null and b/public/assets/images/home-04-EngagementStartsWithPrayer.avif differ diff --git a/public/assets/images/home-04-EngagementStartsWithPrayer.webp b/public/assets/images/home-04-EngagementStartsWithPrayer.webp new file mode 100644 index 00000000..c77e29ca Binary files /dev/null and b/public/assets/images/home-04-EngagementStartsWithPrayer.webp differ diff --git a/public/assets/images/home-05-WhatDoesDoxaMean.avif b/public/assets/images/home-05-WhatDoesDoxaMean.avif new file mode 100644 index 00000000..2523b99b Binary files /dev/null and b/public/assets/images/home-05-WhatDoesDoxaMean.avif differ diff --git a/public/assets/images/home-05-WhatDoesDoxaMean.webp b/public/assets/images/home-05-WhatDoesDoxaMean.webp new file mode 100644 index 00000000..40024f19 Binary files /dev/null and b/public/assets/images/home-05-WhatDoesDoxaMean.webp differ diff --git a/public/assets/images/home-doxa-background.avif b/public/assets/images/home-doxa-background.avif new file mode 100644 index 00000000..5d1960d1 Binary files /dev/null and b/public/assets/images/home-doxa-background.avif differ diff --git a/public/assets/images/home-doxa-background.webp b/public/assets/images/home-doxa-background.webp new file mode 100644 index 00000000..89ac0b5f Binary files /dev/null and b/public/assets/images/home-doxa-background.webp differ diff --git a/public/assets/images/pray-01-hero.avif b/public/assets/images/pray-01-hero.avif new file mode 100644 index 00000000..ceb5a898 Binary files /dev/null and b/public/assets/images/pray-01-hero.avif differ diff --git a/public/assets/images/pray-01-hero.webp b/public/assets/images/pray-01-hero.webp new file mode 100644 index 00000000..1d2dffec Binary files /dev/null and b/public/assets/images/pray-01-hero.webp differ diff --git a/public/assets/images/pray-02-PrayerFUEL-Phone-graphic-2.avif b/public/assets/images/pray-02-PrayerFUEL-Phone-graphic-2.avif new file mode 100644 index 00000000..fdfa0980 Binary files /dev/null and b/public/assets/images/pray-02-PrayerFUEL-Phone-graphic-2.avif differ diff --git a/public/assets/images/pray-02-PrayerFUEL-Phone-graphic-2.webp b/public/assets/images/pray-02-PrayerFUEL-Phone-graphic-2.webp new file mode 100644 index 00000000..3b652c1e Binary files /dev/null and b/public/assets/images/pray-02-PrayerFUEL-Phone-graphic-2.webp differ diff --git a/public/assets/images/pray-03-bottom-unsplash.avif b/public/assets/images/pray-03-bottom-unsplash.avif new file mode 100644 index 00000000..34d9cda9 Binary files /dev/null and b/public/assets/images/pray-03-bottom-unsplash.avif differ diff --git a/public/assets/images/pray-03-bottom-unsplash.webp b/public/assets/images/pray-03-bottom-unsplash.webp new file mode 100644 index 00000000..c2197fdd Binary files /dev/null and b/public/assets/images/pray-03-bottom-unsplash.webp differ diff --git a/server/plugins/cloudflare-purge.ts b/server/plugins/cloudflare-purge.ts new file mode 100644 index 00000000..82be0483 --- /dev/null +++ b/server/plugins/cloudflare-purge.ts @@ -0,0 +1,27 @@ +// Purge the Cloudflare edge cache when a fresh container boots — which is what +// every deploy triggers on this platform. The prerendered marketing HTML is +// edge-cached (Cache-Control s-maxage), but it references content-hashed +// /_nuxt assets that the new deploy just replaced. If stale HTML survived in +// the edge it would point at files that no longer exist, so it must be evicted. +// +// Fire-and-forget: a purge failure must never block the server from starting. +// +// Caveat: this also runs on plain restarts / scale-ups, which is harmless (it +// just re-warms the cache). If the app ever enters a crash loop, move the purge +// to a POST_DEPLOY job so the API can't be hammered. +export default defineNitroPlugin(() => { + // Don't fire during local dev or the build-time prerender pass — only when a + // real deployed container comes up. + if (import.meta.dev || import.meta.prerender) return + + const { cfApiToken, cfZoneId } = useRuntimeConfig() + if (!cfApiToken || !cfZoneId) return + + $fetch(`https://api.cloudflare.com/client/v4/zones/${cfZoneId}/purge_cache`, { + method: 'POST', + headers: { Authorization: `Bearer ${cfApiToken}` }, + body: { purge_everything: true } + }) + .then(() => console.log('[cf-purge] Cloudflare edge cache purged on boot')) + .catch((err: unknown) => console.error('[cf-purge] purge failed:', err)) +})