From 604896df2d81ef56e72f79a80fb881c59834bca6 Mon Sep 17 00:00:00 2001 From: Michael Selander Date: Mon, 13 Jul 2026 15:33:45 -0600 Subject: [PATCH 1/7] Add templates list and detail pages --- package-lock.json | 1 + package.json | 1 + src/_data/templates.js | 303 ++++++++++++++++++++++++++ src/_layouts/main.webc | 4 +- src/lib/template-pages.js | 397 ++++++++++++++++++++++++++++++++++ src/templates/family.11ty.js | 39 ++++ src/templates/index.11ty.js | 23 ++ src/templates/variant.11ty.js | 39 ++++ 8 files changed, 805 insertions(+), 2 deletions(-) create mode 100644 src/_data/templates.js create mode 100644 src/lib/template-pages.js create mode 100644 src/templates/family.11ty.js create mode 100644 src/templates/index.11ty.js create mode 100644 src/templates/variant.11ty.js diff --git a/package-lock.json b/package-lock.json index fe2d7a0..e8c7080 100644 --- a/package-lock.json +++ b/package-lock.json @@ -21,6 +21,7 @@ "@types/react": "^19.2.14", "gray-matter": "^4.0.3", "html-minifier-terser": "^7.2.0", + "js-yaml": "^4.1.1", "markdown-it": "^14.1.1", "tailwindcss": "^4.0.14" }, diff --git a/package.json b/package.json index 7a5ba19..ea6101e 100644 --- a/package.json +++ b/package.json @@ -28,6 +28,7 @@ "@types/react": "^19.2.14", "gray-matter": "^4.0.3", "html-minifier-terser": "^7.2.0", + "js-yaml": "^4.1.1", "markdown-it": "^14.1.1", "tailwindcss": "^4.0.14" }, diff --git a/src/_data/templates.js b/src/_data/templates.js new file mode 100644 index 0000000..3a24f5f --- /dev/null +++ b/src/_data/templates.js @@ -0,0 +1,303 @@ +import fs from "fs"; +import yaml from "js-yaml"; +import providers from "./providers.js"; + +const REGISTRY_OWNER = "stripe"; +const REGISTRY_REPO = "projects-template-registry"; +const REGISTRY_REF = "main"; +const REGISTRY_API_BASE = `https://api.github.com/repos/${REGISTRY_OWNER}/${REGISTRY_REPO}`; +const REGISTRY_RAW_BASE = `https://raw.githubusercontent.com/${REGISTRY_OWNER}/${REGISTRY_REPO}/${REGISTRY_REF}`; +const GITHUB_HEADERS = { + Accept: "application/vnd.github+json", + "User-Agent": "projects-site", +}; + +const PROVIDER_NAME_OVERRIDES = { + e2b: "E2B", + openrouter: "OpenRouter", + auth0: "Auth0", + flyio: "Fly.io", +}; + +const ASSET_SOURCES = [ + { + dir: new URL("../assets/images/svg/provider-icons/", import.meta.url), + urlPrefix: "/assets/images/svg/provider-icons/", + }, + { + dir: new URL("../assets/images/svg/provider-logos/", import.meta.url), + urlPrefix: "/assets/images/svg/provider-logos/", + }, +]; + +const providerNameMap = new Map( + providers.map((provider) => [provider.slug.split("/")[0], provider.name]), +); + +function titleCase(value) { + return String(value) + .split(/[_-]+/) + .filter(Boolean) + .map((part) => part.charAt(0).toUpperCase() + part.slice(1)) + .join(" "); +} + +function getProviderName(providerSlug) { + return ( + PROVIDER_NAME_OVERRIDES[providerSlug] || + providerNameMap.get(providerSlug) || + titleCase(providerSlug) + ); +} + +function getProviderInitials(name) { + const parts = String(name).split(/\s+/).filter(Boolean); + if (parts.length === 0) return "?"; + if (parts.length === 1) return parts[0].slice(0, 2).toUpperCase(); + return parts + .slice(0, 2) + .map((part) => part[0].toUpperCase()) + .join(""); +} + +function getProviderIconUrl(providerSlug) { + for (const source of ASSET_SOURCES) { + const assetUrl = new URL(`${providerSlug}.svg`, source.dir); + if (fs.existsSync(assetUrl)) { + return `${source.urlPrefix}${providerSlug}.svg`; + } + } + + return null; +} + +function getRepoRootUrl(repoUrl) { + if (!repoUrl) return ""; + const match = repoUrl.match(/^(https:\/\/github\.com\/[^/]+\/[^/]+)/i); + return match ? match[1] : repoUrl; +} + +function normalizeTags(tags = []) { + const seen = new Set(); + return tags.filter(Boolean).filter((tag) => { + const key = String(tag).toLowerCase(); + if (seen.has(key)) return false; + seen.add(key); + return true; + }); +} + +function createServiceItem(serviceSlug) { + const [providerSlug, ...serviceParts] = String(serviceSlug).split("/"); + const providerName = getProviderName(providerSlug); + + return { + slug: serviceSlug, + providerSlug, + providerName, + serviceName: serviceParts.join("/"), + iconUrl: getProviderIconUrl(providerSlug), + fallbackInitials: getProviderInitials(providerName), + }; +} + +function sortVariants(left, right) { + if (left.isDefault !== right.isDefault) { + return left.isDefault ? -1 : 1; + } + + return left.variantId.localeCompare(right.variantId); +} + +function sortFamilies(left, right) { + return left.name.localeCompare(right.name); +} + +async function fetchJson(url) { + const response = await fetch(url, { headers: GITHUB_HEADERS }); + if (!response.ok) { + throw new Error(`GitHub request failed (${response.status}) for ${url}`); + } + return response.json(); +} + +async function fetchText(url) { + const response = await fetch(url, { headers: GITHUB_HEADERS }); + if (!response.ok) { + throw new Error(`GitHub request failed (${response.status}) for ${url}`); + } + return response.text(); +} + +export default async function () { + const tree = await fetchJson(`${REGISTRY_API_BASE}/git/trees/${REGISTRY_REF}?recursive=1`); + const guidedRaw = await fetchText(`${REGISTRY_RAW_BASE}/guided.yaml`); + const guided = yaml.load(guidedRaw) || {}; + const guidedCategories = new Map( + (guided.categories || []).map((category) => [category.key, category]), + ); + + const manifestPaths = (tree.tree || []) + .map((entry) => entry.path) + .filter((path) => path && /\.(yaml|yml)$/i.test(path)) + .filter((path) => path !== "guided.yaml" && path !== "example/example.yaml") + .sort((left, right) => left.localeCompare(right)); + + const manifestTexts = await Promise.all( + manifestPaths.map(async (path) => ({ + path, + source: await fetchText(`${REGISTRY_RAW_BASE}/${path}`), + })), + ); + + const variants = manifestTexts.map(({ path, source }) => { + const manifest = yaml.load(source); + + if (!manifest?.template || !manifest?.variant || !manifest?.metadata?.name) { + throw new Error(`Registry manifest is missing required fields: ${path}`); + } + + const [owner = "", templateSlug = ""] = String(manifest.template).split("/"); + const ownerSlug = owner.toLowerCase(); + const templatePathSlug = templateSlug.toLowerCase(); + const routeUrl = `/templates/${ownerSlug}/${templatePathSlug}/`; + const variantSlug = String(manifest.variant).toLowerCase(); + const services = (manifest.services || []).map(createServiceItem); + const categoryKey = manifest.guided?.category || "other"; + const frameworkKey = manifest.guided?.framework || "other"; + const categoryLabel = guidedCategories.get(categoryKey)?.label || titleCase(categoryKey); + + return { + templateId: manifest.template, + variantId: manifest.variant, + variantSlug, + fullTemplateId: `${manifest.template}/${manifest.variant}`, + familyPath: path.split("/")[0] || "", + path, + isDefault: Boolean(manifest.default), + routeUrl, + url: `/templates/${ownerSlug}/${templatePathSlug}/${variantSlug}/`, + ownerSlug, + templateSlug: templatePathSlug, + categoryKey, + categoryLabel, + frameworkKey, + frameworkLabel: titleCase(frameworkKey), + variantDescription: manifest.variant_description || "", + installCommand: manifest.install_command || "npm install", + repoUrl: manifest.repo, + repoRootUrl: getRepoRootUrl(manifest.repo), + ref: manifest.ref || "", + metadata: { + name: manifest.metadata.name, + description: manifest.metadata.description || "", + owner: manifest.metadata.owner || ownerSlug, + tags: normalizeTags(manifest.metadata.tags || []), + }, + services, + nextSteps: manifest.next_steps || [], + buildCommand: `stripe projects build my-app --template ${manifest.template}/${manifest.variant}`, + tierPlans: manifest.tier_plans || {}, + serviceOverrides: manifest.service_overrides || {}, + }; + }); + + const familiesById = new Map(); + + for (const variant of variants) { + const family = familiesById.get(variant.templateId) || { + templateId: variant.templateId, + ownerSlug: variant.ownerSlug, + templateSlug: variant.templateSlug, + url: variant.routeUrl, + variants: [], + }; + + family.variants.push(variant); + familiesById.set(variant.templateId, family); + } + + const families = Array.from(familiesById.values()) + .map((family) => { + const variants = family.variants.sort(sortVariants); + const canonicalVariant = variants[0]; + const servicesBySlug = new Map(); + const providersBySlug = new Map(); + const tags = []; + const seenTags = new Set(); + + for (const variant of variants) { + for (const service of variant.services) { + if (!servicesBySlug.has(service.slug)) { + servicesBySlug.set(service.slug, service); + } + if (!providersBySlug.has(service.providerSlug)) { + providersBySlug.set(service.providerSlug, { + providerSlug: service.providerSlug, + providerName: service.providerName, + iconUrl: service.iconUrl, + fallbackInitials: service.fallbackInitials, + }); + } + } + + for (const tag of variant.metadata.tags) { + const key = String(tag).toLowerCase(); + if (!seenTags.has(key)) { + seenTags.add(key); + tags.push(tag); + } + } + } + + return { + ...family, + name: canonicalVariant.metadata.name, + description: canonicalVariant.metadata.description, + owner: canonicalVariant.metadata.owner, + categoryKey: canonicalVariant.categoryKey, + categoryLabel: canonicalVariant.categoryLabel, + frameworkKey: canonicalVariant.frameworkKey, + frameworkLabel: canonicalVariant.frameworkLabel, + variantDescription: canonicalVariant.variantDescription, + buildCommand: `stripe projects build my-app --template ${family.templateId}`, + defaultVariant: canonicalVariant, + variantCount: variants.length, + services: Array.from(servicesBySlug.values()).sort((left, right) => + left.slug.localeCompare(right.slug), + ), + providers: Array.from(providersBySlug.values()).sort((left, right) => + left.providerName.localeCompare(right.providerName), + ), + tags, + variants, + }; + }) + .sort(sortFamilies); + + const enrichedVariants = families + .flatMap((family) => + family.variants.map((variant) => ({ + ...variant, + familyName: family.name, + familyDescription: family.description, + familyUrl: family.url, + familyBuildCommand: family.buildCommand, + familyVariantCount: family.variantCount, + siblingVariants: family.variants.map((sibling) => ({ + variantId: sibling.variantId, + variantDescription: sibling.variantDescription, + isDefault: sibling.isDefault, + url: sibling.url, + })), + })), + ) + .sort(sortVariants); + + return { + registryUrl: `https://github.com/${REGISTRY_OWNER}/${REGISTRY_REPO}`, + families, + variants: enrichedVariants, + categoryOptions: Array.from(guidedCategories.values()), + }; +} diff --git a/src/_layouts/main.webc b/src/_layouts/main.webc index 4373460..9da8c02 100644 --- a/src/_layouts/main.webc +++ b/src/_layouts/main.webc @@ -4,7 +4,7 @@ - + @@ -15,7 +15,7 @@ - + diff --git a/src/lib/template-pages.js b/src/lib/template-pages.js new file mode 100644 index 0000000..4b6696b --- /dev/null +++ b/src/lib/template-pages.js @@ -0,0 +1,397 @@ +function escapeHtml(value = "") { + return String(value) + .replaceAll("&", "&") + .replaceAll("<", "<") + .replaceAll(">", ">") + .replaceAll('"', """) + .replaceAll("'", "'"); +} + +function renderLogo(item, sizeClass = "w-16 h-16") { + if (item.iconUrl) { + return ``; + } + + return `${escapeHtml(item.fallbackInitials)}`; +} + +function renderMetaPill(label) { + return `${escapeHtml(label)}`; +} + +function renderServiceBadge(service) { + return `${renderLogo(service, "w-14 h-14")}${escapeHtml(service.slug)}`; +} + +function renderLinkButton(href, label) { + return ` + ${escapeHtml(label)} + + `; +} + +function renderCopyButton(command, label = "Copy command") { + return ``; +} + +function renderHeader({ backHref, backLabel, rightHref, rightLabel }) { + const left = backHref + ? ` + + ${escapeHtml(backLabel)} + ` + : "
"; + const right = rightHref + ? `` + : "
"; + + return `
+
+ ${left} + +
+ + + + Stripe Projects +
+
+ ${right} +
+
`; +} + +function renderFooter() { + return ``; +} + +function renderCopySupport() { + return ` + `; +} + +export function renderTemplatesIndex(templates) { + const cards = templates.families + .map((family) => { + const services = family.services.slice(0, 6); + const extraServices = family.services.length - services.length; + + return `
+
+
+
+ ${escapeHtml(family.owner)} + ${renderMetaPill(family.categoryLabel)} + ${renderMetaPill(family.frameworkLabel)} +
+

${escapeHtml(family.name)}

+

${escapeHtml(family.description)}

+
+ ${renderMetaPill(`${family.variantCount} variant${family.variantCount === 1 ? "" : "s"}`)} +
+ +
+ ${services.map(renderServiceBadge).join("")} + ${extraServices > 0 ? renderMetaPill(`+${extraServices} more`) : ""} +
+ +
+

Default command

+ ${escapeHtml(family.buildCommand)} +
+ +
+

${escapeHtml(family.variantDescription || "Browse variants and providers")}

+
+ ${renderCopyButton(family.buildCommand)} + ${renderLinkButton(family.url, "View template")} +
+
+
`; + }) + .join(""); + + return `
+ ${renderHeader({ backHref: "/", backLabel: "Home", rightHref: templates.registryUrl, rightLabel: "Registry repo" })} + +
+
+
+
+

Templates

+

Browse every starter currently published in the public Stripe Projects template registry. Each template page shows its variants, included services, and the exact stripe projects build command to run.

+
+ ${renderMetaPill(`${templates.families.length} families`)} + ${renderMetaPill(`${templates.variants.length} variants`)} + View public registry +
+
+
+
+ +
+
+ ${cards} +
+
+
+ + ${renderFooter()} + ${renderCopySupport()} +
`; +} + +export function renderTemplateFamilyPage(family) { + const variants = family.variants + .map((variant) => { + const services = variant.services.map(renderServiceBadge).join(""); + const nextSteps = variant.nextSteps.length + ? `
+

Next steps

+ ${variant.nextSteps + .map( + (step) => `
+

${escapeHtml(step.label)}

+ ${escapeHtml(step.command)} +
`, + ) + .join("")} +
` + : ""; + + return `
+
+
+
+ ${variant.isDefault ? renderMetaPill("Default") : ""} + ${renderMetaPill(variant.variantId)} +
+

${escapeHtml(variant.variantDescription || variant.variantId)}

+

Template selector: ${escapeHtml(variant.fullTemplateId)}

+
+ ${renderCopyButton(variant.buildCommand)} +
+ +
+

Build command

+ ${escapeHtml(variant.buildCommand)} +
+ +
+ ${services} +
+ +
+
+

Source

+

${escapeHtml(variant.repoRootUrl)}

+

Pinned ref: ${escapeHtml(variant.ref || "Unpinned")}

+
+
+

Setup

+

Install command

+ ${escapeHtml(variant.installCommand)} +
+
+ + ${nextSteps} + +
+ ${renderLinkButton(variant.url, "Open variant page")} +
+
`; + }) + .join(""); + + const tags = family.tags.length ? `
${family.tags.map(renderMetaPill).join("")}
` : ""; + + return `
+ ${renderHeader({ backHref: "/templates/", backLabel: "All templates", rightHref: family.defaultVariant.repoUrl, rightLabel: "Source repo" })} + +
+
+
+
+ ${renderMetaPill(family.owner)} + ${renderMetaPill(family.categoryLabel)} + ${renderMetaPill(family.frameworkLabel)} + ${renderMetaPill(`${family.variantCount} variant${family.variantCount === 1 ? "" : "s"}`)} +
+ +

${escapeHtml(family.name)}

+

${escapeHtml(family.description)}

+ +
+ ${family.services.map(renderServiceBadge).join("")} +
+ + ${tags} + +
+
+
+

Default build command

+ ${escapeHtml(family.buildCommand)} +
+ ${renderCopyButton(family.buildCommand)} +
+

This uses the registry’s default variant for ${escapeHtml(family.templateId)}. Use the variant-specific commands below to target a particular stack.

+
+
+
+ +
+
+ ${variants} +
+
+
+ + ${renderFooter()} + ${renderCopySupport()} +
`; +} + +export function renderTemplateVariantPage(variant) { + const nextSteps = variant.nextSteps.length + ? `
+

Next steps

+
+ ${variant.nextSteps + .map( + (step) => `
+

${escapeHtml(step.label)}

+ ${escapeHtml(step.command)} +
`, + ) + .join("")} +
+
` + : ""; + + const siblingVariants = variant.siblingVariants.length + ? `
+
+
+

Other variants

+

Browse the other stacks published under ${escapeHtml(variant.templateId)}.

+
+ ${renderLinkButton(variant.familyUrl, "View all variants")} +
+
+ ${variant.siblingVariants + .map((sibling) => + sibling.url === variant.url + ? `${escapeHtml(sibling.variantDescription || sibling.variantId)}${sibling.isDefault ? " • Default" : ""}` + : `${escapeHtml(sibling.variantDescription || sibling.variantId)}${sibling.isDefault ? " • Default" : ""}`, + ) + .join("")} +
+
` + : ""; + + return `
+ ${renderHeader({ backHref: variant.familyUrl, backLabel: "All variants", rightHref: variant.repoUrl, rightLabel: "Source repo" })} + +
+
+
+
+ ${renderMetaPill(variant.metadata.owner)} + ${renderMetaPill(variant.categoryLabel)} + ${renderMetaPill(variant.frameworkLabel)} + ${variant.isDefault ? renderMetaPill("Default variant") : ""} +
+ +

${escapeHtml(variant.metadata.name)}

+

${escapeHtml(variant.metadata.description)}

+

Variant: ${escapeHtml(variant.fullTemplateId)}

+ +
+ ${variant.services.map(renderServiceBadge).join("")} +
+ +
+
+
+
+

Build command

+ ${escapeHtml(variant.buildCommand)} +
+ ${renderCopyButton(variant.buildCommand)} +
+

This targets the specific ${escapeHtml(variant.variantId)} variant directly.

+
+ +
+
+

Source

+

${escapeHtml(variant.repoRootUrl)}

+

Pinned ref: ${escapeHtml(variant.ref || "Unpinned")}

+
+
+

Setup

+

Install command

+ ${escapeHtml(variant.installCommand)} +
+
+ + ${nextSteps} + ${siblingVariants} +
+
+
+
+ + ${renderFooter()} + ${renderCopySupport()} +
`; +} diff --git a/src/templates/family.11ty.js b/src/templates/family.11ty.js new file mode 100644 index 0000000..d689c6d --- /dev/null +++ b/src/templates/family.11ty.js @@ -0,0 +1,39 @@ +import { renderTemplateFamilyPage } from "../lib/template-pages.js"; + +export default class TemplateFamilyPage { + data() { + return { + pagination: { + data: "templates.families", + size: 1, + alias: "templateFamily", + }, + permalink: (data) => data.templateFamily?.url, + layout: "main.webc", + ogImage: "/assets/images/og/default.jpg", + ogImageAlt: "Stripe Projects template details", + eleventyComputed: { + canonicalUrl: (data) => + `${data.base?.siteOrigin || ""}${data.templateFamily?.url || data.page?.url || "/"}`, + ogUrl: (data) => + `${data.base?.siteOrigin || ""}${data.templateFamily?.url || data.page?.url || "/"}`, + seoTitle: (data) => + `${data.templateFamily?.name || "Template"} | Stripe Projects Templates`, + ogTitle: (data) => + `${data.templateFamily?.name || "Template"} | Stripe Projects Templates`, + seoDesc: (data) => + data.templateFamily?.description || + "Inspect template variants, services, and build commands.", + ogDesc: (data) => + data.templateFamily?.description || + "Inspect template variants, services, and build commands.", + }, + changefreq: "daily", + wave: false, + }; + } + + render(data) { + return renderTemplateFamilyPage(data.templateFamily); + } +} diff --git a/src/templates/index.11ty.js b/src/templates/index.11ty.js new file mode 100644 index 0000000..aeb69a6 --- /dev/null +++ b/src/templates/index.11ty.js @@ -0,0 +1,23 @@ +import { renderTemplatesIndex } from "../lib/template-pages.js"; + +export default class TemplatesIndexPage { + data() { + return { + permalink: "/templates/", + layout: "main.webc", + title: "Templates", + seoTitle: "Templates | Stripe Projects", + ogTitle: "Templates | Stripe Projects", + seoDesc: "Browse Stripe Projects templates and inspect every variant, provider, and build command.", + ogDesc: "Browse Stripe Projects templates and inspect every variant, provider, and build command.", + ogImage: "/assets/images/og/default.jpg", + ogImageAlt: "Stripe Projects templates", + changefreq: "daily", + wave: false, + }; + } + + render(data) { + return renderTemplatesIndex(data.templates); + } +} diff --git a/src/templates/variant.11ty.js b/src/templates/variant.11ty.js new file mode 100644 index 0000000..3885396 --- /dev/null +++ b/src/templates/variant.11ty.js @@ -0,0 +1,39 @@ +import { renderTemplateVariantPage } from "../lib/template-pages.js"; + +export default class TemplateVariantPage { + data() { + return { + pagination: { + data: "templates.variants", + size: 1, + alias: "templateVariant", + }, + permalink: (data) => data.templateVariant?.url, + layout: "main.webc", + ogImage: "/assets/images/og/default.jpg", + ogImageAlt: "Stripe Projects template variant details", + eleventyComputed: { + canonicalUrl: (data) => + `${data.base?.siteOrigin || ""}${data.templateVariant?.url || data.page?.url || "/"}`, + ogUrl: (data) => + `${data.base?.siteOrigin || ""}${data.templateVariant?.url || data.page?.url || "/"}`, + seoTitle: (data) => + `${data.templateVariant?.metadata?.name || "Template"}: ${data.templateVariant?.variantDescription || data.templateVariant?.variantId || "Variant"} | Stripe Projects`, + ogTitle: (data) => + `${data.templateVariant?.metadata?.name || "Template"}: ${data.templateVariant?.variantDescription || data.templateVariant?.variantId || "Variant"} | Stripe Projects`, + seoDesc: (data) => + data.templateVariant?.metadata?.description || + "Inspect a Stripe Projects template variant, included services, and its exact build command.", + ogDesc: (data) => + data.templateVariant?.metadata?.description || + "Inspect a Stripe Projects template variant, included services, and its exact build command.", + }, + changefreq: "daily", + wave: false, + }; + } + + render(data) { + return renderTemplateVariantPage(data.templateVariant); + } +} From 671bbe32a4e4cd2457d0e66fae492574caafc2bd Mon Sep 17 00:00:00 2001 From: Mike Stilling Date: Tue, 14 Jul 2026 08:00:58 -0500 Subject: [PATCH 2/7] Initial design explorations --- eleventy.config.js | 11 + src/_data/templates.js | 39 +++- src/assets/css/main.css | 13 ++ .../images/provider-favicons/agentmail.svg | 15 ++ .../images/provider-favicons/agentphone.svg | 13 ++ .../images/provider-favicons/algolia.svg | 11 + .../images/provider-favicons/amplitude.svg | 11 + src/assets/images/provider-favicons/auth0.svg | 11 + .../images/provider-favicons/base44.svg | 11 + .../images/provider-favicons/blaxel.svg | 125 ++++++++++ .../images/provider-favicons/browserbase.svg | 11 + .../images/provider-favicons/chatbase.svg | 17 ++ .../images/provider-favicons/chroma.svg | 13 ++ src/assets/images/provider-favicons/clerk.svg | 13 ++ .../images/provider-favicons/clickhouse.svg | 15 ++ .../images/provider-favicons/cloudflare.svg | 12 + .../images/provider-favicons/composio.svg | 11 + .../images/provider-favicons/createos.svg | 11 + .../images/provider-favicons/customerio.svg | 13 ++ .../images/provider-favicons/daytona.svg | 16 ++ src/assets/images/provider-favicons/depot.svg | 12 + src/assets/images/provider-favicons/e2b.svg | 11 + .../images/provider-favicons/elevenlabs.svg | 12 + src/assets/images/provider-favicons/exa.svg | 11 + .../images/provider-favicons/firecrawl.svg | 11 + src/assets/images/provider-favicons/flyio.svg | 13 ++ .../images/provider-favicons/gitlab.svg | 14 ++ .../images/provider-favicons/heygen.svg | 202 ++++++++++++++++ .../images/provider-favicons/huggingface.svg | 14 ++ .../images/provider-favicons/inngest.svg | 11 + .../images/provider-favicons/kernel.svg | 15 ++ .../images/provider-favicons/laravelcloud.svg | 11 + .../images/provider-favicons/metronome.svg | 20 ++ .../images/provider-favicons/mixpanel.svg | 11 + src/assets/images/provider-favicons/neon.svg | 11 + .../images/provider-favicons/netlify.svg | 22 ++ .../images/provider-favicons/nextjs.svg | 21 ++ .../images/provider-favicons/openai.svg | 11 + .../images/provider-favicons/openrouter.svg | 11 + .../images/provider-favicons/parallel.svg | 18 ++ .../images/provider-favicons/planetscale.svg | 12 + .../images/provider-favicons/postalform.svg | 16 ++ .../images/provider-favicons/posthog.svg | 15 ++ .../images/provider-favicons/prisma.svg | 11 + src/assets/images/provider-favicons/privy.svg | 12 + .../images/provider-favicons/pydantic.svg | 11 + .../images/provider-favicons/railway.svg | 16 ++ .../images/provider-favicons/render.svg | 11 + .../images/provider-favicons/runloop.svg | 12 + .../images/provider-favicons/sentry.svg | 11 + src/assets/images/provider-favicons/sinch.svg | 11 + .../images/provider-favicons/spaceship.svg | 11 + .../images/provider-favicons/squarespace.svg | 15 ++ .../images/provider-favicons/stripe.svg | 11 + .../images/provider-favicons/supabase.svg | 21 ++ .../images/provider-favicons/supermemory.svg | 12 + .../images/provider-favicons/tabstack.svg | 11 + .../images/provider-favicons/tailwind.svg | 11 + src/assets/images/provider-favicons/turso.svg | 13 ++ .../images/provider-favicons/twilio.svg | 15 ++ .../images/provider-favicons/upstash.svg | 14 ++ .../images/provider-favicons/vercel.svg | 11 + src/assets/images/provider-favicons/wix.svg | 11 + .../images/provider-favicons/wordpress.svg | 11 + .../images/provider-favicons/workos.svg | 12 + .../images/provider-logos/logo-agentmail.svg | 17 ++ .../images/provider-logos/logo-agentphone.svg | 18 ++ .../images/provider-logos/logo-algolia.svg | 11 + .../images/provider-logos/logo-amplitude.svg | 14 ++ .../images/provider-logos/logo-auth0.svg | 11 + .../images/provider-logos/logo-base44.svg | 4 + .../images/provider-logos/logo-blaxel.svg | 120 ++++++++++ .../provider-logos/logo-browserbase.svg | 16 ++ .../images/provider-logos/logo-chroma.svg | 6 + .../images/provider-logos/logo-clerk.svg | 10 + .../images/provider-logos/logo-clickhouse.svg | 18 ++ .../images/provider-logos/logo-cloudflare.svg | 14 ++ .../images/provider-logos/logo-daytona.svg | 15 ++ src/assets/images/provider-logos/logo-e2b.svg | 5 + .../images/provider-logos/logo-elevenlabs.svg | 14 ++ src/assets/images/provider-logos/logo-exa.svg | 6 + .../images/provider-logos/logo-firecrawl.svg | 13 ++ .../images/provider-logos/logo-flyio.svg | 5 + .../images/provider-logos/logo-gitlab.svg | 13 ++ .../images/provider-logos/logo-heygen.svg | 207 ++++++++++++++++ .../provider-logos/logo-huggingface.svg | 7 + .../images/provider-logos/logo-inngest.svg | 10 + .../images/provider-logos/logo-kernel.svg | 9 + .../provider-logos/logo-laravelcloud.svg | 15 ++ .../images/provider-logos/logo-metronome.svg | 16 ++ .../images/provider-logos/logo-mixpanel.svg | 3 + .../images/provider-logos/logo-neon.svg | 4 + .../images/provider-logos/logo-netlify.svg | 16 ++ .../images/provider-logos/logo-openrouter.svg | 13 ++ .../images/provider-logos/logo-parallel.svg | 18 ++ .../provider-logos/logo-planetscale.svg | 15 ++ .../images/provider-logos/logo-postalform.svg | 9 + .../images/provider-logos/logo-posthog.svg | 8 + .../images/provider-logos/logo-prisma.svg | 10 + .../images/provider-logos/logo-privy.svg | 9 + .../images/provider-logos/logo-railway.svg | 16 ++ .../images/provider-logos/logo-render.svg | 9 + .../images/provider-logos/logo-runloop.svg | 11 + .../images/provider-logos/logo-sentry.svg | 3 + .../provider-logos/logo-squarespace.svg | 19 ++ .../images/provider-logos/logo-stripe.svg | 3 + .../images/provider-logos/logo-supabase.svg | 20 ++ .../provider-logos/logo-supermemory.svg | 16 ++ .../images/provider-logos/logo-turso.svg | 10 + .../images/provider-logos/logo-twilio.svg | 13 ++ .../images/provider-logos/logo-upstash.svg | 8 + .../images/provider-logos/logo-vercel.svg | 3 + src/assets/images/provider-logos/logo-wix.svg | 3 + .../images/provider-logos/logo-wordpress.svg | 16 ++ .../images/provider-logos/logo-workos.svg | 12 + src/templates-v2.webc | 220 ++++++++++++++++++ src/templates-v3.webc | 203 ++++++++++++++++ 117 files changed, 2454 insertions(+), 1 deletion(-) create mode 100644 src/assets/images/provider-favicons/agentmail.svg create mode 100644 src/assets/images/provider-favicons/agentphone.svg create mode 100644 src/assets/images/provider-favicons/algolia.svg create mode 100644 src/assets/images/provider-favicons/amplitude.svg create mode 100644 src/assets/images/provider-favicons/auth0.svg create mode 100644 src/assets/images/provider-favicons/base44.svg create mode 100644 src/assets/images/provider-favicons/blaxel.svg create mode 100644 src/assets/images/provider-favicons/browserbase.svg create mode 100644 src/assets/images/provider-favicons/chatbase.svg create mode 100644 src/assets/images/provider-favicons/chroma.svg create mode 100644 src/assets/images/provider-favicons/clerk.svg create mode 100644 src/assets/images/provider-favicons/clickhouse.svg create mode 100644 src/assets/images/provider-favicons/cloudflare.svg create mode 100644 src/assets/images/provider-favicons/composio.svg create mode 100644 src/assets/images/provider-favicons/createos.svg create mode 100644 src/assets/images/provider-favicons/customerio.svg create mode 100644 src/assets/images/provider-favicons/daytona.svg create mode 100644 src/assets/images/provider-favicons/depot.svg create mode 100644 src/assets/images/provider-favicons/e2b.svg create mode 100644 src/assets/images/provider-favicons/elevenlabs.svg create mode 100644 src/assets/images/provider-favicons/exa.svg create mode 100644 src/assets/images/provider-favicons/firecrawl.svg create mode 100644 src/assets/images/provider-favicons/flyio.svg create mode 100644 src/assets/images/provider-favicons/gitlab.svg create mode 100644 src/assets/images/provider-favicons/heygen.svg create mode 100644 src/assets/images/provider-favicons/huggingface.svg create mode 100644 src/assets/images/provider-favicons/inngest.svg create mode 100644 src/assets/images/provider-favicons/kernel.svg create mode 100644 src/assets/images/provider-favicons/laravelcloud.svg create mode 100644 src/assets/images/provider-favicons/metronome.svg create mode 100644 src/assets/images/provider-favicons/mixpanel.svg create mode 100644 src/assets/images/provider-favicons/neon.svg create mode 100644 src/assets/images/provider-favicons/netlify.svg create mode 100644 src/assets/images/provider-favicons/nextjs.svg create mode 100644 src/assets/images/provider-favicons/openai.svg create mode 100644 src/assets/images/provider-favicons/openrouter.svg create mode 100644 src/assets/images/provider-favicons/parallel.svg create mode 100644 src/assets/images/provider-favicons/planetscale.svg create mode 100644 src/assets/images/provider-favicons/postalform.svg create mode 100644 src/assets/images/provider-favicons/posthog.svg create mode 100644 src/assets/images/provider-favicons/prisma.svg create mode 100644 src/assets/images/provider-favicons/privy.svg create mode 100644 src/assets/images/provider-favicons/pydantic.svg create mode 100644 src/assets/images/provider-favicons/railway.svg create mode 100644 src/assets/images/provider-favicons/render.svg create mode 100644 src/assets/images/provider-favicons/runloop.svg create mode 100644 src/assets/images/provider-favicons/sentry.svg create mode 100644 src/assets/images/provider-favicons/sinch.svg create mode 100644 src/assets/images/provider-favicons/spaceship.svg create mode 100644 src/assets/images/provider-favicons/squarespace.svg create mode 100644 src/assets/images/provider-favicons/stripe.svg create mode 100644 src/assets/images/provider-favicons/supabase.svg create mode 100644 src/assets/images/provider-favicons/supermemory.svg create mode 100644 src/assets/images/provider-favicons/tabstack.svg create mode 100644 src/assets/images/provider-favicons/tailwind.svg create mode 100644 src/assets/images/provider-favicons/turso.svg create mode 100644 src/assets/images/provider-favicons/twilio.svg create mode 100644 src/assets/images/provider-favicons/upstash.svg create mode 100644 src/assets/images/provider-favicons/vercel.svg create mode 100644 src/assets/images/provider-favicons/wix.svg create mode 100644 src/assets/images/provider-favicons/wordpress.svg create mode 100644 src/assets/images/provider-favicons/workos.svg create mode 100644 src/assets/images/provider-logos/logo-agentmail.svg create mode 100644 src/assets/images/provider-logos/logo-agentphone.svg create mode 100644 src/assets/images/provider-logos/logo-algolia.svg create mode 100644 src/assets/images/provider-logos/logo-amplitude.svg create mode 100644 src/assets/images/provider-logos/logo-auth0.svg create mode 100644 src/assets/images/provider-logos/logo-base44.svg create mode 100644 src/assets/images/provider-logos/logo-blaxel.svg create mode 100644 src/assets/images/provider-logos/logo-browserbase.svg create mode 100644 src/assets/images/provider-logos/logo-chroma.svg create mode 100644 src/assets/images/provider-logos/logo-clerk.svg create mode 100644 src/assets/images/provider-logos/logo-clickhouse.svg create mode 100644 src/assets/images/provider-logos/logo-cloudflare.svg create mode 100644 src/assets/images/provider-logos/logo-daytona.svg create mode 100644 src/assets/images/provider-logos/logo-e2b.svg create mode 100644 src/assets/images/provider-logos/logo-elevenlabs.svg create mode 100644 src/assets/images/provider-logos/logo-exa.svg create mode 100644 src/assets/images/provider-logos/logo-firecrawl.svg create mode 100644 src/assets/images/provider-logos/logo-flyio.svg create mode 100644 src/assets/images/provider-logos/logo-gitlab.svg create mode 100644 src/assets/images/provider-logos/logo-heygen.svg create mode 100644 src/assets/images/provider-logos/logo-huggingface.svg create mode 100644 src/assets/images/provider-logos/logo-inngest.svg create mode 100644 src/assets/images/provider-logos/logo-kernel.svg create mode 100644 src/assets/images/provider-logos/logo-laravelcloud.svg create mode 100644 src/assets/images/provider-logos/logo-metronome.svg create mode 100644 src/assets/images/provider-logos/logo-mixpanel.svg create mode 100644 src/assets/images/provider-logos/logo-neon.svg create mode 100644 src/assets/images/provider-logos/logo-netlify.svg create mode 100644 src/assets/images/provider-logos/logo-openrouter.svg create mode 100644 src/assets/images/provider-logos/logo-parallel.svg create mode 100644 src/assets/images/provider-logos/logo-planetscale.svg create mode 100644 src/assets/images/provider-logos/logo-postalform.svg create mode 100644 src/assets/images/provider-logos/logo-posthog.svg create mode 100644 src/assets/images/provider-logos/logo-prisma.svg create mode 100644 src/assets/images/provider-logos/logo-privy.svg create mode 100644 src/assets/images/provider-logos/logo-railway.svg create mode 100644 src/assets/images/provider-logos/logo-render.svg create mode 100644 src/assets/images/provider-logos/logo-runloop.svg create mode 100644 src/assets/images/provider-logos/logo-sentry.svg create mode 100644 src/assets/images/provider-logos/logo-squarespace.svg create mode 100644 src/assets/images/provider-logos/logo-stripe.svg create mode 100644 src/assets/images/provider-logos/logo-supabase.svg create mode 100644 src/assets/images/provider-logos/logo-supermemory.svg create mode 100644 src/assets/images/provider-logos/logo-turso.svg create mode 100644 src/assets/images/provider-logos/logo-twilio.svg create mode 100644 src/assets/images/provider-logos/logo-upstash.svg create mode 100644 src/assets/images/provider-logos/logo-vercel.svg create mode 100644 src/assets/images/provider-logos/logo-wix.svg create mode 100644 src/assets/images/provider-logos/logo-wordpress.svg create mode 100644 src/assets/images/provider-logos/logo-workos.svg create mode 100644 src/templates-v2.webc create mode 100644 src/templates-v3.webc diff --git a/eleventy.config.js b/eleventy.config.js index 69c9426..3c8a759 100644 --- a/eleventy.config.js +++ b/eleventy.config.js @@ -88,6 +88,17 @@ export default function(eleventyConfig) { slugify: eleventyConfig.getFilter("slugify"), }); + // Check if a provider logo exists on disk + eleventyConfig.addJavaScriptFunction("logoExists", (owner) => { + const name = owner.split('-')[0].trim(); + return fs.existsSync(`src/assets/images/provider-logos/logo-${name}.svg`); + }); + + // Check if a provider favicon exists on disk + eleventyConfig.addJavaScriptFunction("faviconExists", (slug) => { + return fs.existsSync(`src/assets/images/provider-favicons/${slug}.svg`); + }); + // Image optimization eleventyConfig.addPlugin(eleventyImageTransformPlugin); diff --git a/src/_data/templates.js b/src/_data/templates.js index 3a24f5f..26e9625 100644 --- a/src/_data/templates.js +++ b/src/_data/templates.js @@ -1,4 +1,6 @@ import fs from "fs"; +import path from "path"; +import { fileURLToPath } from "url"; import yaml from "js-yaml"; import providers from "./providers.js"; @@ -12,6 +14,35 @@ const GITHUB_HEADERS = { "User-Agent": "projects-site", }; +const __dirname = path.dirname(fileURLToPath(import.meta.url)); +const CACHE_DIR = path.resolve(__dirname, "../../.cache"); +const CACHE_FILE = path.join(CACHE_DIR, "templates-registry.json"); +const CACHE_TTL_MS = 1000 * 60 * 60; // 1 hour + +function readCache() { + try { + if (!fs.existsSync(CACHE_FILE)) return null; + const raw = fs.readFileSync(CACHE_FILE, "utf-8"); + const cached = JSON.parse(raw); + if (Date.now() - cached.timestamp < CACHE_TTL_MS) return cached.data; + } catch { + // corrupt cache — ignore + } + return null; +} + +function writeCache(data) { + try { + fs.mkdirSync(CACHE_DIR, { recursive: true }); + fs.writeFileSync( + CACHE_FILE, + JSON.stringify({ timestamp: Date.now(), data }), + ); + } catch { + // non-critical — skip silently + } +} + const PROVIDER_NAME_OVERRIDES = { e2b: "E2B", openrouter: "OpenRouter", @@ -130,6 +161,9 @@ async function fetchText(url) { } export default async function () { + const cached = readCache(); + if (cached) return cached; + const tree = await fetchJson(`${REGISTRY_API_BASE}/git/trees/${REGISTRY_REF}?recursive=1`); const guidedRaw = await fetchText(`${REGISTRY_RAW_BASE}/guided.yaml`); const guided = yaml.load(guidedRaw) || {}; @@ -294,10 +328,13 @@ export default async function () { ) .sort(sortVariants); - return { + const result = { registryUrl: `https://github.com/${REGISTRY_OWNER}/${REGISTRY_REPO}`, families, variants: enrichedVariants, categoryOptions: Array.from(guidedCategories.values()), }; + + writeCache(result); + return result; } diff --git a/src/assets/css/main.css b/src/assets/css/main.css index ea48b62..40cfeaf 100644 --- a/src/assets/css/main.css +++ b/src/assets/css/main.css @@ -319,6 +319,8 @@ --mask-radial-code: radial-gradient(100% 100% at 0% 0%, rgba(0,0,0, 1) 75%, rgba(0,0,0, 0.25) 100%); --shadow-focus: 0px 0px 0px 2px rgb(from var(--hex-brand-600) r g b / 0.25); + --shadow-focus-hl: 0px 0px 0px 1px var(--hex-neutral-0), 0px 0px 0px 3px rgb(from var(--hex-brand-600) r g b / 1); + --shadow-focus-fg: 0px 0px 0px 1px var(--hex-neutral-25), 0px 0px 0px 2px var(--hex-brand-600); --shadow-border: 0px 0px 0px 1px rgb(from var(--hex-neutral-990) r g b / 0.1); --shadow-border-light: 0px 0px 0px 1px rgb(from var(--hex-neutral-990) r g b / 0.06); --shadow-inset-border: inset 0px 0px 0px 1px rgb(from var(--hex-neutral-990) r g b / 0.12); @@ -344,6 +346,17 @@ scrollbar-width: none; } +/* Show scrollbars on focus-visible (overlay so content doesn't shift) */ +.no-scrollbar:focus-visible::-webkit-scrollbar { + display: initial; +} + +.no-scrollbar:focus-visible { + -ms-overflow-style: auto; + scrollbar-width: thin; + overflow: overlay; +} + /* 8px dot grid background */ .dot-grid-8 { background-image: radial-gradient(circle, color-mix(in srgb, var(--color-neutral-200) 35%, transparent) 1px, transparent 1px); diff --git a/src/assets/images/provider-favicons/agentmail.svg b/src/assets/images/provider-favicons/agentmail.svg new file mode 100644 index 0000000..7b039fc --- /dev/null +++ b/src/assets/images/provider-favicons/agentmail.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/src/assets/images/provider-favicons/agentphone.svg b/src/assets/images/provider-favicons/agentphone.svg new file mode 100644 index 0000000..adda758 --- /dev/null +++ b/src/assets/images/provider-favicons/agentphone.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/src/assets/images/provider-favicons/algolia.svg b/src/assets/images/provider-favicons/algolia.svg new file mode 100644 index 0000000..226c412 --- /dev/null +++ b/src/assets/images/provider-favicons/algolia.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/src/assets/images/provider-favicons/amplitude.svg b/src/assets/images/provider-favicons/amplitude.svg new file mode 100644 index 0000000..5b3bb88 --- /dev/null +++ b/src/assets/images/provider-favicons/amplitude.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/src/assets/images/provider-favicons/auth0.svg b/src/assets/images/provider-favicons/auth0.svg new file mode 100644 index 0000000..7424b18 --- /dev/null +++ b/src/assets/images/provider-favicons/auth0.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/src/assets/images/provider-favicons/base44.svg b/src/assets/images/provider-favicons/base44.svg new file mode 100644 index 0000000..c1833ae --- /dev/null +++ b/src/assets/images/provider-favicons/base44.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/src/assets/images/provider-favicons/blaxel.svg b/src/assets/images/provider-favicons/blaxel.svg new file mode 100644 index 0000000..e9ee7dc --- /dev/null +++ b/src/assets/images/provider-favicons/blaxel.svg @@ -0,0 +1,125 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/images/provider-favicons/browserbase.svg b/src/assets/images/provider-favicons/browserbase.svg new file mode 100644 index 0000000..285233f --- /dev/null +++ b/src/assets/images/provider-favicons/browserbase.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/src/assets/images/provider-favicons/chatbase.svg b/src/assets/images/provider-favicons/chatbase.svg new file mode 100644 index 0000000..947959e --- /dev/null +++ b/src/assets/images/provider-favicons/chatbase.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/src/assets/images/provider-favicons/chroma.svg b/src/assets/images/provider-favicons/chroma.svg new file mode 100644 index 0000000..785fdca --- /dev/null +++ b/src/assets/images/provider-favicons/chroma.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/src/assets/images/provider-favicons/clerk.svg b/src/assets/images/provider-favicons/clerk.svg new file mode 100644 index 0000000..2f56166 --- /dev/null +++ b/src/assets/images/provider-favicons/clerk.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/src/assets/images/provider-favicons/clickhouse.svg b/src/assets/images/provider-favicons/clickhouse.svg new file mode 100644 index 0000000..70e2aac --- /dev/null +++ b/src/assets/images/provider-favicons/clickhouse.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/src/assets/images/provider-favicons/cloudflare.svg b/src/assets/images/provider-favicons/cloudflare.svg new file mode 100644 index 0000000..92dc49e --- /dev/null +++ b/src/assets/images/provider-favicons/cloudflare.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/src/assets/images/provider-favicons/composio.svg b/src/assets/images/provider-favicons/composio.svg new file mode 100644 index 0000000..a7fd4c1 --- /dev/null +++ b/src/assets/images/provider-favicons/composio.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/src/assets/images/provider-favicons/createos.svg b/src/assets/images/provider-favicons/createos.svg new file mode 100644 index 0000000..bf15ee5 --- /dev/null +++ b/src/assets/images/provider-favicons/createos.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/src/assets/images/provider-favicons/customerio.svg b/src/assets/images/provider-favicons/customerio.svg new file mode 100644 index 0000000..73cae43 --- /dev/null +++ b/src/assets/images/provider-favicons/customerio.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/src/assets/images/provider-favicons/daytona.svg b/src/assets/images/provider-favicons/daytona.svg new file mode 100644 index 0000000..3a9c3af --- /dev/null +++ b/src/assets/images/provider-favicons/daytona.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/src/assets/images/provider-favicons/depot.svg b/src/assets/images/provider-favicons/depot.svg new file mode 100644 index 0000000..cf20092 --- /dev/null +++ b/src/assets/images/provider-favicons/depot.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/src/assets/images/provider-favicons/e2b.svg b/src/assets/images/provider-favicons/e2b.svg new file mode 100644 index 0000000..aadd568 --- /dev/null +++ b/src/assets/images/provider-favicons/e2b.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/src/assets/images/provider-favicons/elevenlabs.svg b/src/assets/images/provider-favicons/elevenlabs.svg new file mode 100644 index 0000000..0dce79f --- /dev/null +++ b/src/assets/images/provider-favicons/elevenlabs.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/src/assets/images/provider-favicons/exa.svg b/src/assets/images/provider-favicons/exa.svg new file mode 100644 index 0000000..fc1f85f --- /dev/null +++ b/src/assets/images/provider-favicons/exa.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/src/assets/images/provider-favicons/firecrawl.svg b/src/assets/images/provider-favicons/firecrawl.svg new file mode 100644 index 0000000..642dd8a --- /dev/null +++ b/src/assets/images/provider-favicons/firecrawl.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/src/assets/images/provider-favicons/flyio.svg b/src/assets/images/provider-favicons/flyio.svg new file mode 100644 index 0000000..8db96c4 --- /dev/null +++ b/src/assets/images/provider-favicons/flyio.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/src/assets/images/provider-favicons/gitlab.svg b/src/assets/images/provider-favicons/gitlab.svg new file mode 100644 index 0000000..c43d15d --- /dev/null +++ b/src/assets/images/provider-favicons/gitlab.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/src/assets/images/provider-favicons/heygen.svg b/src/assets/images/provider-favicons/heygen.svg new file mode 100644 index 0000000..fa90865 --- /dev/null +++ b/src/assets/images/provider-favicons/heygen.svg @@ -0,0 +1,202 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/images/provider-favicons/huggingface.svg b/src/assets/images/provider-favicons/huggingface.svg new file mode 100644 index 0000000..8f89935 --- /dev/null +++ b/src/assets/images/provider-favicons/huggingface.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/src/assets/images/provider-favicons/inngest.svg b/src/assets/images/provider-favicons/inngest.svg new file mode 100644 index 0000000..2e6a4c4 --- /dev/null +++ b/src/assets/images/provider-favicons/inngest.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/src/assets/images/provider-favicons/kernel.svg b/src/assets/images/provider-favicons/kernel.svg new file mode 100644 index 0000000..2c8dfe0 --- /dev/null +++ b/src/assets/images/provider-favicons/kernel.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/src/assets/images/provider-favicons/laravelcloud.svg b/src/assets/images/provider-favicons/laravelcloud.svg new file mode 100644 index 0000000..e7b31a3 --- /dev/null +++ b/src/assets/images/provider-favicons/laravelcloud.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/src/assets/images/provider-favicons/metronome.svg b/src/assets/images/provider-favicons/metronome.svg new file mode 100644 index 0000000..b9ff109 --- /dev/null +++ b/src/assets/images/provider-favicons/metronome.svg @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/images/provider-favicons/mixpanel.svg b/src/assets/images/provider-favicons/mixpanel.svg new file mode 100644 index 0000000..cac1ad7 --- /dev/null +++ b/src/assets/images/provider-favicons/mixpanel.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/src/assets/images/provider-favicons/neon.svg b/src/assets/images/provider-favicons/neon.svg new file mode 100644 index 0000000..c1ebcf7 --- /dev/null +++ b/src/assets/images/provider-favicons/neon.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/src/assets/images/provider-favicons/netlify.svg b/src/assets/images/provider-favicons/netlify.svg new file mode 100644 index 0000000..7081fda --- /dev/null +++ b/src/assets/images/provider-favicons/netlify.svg @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/images/provider-favicons/nextjs.svg b/src/assets/images/provider-favicons/nextjs.svg new file mode 100644 index 0000000..eea9d13 --- /dev/null +++ b/src/assets/images/provider-favicons/nextjs.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/images/provider-favicons/openai.svg b/src/assets/images/provider-favicons/openai.svg new file mode 100644 index 0000000..44e3363 --- /dev/null +++ b/src/assets/images/provider-favicons/openai.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/src/assets/images/provider-favicons/openrouter.svg b/src/assets/images/provider-favicons/openrouter.svg new file mode 100644 index 0000000..26bedf7 --- /dev/null +++ b/src/assets/images/provider-favicons/openrouter.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/src/assets/images/provider-favicons/parallel.svg b/src/assets/images/provider-favicons/parallel.svg new file mode 100644 index 0000000..bca1e24 --- /dev/null +++ b/src/assets/images/provider-favicons/parallel.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/src/assets/images/provider-favicons/planetscale.svg b/src/assets/images/provider-favicons/planetscale.svg new file mode 100644 index 0000000..335fd4a --- /dev/null +++ b/src/assets/images/provider-favicons/planetscale.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/src/assets/images/provider-favicons/postalform.svg b/src/assets/images/provider-favicons/postalform.svg new file mode 100644 index 0000000..4031e01 --- /dev/null +++ b/src/assets/images/provider-favicons/postalform.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/src/assets/images/provider-favicons/posthog.svg b/src/assets/images/provider-favicons/posthog.svg new file mode 100644 index 0000000..a583c2a --- /dev/null +++ b/src/assets/images/provider-favicons/posthog.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/src/assets/images/provider-favicons/prisma.svg b/src/assets/images/provider-favicons/prisma.svg new file mode 100644 index 0000000..39c33a3 --- /dev/null +++ b/src/assets/images/provider-favicons/prisma.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/src/assets/images/provider-favicons/privy.svg b/src/assets/images/provider-favicons/privy.svg new file mode 100644 index 0000000..eca8e76 --- /dev/null +++ b/src/assets/images/provider-favicons/privy.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/src/assets/images/provider-favicons/pydantic.svg b/src/assets/images/provider-favicons/pydantic.svg new file mode 100644 index 0000000..4133efa --- /dev/null +++ b/src/assets/images/provider-favicons/pydantic.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/src/assets/images/provider-favicons/railway.svg b/src/assets/images/provider-favicons/railway.svg new file mode 100644 index 0000000..00da966 --- /dev/null +++ b/src/assets/images/provider-favicons/railway.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/src/assets/images/provider-favicons/render.svg b/src/assets/images/provider-favicons/render.svg new file mode 100644 index 0000000..4e3209e --- /dev/null +++ b/src/assets/images/provider-favicons/render.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/src/assets/images/provider-favicons/runloop.svg b/src/assets/images/provider-favicons/runloop.svg new file mode 100644 index 0000000..820bf60 --- /dev/null +++ b/src/assets/images/provider-favicons/runloop.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/src/assets/images/provider-favicons/sentry.svg b/src/assets/images/provider-favicons/sentry.svg new file mode 100644 index 0000000..3f0cef8 --- /dev/null +++ b/src/assets/images/provider-favicons/sentry.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/src/assets/images/provider-favicons/sinch.svg b/src/assets/images/provider-favicons/sinch.svg new file mode 100644 index 0000000..a4f0549 --- /dev/null +++ b/src/assets/images/provider-favicons/sinch.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/src/assets/images/provider-favicons/spaceship.svg b/src/assets/images/provider-favicons/spaceship.svg new file mode 100644 index 0000000..829beb9 --- /dev/null +++ b/src/assets/images/provider-favicons/spaceship.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/src/assets/images/provider-favicons/squarespace.svg b/src/assets/images/provider-favicons/squarespace.svg new file mode 100644 index 0000000..0cb2610 --- /dev/null +++ b/src/assets/images/provider-favicons/squarespace.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/src/assets/images/provider-favicons/stripe.svg b/src/assets/images/provider-favicons/stripe.svg new file mode 100644 index 0000000..312ab30 --- /dev/null +++ b/src/assets/images/provider-favicons/stripe.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/src/assets/images/provider-favicons/supabase.svg b/src/assets/images/provider-favicons/supabase.svg new file mode 100644 index 0000000..eab170e --- /dev/null +++ b/src/assets/images/provider-favicons/supabase.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/images/provider-favicons/supermemory.svg b/src/assets/images/provider-favicons/supermemory.svg new file mode 100644 index 0000000..ace1d80 --- /dev/null +++ b/src/assets/images/provider-favicons/supermemory.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/src/assets/images/provider-favicons/tabstack.svg b/src/assets/images/provider-favicons/tabstack.svg new file mode 100644 index 0000000..990753c --- /dev/null +++ b/src/assets/images/provider-favicons/tabstack.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/src/assets/images/provider-favicons/tailwind.svg b/src/assets/images/provider-favicons/tailwind.svg new file mode 100644 index 0000000..49e72aa --- /dev/null +++ b/src/assets/images/provider-favicons/tailwind.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/src/assets/images/provider-favicons/turso.svg b/src/assets/images/provider-favicons/turso.svg new file mode 100644 index 0000000..db5eae5 --- /dev/null +++ b/src/assets/images/provider-favicons/turso.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/src/assets/images/provider-favicons/twilio.svg b/src/assets/images/provider-favicons/twilio.svg new file mode 100644 index 0000000..79a5a36 --- /dev/null +++ b/src/assets/images/provider-favicons/twilio.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/src/assets/images/provider-favicons/upstash.svg b/src/assets/images/provider-favicons/upstash.svg new file mode 100644 index 0000000..5bcca8b --- /dev/null +++ b/src/assets/images/provider-favicons/upstash.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/src/assets/images/provider-favicons/vercel.svg b/src/assets/images/provider-favicons/vercel.svg new file mode 100644 index 0000000..6d1392f --- /dev/null +++ b/src/assets/images/provider-favicons/vercel.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/src/assets/images/provider-favicons/wix.svg b/src/assets/images/provider-favicons/wix.svg new file mode 100644 index 0000000..5fe7583 --- /dev/null +++ b/src/assets/images/provider-favicons/wix.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/src/assets/images/provider-favicons/wordpress.svg b/src/assets/images/provider-favicons/wordpress.svg new file mode 100644 index 0000000..5adbf19 --- /dev/null +++ b/src/assets/images/provider-favicons/wordpress.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/src/assets/images/provider-favicons/workos.svg b/src/assets/images/provider-favicons/workos.svg new file mode 100644 index 0000000..dd816d7 --- /dev/null +++ b/src/assets/images/provider-favicons/workos.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/src/assets/images/provider-logos/logo-agentmail.svg b/src/assets/images/provider-logos/logo-agentmail.svg new file mode 100644 index 0000000..145a897 --- /dev/null +++ b/src/assets/images/provider-logos/logo-agentmail.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/src/assets/images/provider-logos/logo-agentphone.svg b/src/assets/images/provider-logos/logo-agentphone.svg new file mode 100644 index 0000000..79b1f53 --- /dev/null +++ b/src/assets/images/provider-logos/logo-agentphone.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/src/assets/images/provider-logos/logo-algolia.svg b/src/assets/images/provider-logos/logo-algolia.svg new file mode 100644 index 0000000..533890f --- /dev/null +++ b/src/assets/images/provider-logos/logo-algolia.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/src/assets/images/provider-logos/logo-amplitude.svg b/src/assets/images/provider-logos/logo-amplitude.svg new file mode 100644 index 0000000..896aeb9 --- /dev/null +++ b/src/assets/images/provider-logos/logo-amplitude.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/src/assets/images/provider-logos/logo-auth0.svg b/src/assets/images/provider-logos/logo-auth0.svg new file mode 100644 index 0000000..b3ebe7a --- /dev/null +++ b/src/assets/images/provider-logos/logo-auth0.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/src/assets/images/provider-logos/logo-base44.svg b/src/assets/images/provider-logos/logo-base44.svg new file mode 100644 index 0000000..60f566d --- /dev/null +++ b/src/assets/images/provider-logos/logo-base44.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/assets/images/provider-logos/logo-blaxel.svg b/src/assets/images/provider-logos/logo-blaxel.svg new file mode 100644 index 0000000..d0fcf3d --- /dev/null +++ b/src/assets/images/provider-logos/logo-blaxel.svg @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/images/provider-logos/logo-browserbase.svg b/src/assets/images/provider-logos/logo-browserbase.svg new file mode 100644 index 0000000..a6c7235 --- /dev/null +++ b/src/assets/images/provider-logos/logo-browserbase.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/src/assets/images/provider-logos/logo-chroma.svg b/src/assets/images/provider-logos/logo-chroma.svg new file mode 100644 index 0000000..3873106 --- /dev/null +++ b/src/assets/images/provider-logos/logo-chroma.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/assets/images/provider-logos/logo-clerk.svg b/src/assets/images/provider-logos/logo-clerk.svg new file mode 100644 index 0000000..4215109 --- /dev/null +++ b/src/assets/images/provider-logos/logo-clerk.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/src/assets/images/provider-logos/logo-clickhouse.svg b/src/assets/images/provider-logos/logo-clickhouse.svg new file mode 100644 index 0000000..3cc793e --- /dev/null +++ b/src/assets/images/provider-logos/logo-clickhouse.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/src/assets/images/provider-logos/logo-cloudflare.svg b/src/assets/images/provider-logos/logo-cloudflare.svg new file mode 100644 index 0000000..04a2580 --- /dev/null +++ b/src/assets/images/provider-logos/logo-cloudflare.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/src/assets/images/provider-logos/logo-daytona.svg b/src/assets/images/provider-logos/logo-daytona.svg new file mode 100644 index 0000000..470bace --- /dev/null +++ b/src/assets/images/provider-logos/logo-daytona.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/src/assets/images/provider-logos/logo-e2b.svg b/src/assets/images/provider-logos/logo-e2b.svg new file mode 100644 index 0000000..502ffdd --- /dev/null +++ b/src/assets/images/provider-logos/logo-e2b.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/assets/images/provider-logos/logo-elevenlabs.svg b/src/assets/images/provider-logos/logo-elevenlabs.svg new file mode 100644 index 0000000..5705330 --- /dev/null +++ b/src/assets/images/provider-logos/logo-elevenlabs.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/src/assets/images/provider-logos/logo-exa.svg b/src/assets/images/provider-logos/logo-exa.svg new file mode 100644 index 0000000..f368040 --- /dev/null +++ b/src/assets/images/provider-logos/logo-exa.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/assets/images/provider-logos/logo-firecrawl.svg b/src/assets/images/provider-logos/logo-firecrawl.svg new file mode 100644 index 0000000..eac4f31 --- /dev/null +++ b/src/assets/images/provider-logos/logo-firecrawl.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/src/assets/images/provider-logos/logo-flyio.svg b/src/assets/images/provider-logos/logo-flyio.svg new file mode 100644 index 0000000..3522377 --- /dev/null +++ b/src/assets/images/provider-logos/logo-flyio.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/assets/images/provider-logos/logo-gitlab.svg b/src/assets/images/provider-logos/logo-gitlab.svg new file mode 100644 index 0000000..81510cf --- /dev/null +++ b/src/assets/images/provider-logos/logo-gitlab.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/src/assets/images/provider-logos/logo-heygen.svg b/src/assets/images/provider-logos/logo-heygen.svg new file mode 100644 index 0000000..70cc6e2 --- /dev/null +++ b/src/assets/images/provider-logos/logo-heygen.svg @@ -0,0 +1,207 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/images/provider-logos/logo-huggingface.svg b/src/assets/images/provider-logos/logo-huggingface.svg new file mode 100644 index 0000000..1b9e62d --- /dev/null +++ b/src/assets/images/provider-logos/logo-huggingface.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/src/assets/images/provider-logos/logo-inngest.svg b/src/assets/images/provider-logos/logo-inngest.svg new file mode 100644 index 0000000..ec64cb2 --- /dev/null +++ b/src/assets/images/provider-logos/logo-inngest.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/src/assets/images/provider-logos/logo-kernel.svg b/src/assets/images/provider-logos/logo-kernel.svg new file mode 100644 index 0000000..87af5f3 --- /dev/null +++ b/src/assets/images/provider-logos/logo-kernel.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/src/assets/images/provider-logos/logo-laravelcloud.svg b/src/assets/images/provider-logos/logo-laravelcloud.svg new file mode 100644 index 0000000..5cfe49c --- /dev/null +++ b/src/assets/images/provider-logos/logo-laravelcloud.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/src/assets/images/provider-logos/logo-metronome.svg b/src/assets/images/provider-logos/logo-metronome.svg new file mode 100644 index 0000000..4e5fb6d --- /dev/null +++ b/src/assets/images/provider-logos/logo-metronome.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/src/assets/images/provider-logos/logo-mixpanel.svg b/src/assets/images/provider-logos/logo-mixpanel.svg new file mode 100644 index 0000000..b0c0021 --- /dev/null +++ b/src/assets/images/provider-logos/logo-mixpanel.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/images/provider-logos/logo-neon.svg b/src/assets/images/provider-logos/logo-neon.svg new file mode 100644 index 0000000..c535bf0 --- /dev/null +++ b/src/assets/images/provider-logos/logo-neon.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/assets/images/provider-logos/logo-netlify.svg b/src/assets/images/provider-logos/logo-netlify.svg new file mode 100644 index 0000000..938644e --- /dev/null +++ b/src/assets/images/provider-logos/logo-netlify.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/src/assets/images/provider-logos/logo-openrouter.svg b/src/assets/images/provider-logos/logo-openrouter.svg new file mode 100644 index 0000000..79e6dd0 --- /dev/null +++ b/src/assets/images/provider-logos/logo-openrouter.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/src/assets/images/provider-logos/logo-parallel.svg b/src/assets/images/provider-logos/logo-parallel.svg new file mode 100644 index 0000000..f3cc229 --- /dev/null +++ b/src/assets/images/provider-logos/logo-parallel.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/src/assets/images/provider-logos/logo-planetscale.svg b/src/assets/images/provider-logos/logo-planetscale.svg new file mode 100644 index 0000000..06bdb6e --- /dev/null +++ b/src/assets/images/provider-logos/logo-planetscale.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/src/assets/images/provider-logos/logo-postalform.svg b/src/assets/images/provider-logos/logo-postalform.svg new file mode 100644 index 0000000..3e10ae6 --- /dev/null +++ b/src/assets/images/provider-logos/logo-postalform.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/src/assets/images/provider-logos/logo-posthog.svg b/src/assets/images/provider-logos/logo-posthog.svg new file mode 100644 index 0000000..2c0c8ac --- /dev/null +++ b/src/assets/images/provider-logos/logo-posthog.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/src/assets/images/provider-logos/logo-prisma.svg b/src/assets/images/provider-logos/logo-prisma.svg new file mode 100644 index 0000000..4d5d651 --- /dev/null +++ b/src/assets/images/provider-logos/logo-prisma.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/src/assets/images/provider-logos/logo-privy.svg b/src/assets/images/provider-logos/logo-privy.svg new file mode 100644 index 0000000..291ae82 --- /dev/null +++ b/src/assets/images/provider-logos/logo-privy.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/src/assets/images/provider-logos/logo-railway.svg b/src/assets/images/provider-logos/logo-railway.svg new file mode 100644 index 0000000..63b1342 --- /dev/null +++ b/src/assets/images/provider-logos/logo-railway.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/src/assets/images/provider-logos/logo-render.svg b/src/assets/images/provider-logos/logo-render.svg new file mode 100644 index 0000000..1f51816 --- /dev/null +++ b/src/assets/images/provider-logos/logo-render.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/src/assets/images/provider-logos/logo-runloop.svg b/src/assets/images/provider-logos/logo-runloop.svg new file mode 100644 index 0000000..fcaac26 --- /dev/null +++ b/src/assets/images/provider-logos/logo-runloop.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/src/assets/images/provider-logos/logo-sentry.svg b/src/assets/images/provider-logos/logo-sentry.svg new file mode 100644 index 0000000..361e32b --- /dev/null +++ b/src/assets/images/provider-logos/logo-sentry.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/images/provider-logos/logo-squarespace.svg b/src/assets/images/provider-logos/logo-squarespace.svg new file mode 100644 index 0000000..46f0129 --- /dev/null +++ b/src/assets/images/provider-logos/logo-squarespace.svg @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/images/provider-logos/logo-stripe.svg b/src/assets/images/provider-logos/logo-stripe.svg new file mode 100644 index 0000000..faa4f5b --- /dev/null +++ b/src/assets/images/provider-logos/logo-stripe.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/images/provider-logos/logo-supabase.svg b/src/assets/images/provider-logos/logo-supabase.svg new file mode 100644 index 0000000..a5bba5e --- /dev/null +++ b/src/assets/images/provider-logos/logo-supabase.svg @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/images/provider-logos/logo-supermemory.svg b/src/assets/images/provider-logos/logo-supermemory.svg new file mode 100644 index 0000000..e11d7da --- /dev/null +++ b/src/assets/images/provider-logos/logo-supermemory.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/src/assets/images/provider-logos/logo-turso.svg b/src/assets/images/provider-logos/logo-turso.svg new file mode 100644 index 0000000..68c8fe2 --- /dev/null +++ b/src/assets/images/provider-logos/logo-turso.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/src/assets/images/provider-logos/logo-twilio.svg b/src/assets/images/provider-logos/logo-twilio.svg new file mode 100644 index 0000000..9bad296 --- /dev/null +++ b/src/assets/images/provider-logos/logo-twilio.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/src/assets/images/provider-logos/logo-upstash.svg b/src/assets/images/provider-logos/logo-upstash.svg new file mode 100644 index 0000000..104eae0 --- /dev/null +++ b/src/assets/images/provider-logos/logo-upstash.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/src/assets/images/provider-logos/logo-vercel.svg b/src/assets/images/provider-logos/logo-vercel.svg new file mode 100644 index 0000000..db50a9f --- /dev/null +++ b/src/assets/images/provider-logos/logo-vercel.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/images/provider-logos/logo-wix.svg b/src/assets/images/provider-logos/logo-wix.svg new file mode 100644 index 0000000..d360bcd --- /dev/null +++ b/src/assets/images/provider-logos/logo-wix.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/images/provider-logos/logo-wordpress.svg b/src/assets/images/provider-logos/logo-wordpress.svg new file mode 100644 index 0000000..b0db6f6 --- /dev/null +++ b/src/assets/images/provider-logos/logo-wordpress.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/src/assets/images/provider-logos/logo-workos.svg b/src/assets/images/provider-logos/logo-workos.svg new file mode 100644 index 0000000..43031d9 --- /dev/null +++ b/src/assets/images/provider-logos/logo-workos.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/src/templates-v2.webc b/src/templates-v2.webc new file mode 100644 index 0000000..030d1c2 --- /dev/null +++ b/src/templates-v2.webc @@ -0,0 +1,220 @@ +--- +layout: "main.webc" +title: "Templates V2" +seoTitle: "Stripe Projects: Templates" +ogTitle: "Stripe Projects: Templates" +seoDesc: "Browse Stripe Projects templates and inspect every variant, provider, and build command." +ogDesc: "Browse Stripe Projects templates and inspect every variant, provider, and build command." +ogImage: "/assets/images/og/default.jpg" +ogImageAlt: "" +changefreq: "weekly" +wave: true +--- + +
+ + +
+ + + + +
+
+ + Stripe Projects +
+
+ + +
+
+ +
+ + + + + +
+
+
+
+ + +
+

+ Templates +

+

+ Browse every starter currently published in the public Stripe Projects template registry. Each template page shows its variants, included services, and the exact stripe projects build command to run. +

+
+ + View public registry + + + 13 families + 23 variants +
+
+
+
+ + + +
+ +
    + +
  • + + +
    + +
    + +
    + + + +
    +

    +
    + +
    +

    +
    + +
    +

    +
    +
    + +
    +

    +

    +
    +
    + +

    + +

    +
    + + +
    + +
    + +
    +

    +
    + +
    + +
    + + +
    +
    + +
    + +
    +
      +
    • + +
      +
    • +
    +
    + + View template + + +
    +
    + +
  • +
+
+
+ +
+ +
+ + + + + + \ No newline at end of file diff --git a/src/templates-v3.webc b/src/templates-v3.webc new file mode 100644 index 0000000..79ea151 --- /dev/null +++ b/src/templates-v3.webc @@ -0,0 +1,203 @@ +--- +layout: "main.webc" +title: "Templates V3" +seoTitle: "Stripe Projects: Templates" +ogTitle: "Stripe Projects: Templates" +seoDesc: "Browse Stripe Projects templates and inspect every variant, provider, and build command." +ogDesc: "Browse Stripe Projects templates and inspect every variant, provider, and build command." +ogImage: "/assets/images/og/default.jpg" +ogImageAlt: "" +changefreq: "weekly" +wave: true +--- + +
+ + +
+ + + + +
+
+ + Stripe Projects +
+
+ + +
+
+ +
+ + + + + +
+
+
+
+ + +
+

+ Templates +

+

+ Browse every starter currently published in the public Stripe Projects template registry. Each template page shows its variants, included services, and the exact stripe projects build command to run. +

+
+ + View public registry + + + 13 families + 23 variants +
+
+
+
+ + + +
+ +
    + +
  • + + +
    + +
    + +
    + + + +
    +

    +
    + +
    +

    +
    + +
    +

    +
    + +
    +

    +

    +
    +
    + +
    +
      +
    • + +
      +
    • +
    +
    +
    + +

    + +

    +
    + + +
    + +
    + + View template + + + + View template + + +
    +
    + +
  • +
+
+
+ +
+ +
+ + + + + + \ No newline at end of file From 7d481c3fc189e0be8b483b715202c4a9d77994df Mon Sep 17 00:00:00 2001 From: Mike Stilling Date: Tue, 14 Jul 2026 08:03:05 -0500 Subject: [PATCH 3/7] rm v3 --- src/templates-v3.webc | 203 ------------------------------------------ 1 file changed, 203 deletions(-) delete mode 100644 src/templates-v3.webc diff --git a/src/templates-v3.webc b/src/templates-v3.webc deleted file mode 100644 index 79ea151..0000000 --- a/src/templates-v3.webc +++ /dev/null @@ -1,203 +0,0 @@ ---- -layout: "main.webc" -title: "Templates V3" -seoTitle: "Stripe Projects: Templates" -ogTitle: "Stripe Projects: Templates" -seoDesc: "Browse Stripe Projects templates and inspect every variant, provider, and build command." -ogDesc: "Browse Stripe Projects templates and inspect every variant, provider, and build command." -ogImage: "/assets/images/og/default.jpg" -ogImageAlt: "" -changefreq: "weekly" -wave: true ---- - -
- - -
- - - - -
-
- - Stripe Projects -
-
- - -
-
- -
- - - - - -
-
-
-
- - -
-

- Templates -

-

- Browse every starter currently published in the public Stripe Projects template registry. Each template page shows its variants, included services, and the exact stripe projects build command to run. -

-
- - View public registry - - - 13 families - 23 variants -
-
-
-
- - - -
- -
    - -
  • - - -
    - -
    - -
    - - - -
    -

    -
    - -
    -

    -
    - -
    -

    -
    - -
    -

    -

    -
    -
    - -
    -
      -
    • - -
      -
    • -
    -
    -
    - -

    - -

    -
    - - -
    - -
    - - View template - - - - View template - - -
    -
    - -
  • -
-
-
- -
- -
- - - - - - \ No newline at end of file From f99e09a8ef51751615cadb204f746586622621e4 Mon Sep 17 00:00:00 2001 From: Mike Stilling Date: Tue, 14 Jul 2026 08:50:57 -0500 Subject: [PATCH 4/7] add mobile styles to templates overview page --- .../js/NouveauBloomWave/NouveauBloomWave.js | 67 +++++++++++++++++-- src/templates-v2.webc | 53 ++++++++------- 2 files changed, 89 insertions(+), 31 deletions(-) diff --git a/src/assets/js/NouveauBloomWave/NouveauBloomWave.js b/src/assets/js/NouveauBloomWave/NouveauBloomWave.js index efbb7d9..8edf036 100644 --- a/src/assets/js/NouveauBloomWave/NouveauBloomWave.js +++ b/src/assets/js/NouveauBloomWave/NouveauBloomWave.js @@ -247,6 +247,30 @@ class PostProcessing { } } +const parseResponsiveAttr = (container, baseName) => { + const breakpoints = []; + const baseValue = container.getAttribute(baseName); + if (baseValue !== null) { + breakpoints.push({ minWidth: 0, value: parseFloat(baseValue) }); + } + for (const attr of container.attributes) { + const match = attr.name.match(new RegExp(`^${baseName}-(\\d+)$`)); + if (match) { + breakpoints.push({ minWidth: parseInt(match[1], 10), value: parseFloat(attr.value) }); + } + } + breakpoints.sort((a, b) => a.minWidth - b.minWidth); + return breakpoints; +}; + +const resolveResponsiveValue = (breakpoints, width) => { + let resolved = null; + for (const bp of breakpoints) { + if (width >= bp.minWidth) resolved = bp.value; + } + return resolved; +}; + class NouveauBloomWave { constructor() { this.containers = document.querySelectorAll( @@ -363,13 +387,15 @@ class NouveauBloomWave { waveScene.camera.lookAt(camState.lookat); }; - // Get position from data attributes if provided - const customPositionX = container.dataset.positionX; - const customPositionY = container.dataset.positionY; + // Parse responsive position breakpoints const defaultPositionX = 662.7; const defaultPositionY = -301.7; - const positionX = customPositionX ? parseFloat(customPositionX) : defaultPositionX; - const positionY = customPositionY ? parseFloat(customPositionY) : defaultPositionY; + const posXBreakpoints = parseResponsiveAttr(container, 'data-position-x'); + const posYBreakpoints = parseResponsiveAttr(container, 'data-position-y'); + const positionX = resolveResponsiveValue(posXBreakpoints, window.innerWidth) ?? defaultPositionX; + const positionY = resolveResponsiveValue(posYBreakpoints, window.innerWidth) ?? defaultPositionY; + let lastResolvedPosX = positionX; + let lastResolvedPosY = positionY; // Parse the petal JSON and update positions const petalData = JSON.parse('{"timeOffset":2275,"colorContrast":1,"colorSaturation":1,"colorHueShift":-0.00159265358979299,"displaceFrequencyX":0.005831,"displaceFrequencyZ":0.016001,"displaceAmount":-7.821,"positionX":662.7,"positionY":-301.7,"positionZ":-11.0999999999999,"rotationX":-0.449592653589793,"rotationY":-0.117592653589793,"rotationZ":1.87440734641021,"scaleX":9,"scaleY":8,"scaleZ":5,"twistFrequencyX":-0.649999999999999,"twistFrequencyY":0.41,"twistFrequencyZ":-0.58,"twistPowerX":3.63,"twistPowerY":0.7,"twistPowerZ":3.95,"glowAmount":1.98,"glowPower":0.806,"glowRamp":0.834,"lights":[]}'); @@ -447,6 +473,18 @@ class NouveauBloomWave { waveScene.camera.top = containerSize.height / 2; waveScene.camera.bottom = -containerSize.height / 2; waveScene.camera.updateProjectionMatrix(); + + // Re-evaluate responsive position breakpoints + const newPosX = resolveResponsiveValue(posXBreakpoints, window.innerWidth) ?? defaultPositionX; + const newPosY = resolveResponsiveValue(posYBreakpoints, window.innerWidth) ?? defaultPositionY; + if (newPosX !== lastResolvedPosX) { + lastResolvedPosX = newPosX; + animatePositionX(newPosX); + } + if (newPosY !== lastResolvedPosY) { + lastResolvedPosY = newPosY; + animatePositionY(newPosY); + } }; const keydown = (e) => { @@ -598,9 +636,23 @@ class NouveauBloomWave { renderLoop.start(); }); + const checkResponsivePosition = () => { + const newPosX = resolveResponsiveValue(posXBreakpoints, window.innerWidth) ?? defaultPositionX; + const newPosY = resolveResponsiveValue(posYBreakpoints, window.innerWidth) ?? defaultPositionY; + if (newPosX !== lastResolvedPosX) { + lastResolvedPosX = newPosX; + animatePositionX(newPosX); + } + if (newPosY !== lastResolvedPosY) { + lastResolvedPosY = newPosY; + animatePositionY(newPosY); + } + }; + window.addEventListener("resize", () => { scroll(); resize(); + checkResponsivePosition(); }); // Shared easing function @@ -928,9 +980,11 @@ class NouveauBloomWave { if (container.hasAttribute('data-position-x')) { const posXValue = parseFloat(container.getAttribute('data-position-x')); if (!isNaN(posXValue)) { + lastResolvedPosX = posXValue; animatePositionX(posXValue); } } else { + lastResolvedPosX = originalPositionX; animatePositionX(originalPositionX); } } @@ -939,10 +993,11 @@ class NouveauBloomWave { if (container.hasAttribute('data-position-y')) { const posYValue = parseFloat(container.getAttribute('data-position-y')); if (!isNaN(posYValue)) { + lastResolvedPosY = posYValue; animatePositionY(posYValue); } } else { - // Attribute removed, animate back to default + lastResolvedPosY = originalPositionY; animatePositionY(originalPositionY); } } diff --git a/src/templates-v2.webc b/src/templates-v2.webc index 030d1c2..8e4e763 100644 --- a/src/templates-v2.webc +++ b/src/templates-v2.webc @@ -51,7 +51,8 @@ wave: true data-js-target="nouveau-bloom-wave" class="relative w-full h-full" data-position-x="350" - data-position-y="-250" + data-position-y="-225" + data-position-y-640="-250" data-blur="0" data-camera-zoom="0.85" data-wave-rotation="-75" @@ -62,21 +63,21 @@ wave: true - -
+ +

Templates

- Browse every starter currently published in the public Stripe Projects template registry. Each template page shows its variants, included services, and the exact stripe projects build command to run. + Browse every starter currently published in the public Stripe Projects template registry. Each template page shows its variants, included services, and the exact stripe projects build command to run.

View public registry - 13 families - 23 variants + +
@@ -84,11 +85,11 @@ wave: true -
+
-
    +
      -
    • +
    • @@ -111,26 +112,26 @@ wave: true

      -
      +
      - -
      + +
      -

      +

      -

      +

-
+

@@ -153,22 +154,24 @@ wave: true
-
-
    -
  • + - - View template - - +
    + + View template + + +
@@ -182,8 +185,8 @@ wave: true
-
- +
+

Privacy & Terms From 204f9e7aa9c8d27359260e46b9c40a7f85e31de0 Mon Sep 17 00:00:00 2001 From: Mike Stilling Date: Tue, 14 Jul 2026 08:51:53 -0500 Subject: [PATCH 5/7] fix overflow bug --- src/templates-v2.webc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/templates-v2.webc b/src/templates-v2.webc index 8e4e763..3d8d4b4 100644 --- a/src/templates-v2.webc +++ b/src/templates-v2.webc @@ -155,7 +155,7 @@ wave: true
@@ -116,22 +114,17 @@ wave: true

- -
-

+

-

+

-
+

@@ -141,7 +134,7 @@ wave: true
-