From 812b36ae8ab4839e6d9772ba9da252585e28c47d Mon Sep 17 00:00:00 2001 From: bryantgillespie Date: Wed, 28 Oct 2026 16:12:49 -0400 Subject: [PATCH 1/2] Bake tutorial card images instead of rendering them with sharp --- .github/workflows/docs-checks.yml | 5 + app/components/TutorialCard.vue | 6 +- package.json | 4 +- pnpm-lock.yaml | 6 +- public/img/tutorials/cards/airbyte.jpg | Bin 0 -> 6223 bytes public/img/tutorials/cards/algolia.jpg | Bin 0 -> 9978 bytes public/img/tutorials/cards/angular.jpg | Bin 0 -> 7278 bytes public/img/tutorials/cards/astro.jpg | Bin 0 -> 6099 bytes public/img/tutorials/cards/aws.jpg | Bin 0 -> 7708 bytes public/img/tutorials/cards/azure.jpg | Bin 0 -> 6308 bytes public/img/tutorials/cards/chrome.jpg | Bin 0 -> 8232 bytes public/img/tutorials/cards/clarifai.jpg | Bin 0 -> 6100 bytes public/img/tutorials/cards/clay.jpg | Bin 0 -> 6223 bytes public/img/tutorials/cards/clearbit.jpg | Bin 0 -> 5283 bytes public/img/tutorials/cards/crowdin.jpg | Bin 0 -> 7986 bytes public/img/tutorials/cards/db.jpg | Bin 0 -> 7816 bytes public/img/tutorials/cards/deepgram.jpg | Bin 0 -> 8306 bytes public/img/tutorials/cards/digitalocean.jpg | Bin 0 -> 7901 bytes public/img/tutorials/cards/directus.jpg | Bin 0 -> 6223 bytes public/img/tutorials/cards/django.jpg | Bin 0 -> 6625 bytes public/img/tutorials/cards/elasticsearch.jpg | Bin 0 -> 6439 bytes public/img/tutorials/cards/eleventy.jpg | Bin 0 -> 6223 bytes public/img/tutorials/cards/flask.jpg | Bin 0 -> 7443 bytes public/img/tutorials/cards/flutter.jpg | Bin 0 -> 6860 bytes public/img/tutorials/cards/framer.jpg | Bin 0 -> 6223 bytes public/img/tutorials/cards/gcp.jpg | Bin 0 -> 7383 bytes public/img/tutorials/cards/github.jpg | Bin 0 -> 6421 bytes public/img/tutorials/cards/inngest.jpg | Bin 0 -> 6223 bytes public/img/tutorials/cards/javascript.jpg | Bin 0 -> 7614 bytes public/img/tutorials/cards/kotlin.jpg | Bin 0 -> 6000 bytes public/img/tutorials/cards/kubernetes.jpg | Bin 0 -> 9425 bytes public/img/tutorials/cards/meilisearch.jpg | Bin 0 -> 5991 bytes public/img/tutorials/cards/n8n.jpg | Bin 0 -> 5672 bytes public/img/tutorials/cards/netlify.jpg | Bin 0 -> 8642 bytes public/img/tutorials/cards/nextjs.jpg | Bin 0 -> 6811 bytes public/img/tutorials/cards/northflank.jpg | Bin 0 -> 8206 bytes public/img/tutorials/cards/notion.jpg | Bin 0 -> 7282 bytes public/img/tutorials/cards/nuxt.jpg | Bin 0 -> 5792 bytes public/img/tutorials/cards/okta.jpg | Bin 0 -> 7105 bytes public/img/tutorials/cards/openai.jpg | Bin 0 -> 8997 bytes public/img/tutorials/cards/railway.jpg | Bin 0 -> 9725 bytes public/img/tutorials/cards/react.jpg | Bin 0 -> 8952 bytes public/img/tutorials/cards/render.jpg | Bin 0 -> 6223 bytes public/img/tutorials/cards/sentry.jpg | Bin 0 -> 8018 bytes public/img/tutorials/cards/solidstart.jpg | Bin 0 -> 6109 bytes public/img/tutorials/cards/spring-boot.jpg | Bin 0 -> 6223 bytes public/img/tutorials/cards/stripe.jpg | Bin 0 -> 6732 bytes public/img/tutorials/cards/supabase.jpg | Bin 0 -> 6223 bytes public/img/tutorials/cards/sveltekit.jpg | Bin 0 -> 9205 bytes public/img/tutorials/cards/swift.jpg | Bin 0 -> 7171 bytes public/img/tutorials/cards/twilio.jpg | Bin 0 -> 9336 bytes public/img/tutorials/cards/ubuntu.jpg | Bin 0 -> 8275 bytes public/img/tutorials/cards/vercel.jpg | Bin 0 -> 5442 bytes public/img/tutorials/cards/vonage.jpg | Bin 0 -> 6101 bytes public/img/tutorials/cards/vue.jpg | Bin 0 -> 6545 bytes public/img/tutorials/cards/wordpress.jpg | Bin 0 -> 10201 bytes public/img/tutorials/cards/zapier.jpg | Bin 0 -> 5703 bytes scripts/tutorial-cards.ts | 102 +++++++++++++++++++ server/api/tutorialimg.ts | 77 -------------- 59 files changed, 115 insertions(+), 85 deletions(-) create mode 100644 public/img/tutorials/cards/airbyte.jpg create mode 100644 public/img/tutorials/cards/algolia.jpg create mode 100644 public/img/tutorials/cards/angular.jpg create mode 100644 public/img/tutorials/cards/astro.jpg create mode 100644 public/img/tutorials/cards/aws.jpg create mode 100644 public/img/tutorials/cards/azure.jpg create mode 100644 public/img/tutorials/cards/chrome.jpg create mode 100644 public/img/tutorials/cards/clarifai.jpg create mode 100644 public/img/tutorials/cards/clay.jpg create mode 100644 public/img/tutorials/cards/clearbit.jpg create mode 100644 public/img/tutorials/cards/crowdin.jpg create mode 100644 public/img/tutorials/cards/db.jpg create mode 100644 public/img/tutorials/cards/deepgram.jpg create mode 100644 public/img/tutorials/cards/digitalocean.jpg create mode 100644 public/img/tutorials/cards/directus.jpg create mode 100644 public/img/tutorials/cards/django.jpg create mode 100644 public/img/tutorials/cards/elasticsearch.jpg create mode 100644 public/img/tutorials/cards/eleventy.jpg create mode 100644 public/img/tutorials/cards/flask.jpg create mode 100644 public/img/tutorials/cards/flutter.jpg create mode 100644 public/img/tutorials/cards/framer.jpg create mode 100644 public/img/tutorials/cards/gcp.jpg create mode 100644 public/img/tutorials/cards/github.jpg create mode 100644 public/img/tutorials/cards/inngest.jpg create mode 100644 public/img/tutorials/cards/javascript.jpg create mode 100644 public/img/tutorials/cards/kotlin.jpg create mode 100644 public/img/tutorials/cards/kubernetes.jpg create mode 100644 public/img/tutorials/cards/meilisearch.jpg create mode 100644 public/img/tutorials/cards/n8n.jpg create mode 100644 public/img/tutorials/cards/netlify.jpg create mode 100644 public/img/tutorials/cards/nextjs.jpg create mode 100644 public/img/tutorials/cards/northflank.jpg create mode 100644 public/img/tutorials/cards/notion.jpg create mode 100644 public/img/tutorials/cards/nuxt.jpg create mode 100644 public/img/tutorials/cards/okta.jpg create mode 100644 public/img/tutorials/cards/openai.jpg create mode 100644 public/img/tutorials/cards/railway.jpg create mode 100644 public/img/tutorials/cards/react.jpg create mode 100644 public/img/tutorials/cards/render.jpg create mode 100644 public/img/tutorials/cards/sentry.jpg create mode 100644 public/img/tutorials/cards/solidstart.jpg create mode 100644 public/img/tutorials/cards/spring-boot.jpg create mode 100644 public/img/tutorials/cards/stripe.jpg create mode 100644 public/img/tutorials/cards/supabase.jpg create mode 100644 public/img/tutorials/cards/sveltekit.jpg create mode 100644 public/img/tutorials/cards/swift.jpg create mode 100644 public/img/tutorials/cards/twilio.jpg create mode 100644 public/img/tutorials/cards/ubuntu.jpg create mode 100644 public/img/tutorials/cards/vercel.jpg create mode 100644 public/img/tutorials/cards/vonage.jpg create mode 100644 public/img/tutorials/cards/vue.jpg create mode 100644 public/img/tutorials/cards/wordpress.jpg create mode 100644 public/img/tutorials/cards/zapier.jpg create mode 100644 scripts/tutorial-cards.ts delete mode 100644 server/api/tutorialimg.ts diff --git a/.github/workflows/docs-checks.yml b/.github/workflows/docs-checks.yml index d1199bcf7..ce1e37179 100644 --- a/.github/workflows/docs-checks.yml +++ b/.github/workflows/docs-checks.yml @@ -12,6 +12,8 @@ on: - 'scripts/check-stable-ids.ts' - 'scripts/ensure-stable-ids.ts' - 'scripts/redirects-sync.ts' + - 'scripts/tutorial-cards.ts' + - 'public/img/tutorials/**' - 'package.json' - 'pnpm-lock.yaml' - '.github/workflows/docs-checks.yml' @@ -46,6 +48,9 @@ jobs: - name: Check stable IDs run: pnpm stable-ids:check + - name: Check tutorial cards + run: pnpm tutorial-cards:check + # Redirect check diffs against origin/main, so it only makes sense as a # pre-merge gate on PRs. On push to main the merge already landed and # origin/main points at the pushed commit (self-comparison), so skip it. diff --git a/app/components/TutorialCard.vue b/app/components/TutorialCard.vue index 67cefd862..bafd1272a 100644 --- a/app/components/TutorialCard.vue +++ b/app/components/TutorialCard.vue @@ -10,10 +10,8 @@ const props = defineProps<{ }; }>(); -const imageSrc = computed(() => { - const technologies = props.article.technologies?.length ? props.article.technologies : ['directus']; - return `/docs/api/tutorialimg?logos=${technologies.join(', ')}`; -}); +// Cards are baked by `pnpm tutorial-cards`. +const imageSrc = computed(() => `/docs/img/tutorials/cards/${props.article.technologies?.[0] ?? 'directus'}.jpg`);