Commit Graph

170 Commits

Author SHA1 Message Date
Mobeen Abdullah
7d2858e74b feat(website): add Supported Models link to nav and footer (#13432)
## Summary

Surface the supported-models catalog (`/p/supported-models`) from the
home page by adding a "Supported Models" link to the Products dropdown
and the footer.

## Changes

- **What**: Add a `nav.supportedModels` i18n entry (en `Supported
Models`, zh-CN `支持的模型`) and link it to the existing `routes.models`
constant in two places: the Products mega-menu Features column (between
Launches and Docs) and the footer Products column (after Comfy MCP).
Locale handling comes from `getRoutes`, so zh-CN resolves to
`/zh-CN/p/supported-models` automatically.

## Review Focus

- Placement is intentionally in **both** the nav and the footer (per
FE-1190). Fine to drop either, happy to adjust after review.
- Reuses the existing nav/footer link pattern, no new components or
styles, and no `new` badge (the page is not newly launched).
- Consumes `routes.models`, which was already defined but previously
unused.

FE-1190

## Screenshots

**Nav — Products dropdown, Features column**

_Desktop:_

_Mobile:_

**Footer — Products column**

_Desktop:_

_Mobile:_

Preview: https://comfy-website-preview-pr-13432.vercel.app
2026-07-04 09:33:26 +05:00
imick-io
156f2f59b7 feat(website): swap nav featured card to Comfy MCP (#13388)
## Summary

Repurpose the Products dropdown featured card to promote Comfy MCP.

## Changes

- **What**: Update the nav featured card title ("NEW: COMFY MCP"), alt
text, image asset (`mcp-card.webp`), and CTA ("GET STARTED") in
`mainNavigation.ts`; route the CTA to the localized `/mcp` page via
`routes.mcp`. All copy is i18n'd (en + zh-CN) in `translations.ts`,
adding a reusable `cta.getStarted` key.

## Review Focus

- CTA uses a new reusable `cta.getStarted` key rather than the
section-scoped `mcp.setup.label`, and routes to the internal
`routes.mcp` so non-en locales resolve to `/{locale}/mcp`.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-03 05:01:55 +00:00
nav-tej
d855466fdf fix(website): cap contact intro text width and space it from the form (#13420)
*PR Created by the Glary-Bot Agent*

---

## Summary

On `comfy.org/contact` the intro copy ("Create powerful workflows, scale
without limits." + description) ran right up against the HubSpot form
fields on desktop. The two `lg:w-1/2` columns had no gap between them
and the left column had no max-width, so long description text extended
almost to the form's edge.

- Add `lg:gap-16` between the two columns in `FormSection.vue`, matching
the pattern already used by `common/ContentSection.vue` and
`legal/LegalContentSection.vue`.
- Wrap the intro text block (badge + heading + description) in an
`lg:max-w-xl` container so the copy no longer stretches into the gap.
The illustration below keeps its full-column bleed via the existing
`lg:-ml-20`.
- Mobile (`<lg`) layout is unchanged — all new classes are
`lg:`-prefixed.

## Verification

Screenshots taken via Playwright against the local `apps/website` dev
server:

- Desktop (1512×900) — intro text now caps at a comfortable line length
with a clear gap to the form.
- 1024px — still works at the `lg:` breakpoint.
- 375px mobile — visually identical to before.

Also ran `pnpm format` and `pnpm --filter @comfyorg/website typecheck`
(0 errors). Three pre-existing
`better-tailwindcss/enforce-consistent-class-order` lint warnings on
this file exist on `main` and were left untouched.

- Fixes contact-page layout complaint from #website-and-docs (July 2)

## Screenshots

![Contact page after fix at 1512px — intro text capped with clear gap to
form](https://pub-1fd11710d4c8405b948c9edc4287a3f2.r2.dev/sessions/5f8bf9cb18d1cd3fea28126c5aa832b0c655c1ecef2398b16fa50d81520df3fd/pr-images/1783049233475-b5932d36-9087-4689-a7ea-925bad2f09ff.png)

![Contact page after fix at 1024px
viewport](https://pub-1fd11710d4c8405b948c9edc4287a3f2.r2.dev/sessions/5f8bf9cb18d1cd3fea28126c5aa832b0c655c1ecef2398b16fa50d81520df3fd/pr-images/1783049234208-8ef2cdac-b929-4c4d-b60a-e794f989fd76.png)

![Contact page after fix at 375px mobile viewport — layout
unchanged](https://pub-1fd11710d4c8405b948c9edc4287a3f2.r2.dev/sessions/5f8bf9cb18d1cd3fea28126c5aa832b0c655c1ecef2398b16fa50d81520df3fd/pr-images/1783049234909-c502d978-2586-4ce7-b54a-d96fc759d306.png)

Co-authored-by: Glary-Bot <glary-bot@users.noreply.github.com>
2026-07-03 03:51:31 +00:00
Mobeen Abdullah
4cc0402325 revert(website): remove Creative Campus customer stories (#13370) (#13407)
## Summary

Reverts #13370 (the five Creative Campus customer stories) from `main`.
These are education-tied stories, and the "Education Program is live"
CTA links to the education page, which is not live yet, so they should
not be public before the education launch.

This is a clean `git revert` of the squash commit `49a90d4e2` (no
history rewrite, no force-push). No work is lost: the story branch
(`feat/website-customer-stories-education`) is intact, and the stories
will relaunch together with pricing and the education page via #13406.

## Changes

- **What**: Reverts the 5 new story MDX files, the new article block
components, and the related changes to `CustomerArticle.astro`,
`global.css`, `Figure`/`Quote`/`Contributors`, the content test, and the
e2e spec. The existing five stories and the customers pages are
unaffected.
- **Breaking**: none.

## Review Focus

- Pure inverse of #13370; the diff is `-858/+11` mirroring the original
merge.
- Files touched by #13370 are disjoint from the education-page work in
#13406, so this does not conflict with that branch.

## Verification

- Build: 497 pages (down 5 en story pages). Unit: 156/156. Typecheck: 0
errors. format:check and knip clean.

## Next steps

- Stories move into the education bundle (#13406) via a separate PR.
- When the education page and its auth (FE-1174) are ready, pricing +
customer stories + education launch together.
2026-07-03 01:49:47 +05:00
Mobeen Abdullah
49a90d4e2e feat(website): add five Creative Campus customer stories (#13370)
## Summary

Add the five new Comfy Education Initiative (Creative Campus) customer
stories to `/customers`, each with its own detail page, reusing the
existing Astro content-collection pattern. Brings the listing to ten
stories. Linear: FE-1161.

## Changes

- **What**: Five new English MDX stories (Xindi Zhang, Ina Conradi,
Golan Levin, Kathy Smith, and the UAL CCI partnership) added to the
customers collection, ordered after the existing five. Adds a small set
of reusable article blocks these stories need: `Embed` (Vimeo), `Video`
(wraps the existing `VideoPlayer`), `Download` (workflow JSON),
`AuthorBio`, `EducationCta`, `AtAGlance`, a styled inline `Link`, and
`Heading4`. `Quote`'s `name` is now optional for unattributed
pull-quotes; `Figure` gained an optional rich-caption slot (for captions
that contain links); `AuthorBio` supports a single-author bio via slot.
- **Breaking**: none. All additions are backward compatible; the
existing five stories and their pages are untouched.
- **Dependencies**: none.

## Review Focus

- The logic to review is small and isolated: the new block components in
`components/customers/content/` and their registration in
`CustomerArticle.astro`. The rest of the diff is MDX content.
- **Story copy is transcribed verbatim from the source docs**;
punctuation (em/en dashes, curly quotes) is preserved as written and is
intentional, not a formatting slip.
- **Downloads (cross-origin):** the workflow JSON files are on
media.comfy.org, so the HTML `download` attribute is ignored by
browsers. The real download is forced server-side with
`Content-Disposition: attachment` on the storage objects. Xindi's two
workflow files are served from a cache-fresh `.../workflows/` path (with
an explicit `filename=`) so the CDN serves the attachment header
immediately.
- **Embed hardening:** the Vimeo `Embed` iframe carries
`referrerpolicy="strict-origin-when-cross-origin"` and a scoped
`sandbox` (`allow-scripts allow-same-origin allow-presentation
allow-popups`); the player was verified to still load and play.
- All media (card covers, inline images, one video with a poster frame,
workflow JSON/PNG downloads) is hosted on media.comfy.org. No local
assets are committed. Golan's workflow files are re-hosted there; his
lesson-plan and demo-project links intentionally stay on GitHub/p5.js as
view-only.
- English-first: Chinese versions will be added later through a separate
translation service. The listing and detail pages already handle a
locale that only has English entries, so no page-code changes were
needed.
- Tags: "Creative Campus Showcase" for the four teaching stories, and
"Creative Campus Partnership" for the UAL announcement.

## Verification

- Unit `176/176`, typecheck (astro check) `0 errors`, build `502 pages`,
`format:check`, `knip`, and `eslint` all pass.
- e2e customer specs `6/6` pass (includes a new test asserting the
Creative Campus education blocks render).
- Visual pass on all ten stories at desktop (1440) and mobile (390): no
horizontal overflow, the Vimeo player plays, and all downloads resolve
to media.comfy.org.

## Screenshots (if applicable)

Easiest way to review is the Vercel preview:
https://comfy-website-preview-pr-13370.vercel.app/customers then open
the five new stories. Verified on desktop (1440) and mobile (390).
2026-07-03 00:34:20 +05:00
imick-io
a6db1ab3d6 fix(website): restore node-link.svg intrinsic sizing (#13384)
## Summary

Restore the original `node-link.svg` asset, which PR #13095 accidentally
overwrote with a stretch-to-fill Figma export, breaking the node
connector across the marketing site.

## Changes

- **What**: Revert `apps/website/public/icons/node-link.svg` to its
intrinsic **20×32** form (`fill="#F2FF59"`). PR #13283 had replaced it
with a raw Figma export (`preserveAspectRatio="none"`, `width="100%"
height="100%"`, `fill="var(--fill-0, …)"`). Every consumer loads it as a
bare `<img src>` and relies on the intrinsic size plus
`scale-*`/`rotate` classes — with no intrinsic dimensions the connector
expanded to fill its container and distorted.

## Review Focus

- The overwrite originated in the first commit of #13283's stack and
rode through the squash merge; nothing in that PR actually referenced
this file (the MCP page uses the separate `NodeUnionIcon.vue`), so
restoring the shared asset fixes all consumers (`BuildWhatSection`,
`ProductShowcaseSection`, `OurValuesSection`, `GalleryDetailModal`)
without touching the MCP page.
- `apps/website/dist/icons/node-link.svg` is stale build output and
regenerates on the next `pnpm build`.

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: github-actions <github-actions@github.com>
2026-07-02 13:07:00 +00:00
Mobeen Abdullah
9cf5c9a93f refactor(website): tidy customer story review nits (#13324)
## Summary

Small follow-up to #13289 applying two non-blocking review nits from
Alex's review.

## Changes

- **What**: drop the redundant `before:content-['']` on the
customer-story list bullet (Tailwind emits the empty `content`
automatically once another `before:` utility is present), and rename
`HEADER_OFFSET` to `HEADER_OFFSET_PX` in `ArticleNav` so the scroll
constants use consistent unit suffixes.

## Review Focus

Both changes are cosmetic with no behavior change. Confirmed in the
browser that the list bullet still renders identically (6px yellow dot)
without the explicit `content` utility.

## Notes from the #13289 review (left as-is here, open to discussion)

Three other comments from the review are intentionally not changed in
this PR; reasoning below so the decisions are on record:

- **`Category` type in `ArticleNav`**: kept the `ComponentProps<typeof
CategoryNav>` derivation. AGENTS.md says to derive component types via
`vue-component-type-helpers` rather than redefining them, so the current
form follows the styleguide. Happy to switch to a plain named type if
preferred.
- **Section ids in frontmatter vs the body `<Section>`**: kept the
`customers.content.test.ts` parity test. The short TOC labels live only
in frontmatter and Astro can't introspect the rendered MDX body to build
the nav, so the frontmatter `sections` list and the body anchor ids
can't be trivially deduplicated. A real fix would need a remark plugin
(larger, separate change). The test guards against silent drift in the
meantime.
- **`nextStory` throw**: left as a fail-loud, build-time invariant. The
slug always comes from the same `getStaticPaths` collection, so the
throw is effectively unreachable; it surfaces a future-refactor bug
loudly instead of linking to the wrong story.
2026-07-01 12:45:24 +00:00
Mobeen Abdullah
01738b7b19 feat(website): move customer stories to Astro content collections (#13289)
## Summary

Move the five customer stories on `/customers` out of the old
`customerStories.ts` array and the shared i18n file into an Astro
content collection (MDX, English and Chinese). The pages look and read
exactly the same; this just changes where the content lives so it is
easier to edit, and it sets the pattern we will reuse to migrate the
rest of the marketing content.

Linear: FE-1158

## Changes

- **What**:
- Added a `customers` content collection (`src/content.config.ts` +
`src/content/customers.schema.ts`), with one MDX file per story per
locale under `src/content/customers/{en,zh-CN}/`.
- Rebuilt the article rendering as small static components (`Section`,
`Figure`, `Quote`, `Contributors`, `Steps`, plus styled
paragraph/heading/list). The article body is now static HTML; only the
scroll-spy sidebar (`ArticleNav.vue`) ships JavaScript.
- Repointed the `/customers` listing and detail pages (both locales) to
read from the collection.
- Removed the old `customerStories.ts` array and the customer-story keys
from `translations.ts` (about 1,300 lines).
- Dropped the two "Read more" links that just redirected back to the
same page; kept the two that point to the real Substack articles.
- Switched the "Read more" button to the design-system `Button`, which
also fixes its vertical alignment.
- Added a short pattern doc at `apps/website/src/content/README.md` for
reuse.
- **Dependencies**: `@astrojs/mdx` (renders the MDX content).

## Review Focus

This is meant to be a no-visual-change migration. I checked content and
layout against the live site for all five stories in both languages, on
desktop and mobile. The only intended differences are the two removed
self-referential "Read more" links and the read-more button now using
the shared `Button`.

A few small setup changes explain part of the diff:

- `src/env.d.ts` now references `.astro/types.d.ts` so the collection
types resolve (this is the repo's first content collection).
- `astro.config.ts` sets `markdown.smartypants: false` so quotes stay
straight (MDX would otherwise curl them). This option is deprecated in
Astro 7 and moves onto the markdown processor; that belongs with the
eventual Astro 7 upgrade, not here.
- ESLint ignores the `astro:` virtual modules for `apps/website` files
(they are real at build time, but the resolver cannot see them).
- Content MDX is excluded from `oxfmt` in `.oxfmtrc.json`: the formatter
rewraps component slots and changes the rendered output (it broke the
blockquotes), so content files are kept out of it like generated files
and fixtures.
- `components/common/ContentSection.vue` and `config/contentSections.ts`
are untouched; they still power the legal and privacy pages.

The diff is large, but most of it is MDX content, the lockfile, and the
removed i18n keys. The logic to review is small: the collection config
and schema, the components, and the page wiring.

## Screenshots

No visual change is intended, so before and after of the article pages
are identical (verified across both locales and on desktop and mobile).
The one deliberate tweak is the "Read more" button, which now uses the
design-system `Button` for better vertical alignment. Before/after
captures are available if needed.
2026-06-30 21:43:54 +00:00
Christian Byrne
da34fa3944 docs(website): update ToS payment terms for Free Tier overages (#13315)
*PR Created by the Glary-Bot Agent*

---

Updates two sections on https://comfy.org/terms-of-service per legal
copy provided in [the website-and-docs Slack
thread](https://comfy-org.slack.com/archives/C098QHJ8YDR/p1782775899132369).

## Changes

Edits `apps/website/src/i18n/translations.ts` (the source of truth for
the ToS page rendered by
`apps/website/src/pages/terms-of-service.astro`):

- **`tos.payment.block.1` — Plans; Fees; Free Tier.** Adds language
clarifying that a Free Tier user who provides a payment method expressly
authorizes Comfy to charge it for overages (intentional use, third-party
use, or technical factors), and that approach-to-cap notifications are
best-effort, not a precondition to charging.
- **`tos.payment.block.3` — Self-Serve Credit Card Billing.** Clarifies
that the billing authorization applies to paid Plan and Free Tier
overages alike, and that retry rights for failed charges extend to Free
Tier overage charges.

`en` and `zh-CN` values are kept in sync per the existing convention for
these keys (the `/zh-CN/terms-of-service` page is a redirect to the
English page).

## Open question for legal / requester

`tos.effectiveDate` is currently `May 13, 2026` and was **not** bumped
in this PR — the original request did not mention it. If legal wants
this revision to carry a new effective date, that should be a follow-up
commit on this branch before merge.

## Verification

- `pnpm typecheck` (apps/website): 0 errors, 0 warnings.
- `pnpm build` (apps/website): 497 pages built; the rendered
`/terms-of-service` HTML contains both new sentences.
- `pnpm exec eslint` / `oxfmt --check` on the changed file: clean.
- Husky pre-commit (`lint-staged` + `check-unused-i18n-keys`): clean.
- Manual: served the built `dist/` via local HTTP and verified the
rendered Payment section in a real browser (screenshot below).

## Screenshots

![Rendered /terms-of-service Payment section showing the updated Plans;
Fees; Free Tier and Self-Serve Credit Card Billing
copy](https://pub-1fd11710d4c8405b948c9edc4287a3f2.r2.dev/sessions/3d085431f019603d3250f274fdae4f9186eaaecbdaee4cbc6b924e2b84854661/pr-images/1782796953351-4deec91c-ac02-4bc5-b8cd-cd0a3413613e.png)

Co-authored-by: Glary-Bot <glary-bot@users.noreply.github.com>
2026-06-30 05:29:13 +00:00
nav-tej
61cb1bcde0 fix(website): point launches Comfy MCP CTA to /mcp (#13287)
*PR Created by the Glary-Bot Agent*

---

## Summary

Update the `EXPLORE` CTA on the Comfy MCP card on
[/launches](https://comfy.org/launches) to link to
[/mcp](https://comfy.org/mcp) instead of the docs
(`docs.comfy.org/agent-tools/cloud`).

## Change

Single line in `apps/website/src/data/drops.ts`:

```diff
     cta: {
       label: EXPLORE,
-      href: { en: externalLinks.docsMcp, 'zh-CN': externalLinks.docsMcp }
+      href: { en: '/mcp', 'zh-CN': '/zh-CN/mcp' }
     }
```

Matches the locale-aware pattern used by sibling cards (`/download` /
`/zh-CN/download`, `/api` / `/zh-CN/api`). Both `src/pages/mcp.astro`
and `src/pages/zh-CN/mcp.astro` already exist, so neither link is dead.
The `externalLinks.docsMcp` constant is retained because the MCP page
itself still uses it.

## Verification

- `pnpm typecheck` / `pnpm typecheck:website` clean.
- `oxfmt`, `oxlint`, `eslint` clean (all ran via lint-staged on commit).
- Manually loaded `/launches` and `/zh-CN/launches` in the dev server
and confirmed the Comfy MCP card now points to `/mcp` and `/zh-CN/mcp`
respectively.
- Loaded `/mcp` and confirmed the destination page renders ("Comfy MCP —
Drive ComfyUI from any AI agent").
- Code review by Oracle: no issues.

Screenshot shows the updated MCP card on /launches.

## Screenshots

![Comfy MCP card on /launches with EXPLORE button now linking to
/mcp](https://pub-1fd11710d4c8405b948c9edc4287a3f2.r2.dev/sessions/9f315ccc2692129159ae31efab9464684ff2f6db3e144feae6dd52fd314c0b47/pr-images/1782765166237-5e83667b-8dc3-4182-9891-609385a1dae5.png)

Co-authored-by: Glary-Bot <glary-bot@users.noreply.github.com>
2026-06-29 22:29:38 +00:00
imick-io
fb3350ee0e feat(website): redesign Comfy MCP setup steps and add button variant (#13285)
## Summary

Reworks the Comfy MCP page's **"Set up Comfy MCP in three steps"**
section to match the new design, and adds a per-action button `variant`
option to `FeatureGrid01`.

The three steps are now:

| Step | Title | Action |
| --- | --- | --- |
| 1 | Copy the MCP URL | Copy field showing
`https://cloud.comfy.org/mcp` |
| 2 | Add the connector | Filled button **"COMFY CLOUD MCP DOCS" ↗** →
MCP docs |
| 3 | Connect and sign in | Filled button **"COMFY CLOUD SKILLS" ↗** →
comfy-skills repo |

## Changes

- **`FeatureGrid01.vue`** — add `variant?: 'default' | 'outline'` to the
link card action; button now uses `card.action.variant ?? 'outline'`
instead of a hardcoded outline, so callers can opt into the filled
style.
- **`config/routes.ts`** — add `mcpSkills` external link
(`https://github.com/Comfy-Org/comfy-skills`).
- **`i18n/translations.ts`** — refresh the `mcp.setup.*` copy (en +
zh-CN): new subtitle, reworded steps, new `step2.cta` / `step3.cta`,
drop the now-unused `step1.cta`.
- **`SetupSection.vue`** — re-map cards: step 1 → copy field, steps 2 &
3 → filled link buttons.

## Test plan

- [x] `pnpm typecheck` — 0 errors
- [x] Pre-commit hooks (stylelint, oxfmt, oxlint, eslint, typecheck)
pass
- [ ] Visual check on `/mcp` and `/zh-CN/mcp` (copy field on step 1; two
filled yellow CTAs with up-right arrows on steps 2 & 3)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-29 19:08:03 +00:00
imick-io
be8e0010ee feat(website): rebuild Comfy MCP page on the design system (+ zh-CN) (#13283)
Rebuilds the **Comfy MCP** marketing page on the website design-system
stack and adds the missing zh-CN page.

## What's here
- Replaces the bespoke `components/product/mcp/` section silo with thin
`templates/mcp/*` wrappers over reusable `blocks/` + `common/`
components.
- Adds `src/pages/zh-CN/mcp.astro` and threads `locale` through every
section (was English-only).
- New/extended design-system blocks:
- `FeatureGrid01` — setup steps, with a reusable `ui/CopyableField`
(uses `@vueuse/core` `useClipboard`).
- `FeatureGrid02` — how-it-works steps with `NodeUnionIcon` connectors +
a CTA pair via `ui/button`.
- `FeatureRows01` — alternating media rows; `ReasonsSplit01` — "why"
list.
- `HeroSplit01` gained `subtitle`, a `media` slot, and a `class`
passthrough; `SectionHeader` gained `align`.
- Standardized block section spacing on `px-6 py-16 lg:py-24`.
- Refreshed all 8 MCP FAQ answers (en + zh-CN) and hydrated the FAQ
section so the accordion is interactive.

## Notes
- Stacked on the original MCP landing-page commits (previously PR
#13095); those ride along here.
- `typecheck` and `build` are green; `/mcp` and `/zh-CN/mcp` both render
in both locales.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Balpreet Brar <balpreet.brar@growthnatives.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: github-actions <github-actions@github.com>
Co-authored-by: Alexander Brown <drjkl@comfy.org>
2026-06-29 10:04:24 -07:00
imick-io
d0e97d6933 fix(website): move launches nav item and add cleanplate workflow link (#13282)
## Summary
- Move the `/launches` nav item from **Company → More** to **Products →
Features** in the main navbar
- Add the workflow link to the **Cleanplate Walkthrough** learning
tutorial (`https://comfy.org/workflows/8f2cf0df5da6-8f2cf0df5da6/`)

## Changes
- `apps/website/src/data/mainNavigation.ts`
- `apps/website/src/data/learningTutorials.ts`

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-29 16:24:10 +00:00
Christian Byrne
4a2393be48 chore: drop unnecessary exports on file-local types to satisfy knip (#13204)
Current `main` **fails a fresh `knip` run** with 13 unused exported
types (exit 1). They're invisible on main because lint/knip only runs on
`pull_request`/`merge_group`, never on push to main — so merge skew (one
PR adds an export used by file X; a later PR removes X's usage)
accumulates latent failures that ambush backport branches (e.g. #13163,
#13162).

Each of the 13 is `export`ed but referenced only within its own file
(verified 0 importers; ≥2 in-file uses, so not dead code). Fix: drop the
redundant `export`.

Types cleaned: `VideoSource`, `ObjectInfoResponse`,
`PromotedMissingModelWorkflow`, `PixelReadout`, `ResizeDirection`,
`ResizeHandle`, `RunButtonTelemetryOptions`, `ResolvedModelNode`,
`AccountPreconditionContext`, `SubscriptionDialogOptions`,
`MonthlyCreditsUsage`, `MissingMediaReference`, `ResolvedHostWidget`.

Reviewer note: `ResolvedHostWidget` and `ResolvedModelNode` sit under
`renderer/extensions`/`platform/assets`; no in-repo importers, but if
either is intended as published/extension-facing API, prefer a knip
`entry`/`ignore` over un-exporting — flag in review and I'll adjust.

After fresh `knip`: **0 unused exported types**.

Supersedes #13179 (fixed only `AccountPreconditionContext`). Pairs with
the push-gate workflow #13203 — merge this first so that gate is green
on main.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-27 03:01:59 +00:00
balpreetgrowthnatives
e2c670bbc3 fix: prevent payment routes from being indexed (#12706)
## Summary

Allow crawler access to `/payment/` routes in robots.txt so search
engines can read the `noindex` tag, and forcefully inject the
`x-robots-tag: noindex` header via `vercel.json`.

## Changes

- **What**: Removed `Disallow: /payment/` from `robots.txt` and added
rules to `vercel.json` applying `x-robots-tag: noindex` to
`/payment/(.*)` and `/zh-CN/payment/(.*)` routes.

## Review Focus

- The configurations in `vercel.json` apply to both English and
localized payment routes (`/zh-CN/payment/(.*)`).

---------

Co-authored-by: nav-tej <36310614+nav-tej@users.noreply.github.com>
Co-authored-by: Christian Byrne <cbyrne@comfy.org>
2026-06-26 15:11:12 -07:00
imick-io
7d3d8ce63f feat(website): add /drops landing page (livestream hero + drops grid) (#13053)
## Summary

Adds the `/drops` landing page in English and Simplified Chinese, ahead
of the 2026-06-24 livestream. The page is composed of a livestream-gated
hero, a 10-card drops grid, a subscribe banner, and a closing CTA.
Production media for the hero and several cards is wired in; the rest
fall back to placeholders.

## Changes

- **New `/drops` page** (`pages/drops.astro`, `pages/zh-CN/drops.astro`)
plus en/zh-CN translations.
- **`HeroLivestream01` block** — renders the rotating-logo video before
the stream window, swaps to a YouTube nocookie iframe between
`startDateTime` and `endDateTime`. SSR stays deterministic on the logo
and only flips to the embed after client hydration. Takes
`youtubeVideoId` directly (no URL parsing).
- **Drops grid** — `data/drops.ts` defines the 10 cards with `imageFor`
/ `videoFor` media helpers, badges, and per-locale
title/description/href. `DropCard.vue` renders an image or autoplaying
muted video inside the new `Card` primitive set (`Card`, `CardHeader`,
`CardTitle`, `CardDescription`, `CardContent`, `CardFooter`).
- **Supporting blocks** — `SubscribeBanner` uses the Button `link`
variant with an animated hover underline; closing `CtaCenter01` is
extended with a terms link. `resolveRel` is shared from `utils/cta.ts`
instead of duplicated per block.
- **Visual extension to `HeroLivestream01.visual`** — discriminated
`image | video` union so the hero can render a looping video.
- **E2E** — `e2e/drops.spec.ts` covers both locales (hero + grid render,
locale-correct links).

## Review Focus

- `youtubeVideoId` is currently a `nlLZfNIqF8M` placeholder;
`startDateTime`/`endDateTime` are placeholders too — see TODO in
`HeroSection.vue`. These need to be swapped to the production stream +
window before launch.
- Several drop cards still point at placeholder destinations (e.g. Comfy
MCP at `/mcp`) — TODO noted in `drops.ts`.
- Drop card media is a mix of images and short MP4s served from
`media.comfy.org`. The videos autoplay muted/looped with
`preload="metadata"`.

## Test plan

- [ ] `pnpm --filter website dev` → visit `/drops` and `/zh-CN/drops`;
confirm hero video plays, grid renders all 10 cards, video cards loop,
subscribe banner link styled correctly
- [ ] Temporarily set `startDateTime` to the past and `endDateTime` to
the future; confirm hero swaps to the YouTube iframe after hydration
- [ ] `pnpm --filter website test:e2e drops.spec.ts`
- [ ] `pnpm typecheck:website`

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-26 19:09:04 +00:00
Benjamin Lu
da55529d23 GTM-93 point Windows download at comfy.org proxy (#12974)
## Summary

- Point the website Windows desktop download URL at
`https://comfy.org/download/windows/nsis/x64`.
- Keep macOS on the existing ToDesktop URL.
- Update the download page smoke test to expect the new Windows href.

## Context

This is the frontend leg of the GTM-93 Windows MVP. ToDesktop still
controls `download.comfy.org`; instead of changing DNS, the website
sends Windows users to a controlled `comfy.org` proxy path that the
router PR handles. The proxy forwards to ToDesktop and adds a tokenized
`Content-Disposition` filename for Desktop to consume on Windows.

Linear:
https://linear.app/comfyorg/issue/GTM-93/fix-posthog-identify-call-unblock-funnel-attribution-desktop-funnel
Router PR: https://github.com/Comfy-Org/comfy-router/pull/33
Desktop PR: https://github.com/Comfy-Org/Comfy-Desktop/pull/1149

## Validation

- `pnpm --filter @comfyorg/website run typecheck`
- `pnpm --filter @comfyorg/website run build`
- `pnpm --filter @comfyorg/website exec playwright test
e2e/download.spec.ts`
- pre-commit: `pnpm typecheck`, `pnpm typecheck:website`
2026-06-24 17:29:53 -07:00
Dante
49a7b7b558 feat(billing): UnifiedPricingTable — one table, personal/team plan toggle (B4 / FE-934) (#12666)
## What
**B4 (FE-934): `UnifiedPricingTable`** — one pricing table for the
**Jun-5 model** (typeless workspace; personal/team is a **plan**, shown
as a Gamma-style **plan toggle** on one workspace), per **DES-197**. A
new, flag-gated component that will replace the two legacy tables at
cutover (strangler).


### video 

https://github.com/user-attachments/assets/82b704a4-101e-4609-8ff5-06b7cf7f9cd7



> **Stacked on #12644 (FE-935 `CreditSlider`).** Base is the slider
branch — retarget to `main` once #12644 merges. The slider commits show
in the diff until then.

## Changes
- **`UnifiedPricingTable.vue`** — plan toggle (personal/team, flag-gated
on `teamWorkspacesEnabled`); personal tier cards (facade `plans` +
`TIER_PRICING` fallback, billing-cycle toggle); team column hosting
`<CreditSlider>`; Enterprise card. Reuses `useBillingContext`; emits
`subscribe`/`resubscribe` (personal) + `subscribeTeam` (team).
- **`SubscriptionRequiredDialogContentUnified.vue`** — host; wires
personal checkout through `useSubscriptionCheckout` (full flow incl.
preview/transition + **new `'success'` step**); team checkout stubbed.
- **Confirm/success screens (DES 3084-15873)** — aligned the reused
`SubscriptionAddPaymentPreviewWorkspace` /
`SubscriptionTransitionPreviewWorkspace` to DES-197 (drop `/member`,
`comfy--credits` icon, plan-specific CTAs **"Subscribe to {plan}" /
"Switch to {plan}"**); added **`SubscriptionSuccessWorkspace.vue`**
("You're all set") as the `'success'` checkout step.
- **`showPricingTable`** — renders the unified host when
`teamWorkspacesEnabled`, legacy `PricingTable.vue` for flag-off. (The
old workspace-variant fork is removed; `PricingTableWorkspace.vue`
becomes unused on flag-on → deleted at cutover.)
- **i18n** — `subscription.planScope` / `teamPlan` / `enterprise` +
`subscription.preview.{subscribeToPlan,switchToPlan}` +
`subscription.success.*` keys.

## Strategy (new component + cutover — per FE-934)
Build new, retire old at cutover (a later single PR deletes
`PricingTable.vue` + `PricingTableWorkspace.vue` + the legacy dialog
host + the dispatch fork; `TIER_PRICING` kept only as the flag-off/OSS
fallback). Avoids half-migrated conditional cruft in the live tables.

## Screenshots
Pricing captured live on the authenticated cloud-prod session
(`local.comfy.org`, flag on). Confirm/success captured in Storybook
(prop-driven) — a **personal** workspace can't reach these live until
**B1/FE-966** flips its billing path off the legacy `/customers/*`
adapter (whose `plans` is always empty); the screens themselves are
unchanged regardless of source.

**Pricing table**

| Personal | Team |
|---|---|
| <img width="420" alt="pricing-personal"
src="https://github.com/user-attachments/assets/2be3b8bc-ac54-41db-8c21-5c950d3e7338"
/> | <img width="420" alt="pricing-team"
src="https://github.com/user-attachments/assets/c4078eb4-ee7d-42f6-bcc3-375686ab7f1e"
/> |

**Confirm your payment / plan change**

| New subscription | Plan change (Pro → Creator) |
|---|---|
| <img width="380" alt="confirm-new-subscription"
src="https://github.com/user-attachments/assets/e371c744-dc64-43e8-b977-73f9f99f85bc"
/> | <img width="380" alt="confirm-plan-change"
src="https://github.com/user-attachments/assets/b1ee5ab3-c572-4c40-9b70-f078d66b78f4"
/> |

**You're all set (success)**

<img width="380" alt="success-all-set"
src="https://github.com/user-attachments/assets/8ec9e90f-8ba4-4cb0-81a7-6b4316e0c19e"
/>

## ⚠️ BE-blocked (deferred)
- **Team checkout**: the slider stop → plan-slug / subscribe-request
shape is undefined (doc **Open Q#2** / "Team-slider contract",
**BE-1254**). `subscribeTeam` is stubbed (toast "coming soon") until BE
provides it.
- **Live discount data**: stops come from the hardcoded **DES-197
fallback** (`teamPlanCreditStops.ts`) until `GET /api/billing/plans`
carries them.
- **Confirm "credits you'll get right away" line** + **async-success
routing** (Stripe-tab/`pending_payment` → in-dialog success) deferred —
see ticket notes; credits-cents unit is the open BE-1254 question.

## Verification
- `vue-tsc --noEmit`: clean (pre-commit).
- `oxlint`/`eslint`/`stylelint`/`oxfmt`: pass (pre-commit).
- `vitest` `useSubscriptionDialog.test.ts` (11) +
`useSubscriptionCheckout.test.ts` (17) + new
`SubscriptionSuccessWorkspace.test.ts` (2): pass.
- Personal checkout reuses the existing `useSubscriptionCheckout` flow;
subscribed → new `'success'` step.

## Not in scope
- Pixel-finalizing vs DES-197 (visual reference = Alex's
**reference-only** #12042); personal-card detail refinement.
- Settings / Misc-UX (FE-768/770); team-checkout wiring (BE contract).

Design: **DES-197** / **3084-15873**. Survey: *FE Billing API
Divergence* (B4 / P1 / P2 / P4).

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: GitHub Action <action@github.com>
2026-06-23 10:11:13 +00:00
imick-io
fc4d44c3db [feat] migrate website navbar to shadcn-vue + mobile sheet drill-down (#12861)
## Summary
- Migrate the website's top nav from bespoke components (`SiteNav`,
`MobileMenu`, `NavDesktopLink`, `PillButton`, `MaskRevealButton`) to
shadcn-vue primitives (`NavigationMenu`, `Sheet`, `Button`), split into
`HeaderMain` → `HeaderMainDesktop` + `HeaderMainMobile`.
- Mobile nav becomes a `Sheet` with drill-down sub-navigation, scroll
lock, sticky CTAs, sr-only i18n title/description, and a back-to-home
logo.
- Desktop nav uses `NavigationMenu` with shared viewport, featured
cards, `NavColumn` extraction, and centralized nav data in
`data/mainNavigation.ts`.
- Adds i18n strings for nav labels, dropdown column headers, close/back
affordances, and the mobile menu description.

## Test plan
- [ ] Desktop: hover PRODUCTS / COMMUNITY / COMPANY — dropdowns open
with featured card + columns, NEW badges render, external links show the
arrow-up-right icon, viewport is shared between triggers.
- [ ] Mobile (<lg): open hamburger sheet — verify logo + close, body
scroll is locked while open, top-level nav scrolls if it overflows, CTAs
stay pinned at bottom.
- [ ] Tap COMMUNITY / PRODUCTS / COMPANY — sub-panel slides over root
nav, in-sheet BACK returns to root, links navigate correctly.
- [ ] Reload `?locale=zh-CN`: dropdown labels, sheet title/description,
BACK / close affordances all localized.
- [ ] No regressions on `/cloud`, `/cloud/pricing`, `/customers`, etc. —
pages that swap CTAs (`BrandButton` → shadcn `Button`) still render at
every breakpoint.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: GitHub Action <action@github.com>
Co-authored-by: github-actions <github-actions@github.com>
Co-authored-by: Alexander Brown <drjkl@comfy.org>
2026-06-19 01:55:02 +00:00
imick-io
003303d8ac feat(website): pricing API copy + tutorial video captions (#12929)
## Summary

- **Pricing copy** — replace "concurrent API jobs" wording with
"workflows via API" on Creator/Pro plans, add a third feature line to
Standard, and add a new "Run Workflows via API" entry to the "What's
Included" section (existing feature11 → feature12).
- **Tutorial captions** — wire per-locale VTT caption tracks into
`TutorialDetailDialog`, so the CC button in `VideoPlayer` is now
functional for the learning tutorials. `LearningTutorial.caption` is
typed as `readonly VideoTrack[]`; `VideoTrack` is now exported from
`VideoPlayer.vue`.
- Tailwind class ordering in `PriceSection.vue` shifted due to the
formatter on touched lines.

## Test plan

- [ ] `/pricing` page (EN + zh-CN): Standard plan shows the new "1
workflow via API" line; Creator/Pro show "3/5 workflows via API";
"What's Included" lists "Run Workflows via API" above "Parallel job
execution".
- [ ] Open a learning tutorial → CC button is visible in the player →
toggling CC shows English captions in sync with playback.
- [ ] Tutorials without a `caption` entry hide the CC button.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: github-actions <github-actions@github.com>
2026-06-18 20:51:40 +00:00
Deep Mehta
ccf2f12b25 fix(website): correct top-up credit rollover copy on cloud pricing (#12923)
## Summary

The `/cloud/pricing` page's "Add more credits anytime" feature claims
unused top-up credits **roll over** to the next month. Per product
(Pablo, #cloud), top-up credits **do not** roll over. Fix the copy to
match policy and the docs.

## Changes

- **What**: `pricing.included.feature5.description` (en + zh-CN) in
`apps/website/src/i18n/translations.ts`.
- Before: "Purchase additional credits at any time. Unused top-ups roll
over to the next month automatically for up to 1 year."
- After: "Purchase additional credits at any time. Top-up credits are
valid for 1 year from the date of purchase and do not roll over with
your monthly plan."
- Keeps the accurate 1-year validity window (matches
`docs/interface/credits.mdx`).
- Scope: this is the **only** rollover claim on the page. The tier cards
(lines 1224/1255/1286) only say "top-ups available" — no change needed.
- **Breaking**: none (copy only).

## Deliberately out of scope

The Slack thread surfaced an **unresolved** question: Pablo said top-ups
don't roll over *"as opposed to subscription credits which do,"* but
`docs/interface/credits.mdx` says monthly credits don't roll over
either. This PR makes **no claim about subscription/monthly credit
rollover** (the new copy is neutral: "do not roll over *with your
monthly plan*"). Resolving that — and the optional FAQ entry / docs
alignment Glary-Bot proposed — needs a product decision first. Flagging
for follow-up.
2026-06-17 18:38:56 +00:00
AustinMroz
eaa6776559 Fix broken e2e test (#12818) 2026-06-12 18:08:47 +00:00
Benjamin Lu
fefbe7843c refactor(website): dedupe download label and add shared Platform type (#12776)
## Summary

Cleanup of the website download button: deduplicate the label lookup in
`DownloadLocalButton.vue`, and export a `Platform` domain type from
`useDownloadUrl` so the button spec, icon map, and analytics all consume
it instead of loose `string`s.

## Changes

- **What**:
- Hoist `t('download.hero.downloadLocal', locale)` into a single `label`
computed, reused by the fallback aria-labels and the button text
(previously evaluated in two places)
- Export `Platform` (`'windows' | 'mac'`) from `useDownloadUrl`;
`ButtonSpec.key`, the `ICONS` map (`Record<Platform, string>`), and
`captureDownloadClick` now consume it — adding a platform without an
icon becomes a compile error, and typo'd platform names can't reach
PostHog
- Drop the redundant `aria-hidden="true"` on the icon (`alt=""` already
marks it decorative)

## Review Focus

`ppformula-text-center` on the icon is intentionally kept — it is
positional (`position: relative; top: 0.19em`), not typographic, and
keeps the icon aligned with the optically-shifted PP Formula text.

No behavior change.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-06-11 16:20:14 +00:00
imick-io
6445690ed3 fix(website): rebrand "Comfy Local" to "Comfy Desktop" (#12794)
## Summary

- Rebrand "Comfy Local" → "Comfy Desktop" across all user-facing copy on
`apps/website`. The nav already showed "Comfy Desktop"; this pulls the
rest of the site in line.
- Updates the homepage product card, the `/cloud` page FAQ + pricing
copy, the `/download` page SEO title/keywords, and matching Storybook
stories. Both `en` and `zh-CN`.
- Internal identifiers left untouched (i18n key names, the
`src/components/product/local/` folder, the `Product = 'local' | …` type
discriminator, and the `media.comfy.org/website/local/*` CDN paths).

## Test plan

- [ ] `pnpm --filter @comfyorg/website dev` and visually verify:
- [ ] `/` — product card section reads "Comfy Desktop" / "SEE DESKTOP
FEATURES"
- [ ] `/cloud` (en + zh-CN) — every FAQ "Local" reference now reads
"Comfy Desktop"
  - [ ] `/download` — page `<title>` and meta keywords show new values
- [ ] Nav + footer still read "Comfy Desktop" / "DOWNLOAD DESKTOP"
(unchanged)
- [ ] `pnpm --filter @comfyorg/website test:e2e -- navigation.spec.ts`
passes
- [ ] Storybook: `Website/Common/ProductCard` and
`Website/Common/FooterLinkColumn` render with new labels
- [ ] Regenerate any screenshot baselines that snapshot the homepage
product cards or the `/cloud` FAQ section

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: github-actions <github-actions@github.com>
2026-06-11 16:15:19 +00:00
Deep Mehta
79acf7be5e fix: re-encode favicon.ico with PNG frames to fix white corner artifacts (#12753)
## Summary

The rebranded `favicon.ico` renders with **opaque white corners** in
browsers — the rounded mark shows white slivers around its corners on
any background. This is a decode bug, not a design issue: the ICO
contains **BMP-format frames** whose alpha channel Chrome (and other
consumers) mishandle. Verified by loading the raw `.ico` in headless
Chrome on a dark page: corners render white instead of transparent.

Every surface that consumes the `.ico` directly shows the artifact —
Google search results, connector icon scraping, raw image views — while
browser tabs look fine because they prefer the SVG favicon.

## Changes

- **What**: Re-encode `apps/website/public/favicon.ico` and
`public/assets/favicon.ico` with **PNG-format ICO frames** (16/32/48).
PNG frames carry unambiguous alpha and decode correctly in all modern
browsers.
- **No design change**: identical rounded artwork, same transparency,
same sizes and filenames. SVG, PNGs, apple-touch-icon, and manifest
icons are untouched.
- **Breaking**: none.

## Review Focus

- Headless-Chrome verified: the old ico renders white corners on a dark
page; the re-encoded one renders transparent corners. (Comparison in PR
comments.)
- PNG-in-ICO is supported by all modern browsers and Google's favicon
pipeline.
- After merge, please add `needs-backport` + `cloud/1.45` so
cloud.comfy.org's copy gets the same fix.

## Screenshots (if applicable)

---------

Co-authored-by: GitHub Action <action@github.com>
2026-06-11 03:27:53 +00:00
Robin Huang
9617e498c9 feat: track desktop download button clicks on website (#12770)
Adds a `website:download_button_clicked` PostHog event (with `platform`
property) fired when a user clicks the desktop installer download button
on comfy.org. Previously we only had `/download` pageviews as a proxy —
autocapture is not active on the website project, so these clicks were
untracked. Includes unit tests for the new capture helper.

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-06-10 20:44:57 +00:00
imick-io
ed4f7db7f4 feat(website): add affiliate program page at /affiliates (#12670)
## Summary

- Adds the Comfy affiliate program landing page at `/affiliates`,
composed from 8 reusable presentational blocks (`HeroSplit01`,
`ChecklistSplit01`, `StepsGrid01`, `BenefitsGrid01`, `DetailsTable01`,
`BrandAssetsGrid01`, `FAQSplit01`, `CtaCenter01`) and thin section
wrappers under `templates/affiliate/*`. The page funnels through: Hero →
Audience → How It Works → Why ComfyUI → Program Details → Brand Assets →
FAQ → closing "Ready to start earning?" CTA.
- Removes the older parallel implementation under
`components/affiliates/*` (7 Vue sections, 3 data files, the i18n
contract test) and the `affiliate-landing.*` translation keys — the page
now has a single canonical i18n surface under `affiliate.*`.
- Rewrites `e2e/affiliates.spec.ts` to target the new sections via
semantic queries (no testids were added to production), covering hero
indexability, the closing CTA's apply + terms links, FAQPage JSON-LD
entry count, and FAQ toggle behavior.
- Apply CTA links to the application form
(`forms.gle/RS8L2ttcuGap4Q1v6`, `target=_blank`); terms link goes to
`/affiliates/terms` (English-only by design, per the legal-reviewed
terms document).

## Test plan

- [ ] `pnpm --filter @comfyorg/website typecheck` passes (0 errors)
- [ ] `pnpm --filter @comfyorg/website test:unit` passes (96 tests
across 13 files)
- [ ] `pnpm --filter @comfyorg/website knip --cache` reports no new
orphans introduced by this branch
- [ ] Visit `/affiliates` — all 8 sections render in order on desktop
and mobile
- [ ] APPLY NOW (in closing CTA section) opens
`forms.gle/RS8L2ttcuGap4Q1v6` in a new tab
- [ ] "Read the affiliate program terms" link navigates to
`/affiliates/terms` in the same tab
- [ ] FAQ items expand/collapse on click; `<script
type="application/ld+json">` FAQPage entry contains all 8 Q/A pairs from
`src/data/affiliateFaq.ts`
- [ ] Run e2e: `pnpm --filter @comfyorg/website playwright test
e2e/affiliates.spec.ts`

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: GitHub Action <action@github.com>
2026-06-09 20:34:43 +00:00
imick-io
39157f2375 Feat/models page (#12429)
## Summary

Add a new `/models` landing page (EN + zh-CN) for the marketing site,
plus supporting tweaks: a generator-side mechanism for old→new
model-slug 301 redirects, spacing/CTA polish on shared sections, and a
per-item layout option on GalleryCard.

## Changes

- **What**:
- New `/models` and `/zh-CN/models` pages composed of a hero (autoplay
video, modelName + i18n CTA), a creations gallery, and the shared
`AIModelsSection`.
- New `ModelsHeroSection.vue` and `ModelCreationsSection.vue`
components; localised strings under `models.list.*` / `models.hero.*` in
`translations.ts`.
- Reused `AIModelsSection` on the models page (replaces the duplicated
showcase markup that previously lived under `models/`) so the same
component now powers both the cloud product page and the models page.
- `generate-models.ts`: renamed the `grok` provider to **Grok Imagine**
(`grok-imagine` slug) and added a `LEGACY_SLUG_REDIRECTS` constant that
emits stub entries so the existing `canonicalSlug` mechanism in
`[slug].astro` issues a 301 from old slugs (`grok-image` →
`grok-imagine`).
- `model-metadata.ts`: renamed the metadata key from `grok-image` to
`grok-imagine` (hub slug unchanged).
- `GalleryCard.vue`: added per-item `objectFit` / `objectPosition`
overrides so individual gallery entries can opt out of the default
`cover` crop.
- `ModelsHeroSection.vue`: dropped the empty-string default on
`videoAriaLabel` and omit `aria-label` (with `aria-hidden="true"`) when
no label is provided — addresses the CodeRabbit accessibility note.
- Minor vertical-spacing tightening on `ModelCreationsSection` and the
shared `AIModelsSection`.
- **Breaking**: None. Old `/p/supported-models/grok-image` URLs 301 to
the new slug.
- **Dependencies**: None.

## Review Focus

- The `LEGACY_SLUG_REDIRECTS` constant in
`apps/website/scripts/generate-models.ts` is the new source of truth for
renamed slugs — future slug renames should follow the same pattern so
the redirect survives regeneration of `generated-models.json`.
- The shared `AIModelsSection` is now used in two places; confirm the
spacing tweak (`py-24 → py-16`, `mt-24 → mt-16 lg:mt-24`) still looks
correct on the cloud product page.
- `generated-models.json` is fully regenerated by `pnpm generate:models`
— diff size is large but mechanical.

## Screenshots (if applicable)

<!-- Add screenshots or video recording to help explain your changes -->

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: Alexander Brown <drjkl@comfy.org>
2026-06-09 20:14:03 +00:00
Deep Mehta
68238a5742 fix(website): show Windows + Mac fallback on /download when UA detection fails (#12727)
## What
The /download hero now surfaces both Windows AND macOS download buttons
when the post-mount UA sniff comes back empty (Linux desktop, mobile,
privacy-stripped UAs). Today those users see only the GitHub-install
button — no actual download link.

## Why
Field complaint: \"I can't find a download link at all on this page.\"
Reproduced on Chrome with a Linux UA — \`useDownloadUrl\` returns
\`platform: null\`, and \`<DownloadLocalButton v-show=\"platform\">\`
collapses to \`display: none\`. The user only sees \"INSTALL FROM
GITHUB\" next to it, with no obvious way to grab the Windows or Mac dmg.

Showing both is the better fallback — they're the two artifacts we
actually ship today (\`downloadUrls.windows\`, \`downloadUrls.macArm\`),
the UA path already encodes them, and the buttons exist as fragment
siblings so they slot into the parent's flex container next to the
existing GitHub button without extra layout wrapping.

## How
- \`useDownloadUrl\` now exposes a \`detected\` ref that flips to
\`true\` post-mount regardless of whether UA matched. Lets the component
distinguish three states:
- **\`!detected\`** → pre-hydration, render nothing (avoids SSR flicker)
  - **\`detected && platform\`** → single matched CTA, current behaviour
  - **\`detected && !platform\`** → NEW: render both Windows AND Mac
- \`DownloadLocalButton\` adds the fallback branch as a \`<template
v-else-if>\` fragment so the two buttons slot directly into the parent's
existing \`flex-col lg:flex-row\` layout next to the GitHub button. Each
carries its OS icon and an \`aria-label\` combining the existing
\"DOWNLOAD DESKTOP\" copy with the OS name so screen readers get equal
context to the detected-OS path.
- \`downloadUrls\` is now re-exported from the composable so the
fallback path uses the same source of truth instead of duplicating the
URLs.

## Tests
- [x] New \`@smoke\` e2e test (\`HeroSection falls back to both Windows
+ Mac when UA is unrecognized\`) — uses Linux UA, asserts both fallback
buttons appear with the right hrefs / target=\"_blank\", and confirms
the auto-detected single CTA is NOT also present
- [x] Existing Windows-UA test (\`HeroSection has download and GitHub
buttons\`) still passes — single CTA branch unchanged
- [ ] Manual: load /download on Linux Chrome → both buttons visible
- [ ] Manual: load /download on Windows → still single \"DOWNLOAD
DESKTOP\" button (no regression)
- [ ] Manual: load /download on macOS → still single \"DOWNLOAD
DESKTOP\" button with Apple icon
- [ ] Manual: load /download on mobile (which detection treats as null)
→ both fallback buttons visible
2026-06-09 05:50:48 +00:00
Deep Mehta
fa2d187c83 feat(website): add Desktop privacy policy at /privacy/desktop (#12714)
## Summary

Publishes the Comfy Desktop privacy policy (currently bundled in-app
only) as a public page at \`/privacy/desktop\`, so users can read what
they consented to without re-opening the app and so the document is
verifiable / link-shareable. Also adds a single-sentence link from the
existing \`/privacy-policy\` page so people who land on the org-wide
policy can find the surface-specific one.

## Changes

- **What**: New marketing-site page at \`/privacy/desktop\` (en) and
\`/zh-CN/privacy/desktop\` (zh), backed by ~50 new \`desktop_privacy.*\`
i18n keys mirroring the in-app document. One-sentence addition to
\`privacy.intro.block.3\` linking to the new page.
- **Breaking**: None.
- **Dependencies**: None.

## Why now

Recent Discord audit by a user (cited Civitai as precedent) identified
six legitimate gaps between our website privacy policy and what GDPR /
UK GDPR Art 13 requires (named processors, lawful basis mapping,
retention specifics, international transfer mechanism, etc.). The
**in-app Desktop policy already addresses all of them**, but it isn't
publicly visible. This PR makes it visible at a URL.

A separate, counsel-reviewed PR will be needed to bring the org-wide
\`/privacy-policy\` page up to the same standard — that's deliberately
not in scope here.

## Content the new page covers

Mirrors the Desktop in-app document (effective 2026-05-19):

- Named processors: PostHog, Datadog, ToDesktop, Comfy Org analytics
warehouse
- Article 6 mapping: 6(1)(a) consent for analytics + crash reports;
6(1)(f) legitimate interests for update server
- Retention: 24 months analytics / 15 days crash / 36 months aggregate /
90 days update logs / removed on uninstall
- International transfers: Standard Contractual Clauses where required
- Data subject rights + \`privacy@comfy.org\` as contact
- Right to lodge complaint with ICO / EU supervisory authority / CPPA

## Review Focus

1. **i18n zh-CN placeholders.** Following the existing convention in
this file (see e.g. \`affiliate-landing.footerCta\`), zh-CN values use
the English text as placeholders. A follow-up PR will land Chinese
translations. Flag if there's a different preferred convention.
2. **Source-of-truth coupling.** This page is a publish of the bundled
in-app policy at \`src/renderer/src/lib/legalDocs.ts\`
(\`PRIVACY_POLICY\` constant) in the \`Comfy-Desktop\` repo. There's no
automated sync — the two need to stay aligned manually when the in-app
policy is revised. Worth a quarterly review reminder.
3. **\`privacy@comfy.org\` mailbox.** The policy directs all data
subject rights requests there. Confirm this inbox exists and is
monitored before merge.
4. **No \`noindex\` on the new page.** Unlike the existing
\`/privacy-policy\` page, this one is intentionally indexable — the
point is that it should be discoverable.

## Test plan

- [x] \`pnpm typecheck\` clean (0 errors, 0 warnings)
- [x] \`pnpm build\` succeeds; both \`/privacy/desktop/index.html\` and
\`/zh-CN/privacy/desktop/index.html\` are emitted
- [x] All 385 site pages still build
- [ ] After preview deploy: verify the link from \`/privacy-policy\` to
\`/privacy/desktop\` renders correctly, and the page table-of-contents
nav works (\`ContentSection\` infers sections from i18n keys)

## Companion items (not in this PR)

- Update \`comfy.org/privacy-policy\` (the org-wide policy) with named
processors, Art 6 mapping, retention specifics, and SCC language —
requires privacy counsel review
- Confirm Comfy Org Inc ICO registration status
- One-page determination from privacy counsel on whether Art 37 requires
a formal DPO (pseudonymous product telemetry is likely below threshold,
but the question deserves a documented answer)
2026-06-08 23:22:43 +00:00
bertfy
6f22ca11c3 feat(website): rename "Local" CTAs/branding to "Desktop" (#12689)
*PR Created by the Glary-Bot Agent*

---

## Summary

Renames the user-facing "Local" copy to "Desktop" across the comfy.org
marketing site (English + Chinese). Covers three surfaces requested in
sequence by the user:

1. "Download Local" CTA → "Download Desktop" (top nav, mobile menu,
homepage Get-started section, download page hero button).
2. "Comfy Local" nav-dropdown / footer label → "Comfy Desktop".
3. The yellow `LOCAL` badge in the `/download` hero → `DESKTOP`.

## Changes

- **i18n** (`apps/website/src/i18n/translations.ts`)
- `getStarted.step1.downloadLocal`, `download.hero.downloadLocal`,
`nav.downloadLocal`: en `Local` → `Desktop`, zh-CN `本地版` → `桌面版`.
- `nav.comfyLocal`: en `Comfy Local` → `Comfy Desktop`, zh-CN `Comfy
本地版` → `Comfy 桌面版`.
- **Nav animated CTA** (`SiteNav.vue`): hardcoded `core: 'LOCAL'` →
`core: 'DESKTOP'` (the visible text in the desktop nav, which is
separate from the i18n aria-label).
- **Download hero badge** (`product/local/HeroSection.vue`): passes
`text="DESKTOP"` to `<ProductHeroBadge />`, matching how the
Cloud/API/Enterprise heroes already specify their own text.
- **Shared badge default** (`common/ProductHeroBadge.vue`): default
`text` changed from `'LOCAL'` to `'DESKTOP'` so future callers do not
inherit retired branding.
- **E2E tests** updated to the new strings (navigation, homepage,
download specs).

## Out of scope (intentionally unchanged)

- The internal product-family slug `local` (Vue component file names
like `DownloadLocalButton.vue`, directory `components/product/local/`,
translation key `comfyLocal`, route `/download`). Renaming these is
internal restructuring that would balloon the diff with no user-visible
benefit and was not requested.
- The homepage products-card strings `products.local.title` ("Comfy
Local") and `products.local.cta` ("SEE LOCAL FEATURES"). These also live
on the homepage and link to `/download`; the user has been driving this
rename surface-by-surface and has not flagged this card yet. Happy to
extend in a follow-up if desired.
- Other "local" occurrences (e.g. "本地运行" in the zh-CN download FAQ, "Run
on your hardware", etc.) — those describe the deployment model, not the
product brand.

## Verification

- `pnpm --filter @comfyorg/website typecheck`: 0 errors
- `pnpm exec oxlint` on every touched file: 0 errors, 0 warnings
- `pnpm exec oxfmt --check` on every touched file: clean
- Husky `lint-staged` (typecheck + lint + format) ran green on each
commit
- Manual browser verification with Playwright at desktop (1440×900) and
mobile (390×844) viewports on `/`, `/download`, `/zh-CN/`,
`/zh-CN/download`:
  - Top nav CTA reads `DOWNLOAD DESKTOP` (aria-label `下载桌面版` on zh-CN)
  - Mobile menu CTA reads `DOWNLOAD DESKTOP`
  - Homepage Get-started section reads `Download Desktop`
  - Products dropdown shows `Comfy Desktop` as the first item
  - `/download` hero badge reads `Comfy DESKTOP` (en + zh-CN)
- DOM `innerText` contains 0 occurrences of `LOCAL`/`下载本地版`/`Comfy 本地版`

## Screenshots

Attached: desktop nav, homepage Get-started section, download hero badge
(en + zh-CN), mobile menu.

## Screenshots

![Desktop nav showing DOWNLOAD DESKTOP
CTA](https://pub-1fd11710d4c8405b948c9edc4287a3f2.r2.dev/sessions/8df93ff9df744afaf52af9f712468ec540611a127894815633c8d1b902dcb0cb/pr-images/1780875107228-7f86d778-c1fd-4eff-89eb-857c64760bf2.png)

![Homepage Get started section showing Download Desktop
link](https://pub-1fd11710d4c8405b948c9edc4287a3f2.r2.dev/sessions/8df93ff9df744afaf52af9f712468ec540611a127894815633c8d1b902dcb0cb/pr-images/1780875107536-4e7a8d15-57d7-4a97-b3dc-414f86c09e71.png)

![Download page hero with Comfy DESKTOP yellow
badge](https://pub-1fd11710d4c8405b948c9edc4287a3f2.r2.dev/sessions/8df93ff9df744afaf52af9f712468ec540611a127894815633c8d1b902dcb0cb/pr-images/1780875107833-b80a479e-18a5-45c7-92b9-a41dcd82741f.png)

![zh-CN download page hero with Comfy DESKTOP
badge](https://pub-1fd11710d4c8405b948c9edc4287a3f2.r2.dev/sessions/8df93ff9df744afaf52af9f712468ec540611a127894815633c8d1b902dcb0cb/pr-images/1780875108144-028f680d-f949-4960-9424-8c8096023222.png)

![Mobile menu showing DOWNLOAD DESKTOP
CTA](https://pub-1fd11710d4c8405b948c9edc4287a3f2.r2.dev/sessions/8df93ff9df744afaf52af9f712468ec540611a127894815633c8d1b902dcb0cb/pr-images/1780875108481-e4a586ba-1b65-4077-b02c-517252f92255.png)

---------

Co-authored-by: Glary-Bot <glary-bot@users.noreply.github.com>
Co-authored-by: github-actions <github-actions@github.com>
Co-authored-by: Michael B <michael@imick.io>
2026-06-08 20:23:11 +00:00
imick-io
5ddf5faef3 feat: scaffold Learning page with Featured Workflow, Tutorials, and CTA sections (#12602)
## Summary

Adds a new Learning page to the website with a hero, featured workflow
showcase, tutorials section, and CTA, wired into site nav and footer
Resources.

## Changes

- **What**:
- New `/learning` page (Astro) with `HeroSection`,
`FeaturedWorkflowSection`, `TutorialsSection`, and `CallToActionSection`
  - Localized for `zh-CN` at `/zh-CN/learning`
  - Featured workflow CTA links out to `comfy.org/workflows/<slug>`
- Added `nav.learning` translation; added Learning entry to `SiteNav`
and `SiteFooter` Resources
- New shared `PillButton`, `MaskRevealButton`, `Badge`, and
`VideoPlayer` work used by the page; `TutorialDetailDialog` for tutorial
deep-dives
  - Featured demo video updated; poster image added
  - `routes.ts`: added `learning` route entry
  - `EventsSection` temporarily hidden pending content

## Review Focus

- Copy on `learning.featured.description` (newly written, both `en` and
`zh-CN`)
- Tutorial data shape in `data/learningTutorials*.ts`
- Internal-vs-external link styling: Learning shows the active-page
yellow when viewing `/learning` (expected — internal route, no external
arrow)

## Screenshots (if applicable)

_Add deployment preview screenshots here._

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: Alexander Brown <drjkl@comfy.org>
2026-06-05 18:11:14 +00:00
nav-tej
ddf9308cd8 feat(website): add Affiliate Program link to footer Resources (#12600)
*PR Created by the Glary-Bot Agent*

---

Adds an **Affiliate Program** entry under the Resources column of the
site footer, positioned immediately after the YouTube link. Links to
`/affiliates` via the existing locale-invariant `routes.affiliates`
helper.

### Stacked on #12002

This PR is branched off `glary/affiliates-landing-page` (PR #12002), not
`main`, because:

- `routes.affiliates` and the `/affiliates` page itself are added by
#12002 and aren't on `main` yet.
- Linking to `/affiliates` from the footer before #12002 merges would
404 in production.

GitHub will auto-rebase this PR onto `main` once #12002 merges.
**Re-target this PR's base from `glary/affiliates-landing-page` to
`main` before reviewing for merge** (or simply merge #12002 first and
GitHub will switch the base for you).

### Diff

```
apps/website/src/components/common/SiteFooter.vue  +4
apps/website/src/i18n/translations.ts              +4
```

- New `footer.affiliateProgram` i18n key. English-only per the go-live
direction for affiliate-related copy (zh-CN mirrors EN to satisfy the
dictionary's `Record<Locale, string>` shape; matches how `nav.youtube`
and other proper-noun footer entries handle this).
- New `FooterLink` entry in `topColumns[1].links` (the Resources
column), after the YouTube entry. Internal route, so no `external:
true`.

### Local verification

- `pnpm typecheck`: 0 errors
- `pnpm build`: 380 pages, footer renders `Affiliate Program` →
`/affiliates` in both desktop and mobile layouts, on `/`, `/about`,
`/zh-CN/`, etc. Link ordering in Resources: `Blog → Discord → GitHub →
Docs → YouTube → Affiliate Program` (verified by parsing the built HTML)
- `pnpm test:unit`: passing (no SiteFooter unit test exists; it's
exercised through e2e/visual coverage)
- `pnpm lint`: no new warnings (3 pre-existing on unrelated files)
- `pnpm format:check`: clean
- `pnpm knip`: clean
- `pnpm exec tsx scripts/check-unused-i18n-keys.ts`: clean (new key is
used)

### Out of scope

- No new Linear ticket (this is a follow-up to the affiliate-program
go-live work tracked under FE-704).
- Header nav / mobile menu changes — only the footer was requested.

Co-authored-by: Glary-Bot <glary-bot@users.noreply.github.com>
2026-06-02 22:47:02 +00:00
nav-tej
f4088bcc63 feat(website): draft Affiliate Program landing page at /affiliates (#12002)
*PR Created by the Glary-Bot Agent*

---

Conversion-oriented English landing page that drives applications to the
Comfy Affiliate Program Google Form. Shipped behind `noindex` while copy
and assets are finalized — a follow-up PR will flip it indexable and add
the zh-CN locale.

Mirrors the type scale, brand tokens, and noindex/sitemap/robots
conventions from the [/affiliates/terms PR
(#11954)](https://github.com/Comfy-Org/ComfyUI_frontend/pull/11954) so
the two pages feel like a set. The footer's "Read the affiliate program
terms" link points at `/affiliates/terms`, which lands with #11954.

## What's in the box

Sections (in render order): hero → trust band → how-it-works →
who-we're-looking-for → program details → brand assets → FAQ → footer
CTA.

- **i18n** — Copy lives under `affiliate-landing.*` in
`src/i18n/translations.ts` (en only; zh-CN values mirror en until a
localized version lands, so non-engineers can edit copy without touching
components).
- **Component reuse audit** — Reuses `common/FAQSection`,
`common/BrandButton`, `common/SectionHeader`, `common/SectionLabel`
verbatim. Sections without a clean primitive fit (split hero, trust
band, 3-step flow, audience list, details table, brand-asset grid,
footer CTA) render inline with brand tokens rather than forking new
shared components.
- **Brand assets** — Wired via a config object in
`components/affiliates/brandAssets.ts` so 728×90 / 300×250 / 160×600 /
1200×628 banners can be dropped in later without code changes. Live
tiles for `/icons/logo.svg` and `/icons/logomark.svg`; placeholder
"Coming soon" tiles for the four banner sizes.
- **CTA** — `Apply Now` → `https://forms.gle/RS8L2ttcuGap4Q1v6`, opens
in new tab with `target="_blank"` and `rel="noopener noreferrer"`. Hero
and footer-CTA both use it.
- **Hero media slot** — Wired as a named slot (`<slot name="media">`)
with a static node-graph SVG fallback, so a video can be dropped in
later via the page without component changes.
- **FAQ structured data** — Page emits `schema.org/FAQPage` JSON-LD so
it's ready for SEO when `noindex` flips off.
- **noindex** — `<meta name="robots" content="noindex, nofollow">` via
`BaseLayout.noindex`. `/affiliates` added to `NOINDEX_PATHNAMES` in
`astro.config.ts` (excluded from sitemap for both en and zh-CN locale
prefixes via the existing `LOCALE_PREFIXES.flatMap` pattern) and to
`robots.txt Disallow` under every UA block including the explicit AI-bot
overrides (GPTBot, ClaudeBot, OAI-SearchBot, ChatGPT-User, Claude-User,
Claude-SearchBot, PerplexityBot, Google-Extended).
- **BrandButton** — Added `rel?: string` prop so external CTAs across
the site can pair `target="_blank"` with `rel="noopener noreferrer"`.
- **Routes** — Added `affiliates`, `affiliateTerms`,
`affiliateApplicationForm` to `src/config/routes.ts`.

## Component-mapping (per AGENTS.md "no speculative variants" rule)

| Section | Where it lives | Reuse decision |
|---|---|---|
| Hero (split text+media) | `components/affiliates/HeroSection.vue` |
Inline. Existing `HeroSection`s are tightly coupled to specific i18n
namespaces (`cloud.hero.*` etc.) and `legal/HeroSection` is title-only.
|
| Trust band | `components/affiliates/TrustBandSection.vue` | Inline.
`common/SocialProofBarSection` hardcodes a 12-logo client strip; not a
fit for a single text claim. |
| How-it-works | `components/affiliates/HowItWorksSection.vue` +
`common/SectionHeader` | Inline cards. Existing `StepsSection`s are
tightly bound to product-specific namespaces. |
| Who we're looking for | `components/affiliates/AudienceSection.vue` +
`common/SectionHeader` | Inline icon-bullet list.
`pricing/PricingPlanFeatureList` is shaped for plan features with
descriptions. |
| Program details | `components/affiliates/ProgramDetailsSection.vue` +
`common/SectionHeader` | Inline `<table>` (desktop) + `<dl>` (mobile).
`product/shared/ReasonSection` is a long-form "left heading + right
list" layout, not a key/value table. |
| Brand assets | `components/affiliates/BrandAssetsSection.vue` +
`common/SectionHeader` | Inline grid (no existing download-grid
primitive). |
| FAQ | `common/FAQSection.vue` (verbatim reuse) | Reuse — the component
is already generic over `headingKey`/`faqPrefix`/`faqCount`. |
| Footer CTA | `components/affiliates/FooterCtaSection.vue` +
`common/BrandButton` | Inline. `customers/WhatsNextSection` is an
arrow-CTA card, not a centered band. |

## Responsive behaviour

- Hero stacks (text above media) under `lg` (1024px).
- Program Details collapses from `<table>` (md+) to a `<dl>` definition
list (sm).
- 3-step flow collapses from 3-up grid to vertical stack at `md`.
- Brand-asset grid steps from `lg:grid-cols-4` → `sm:grid-cols-2` →
`grid-cols-1`.

## Tests

- **Vitest unit** (`src/components/affiliates/affiliateLanding.test.ts`)
— asserts i18n key structure: every section prefix exists, sections
render in order, no internal/draft keys leak, every indexed item (hero
highlights, steps, audience items, details rows, FAQs) has an English
translation.
- **Playwright e2e** (`e2e/affiliates.spec.ts`) — desktop+mobile
render/visibility under `@smoke`, plus a non-smoke `desktop
interactions` describe that exercises the Apply Now click (popup + form
URL) and FAQ accordion toggle. Mobile asserts table → definition-list
collapse and no horizontal overflow on every section. FAQPage JSON-LD
presence verified end-to-end.

Local verification: `pnpm typecheck`, `pnpm test:unit`, `pnpm exec
playwright test e2e/affiliates.spec.ts`, `pnpm knip` — all green (40
unit, 11/11 e2e).

## Out of scope (intentional follow-ups)

- zh-CN locale + `/zh-CN/affiliates` route (omitted from `robots.txt`
until the route exists; sitemap exclusion already handles it generically
via `LOCALE_PREFIXES.flatMap`).
- Flipping `noindex` off once copy and assets are finalized.
- Dropping in the four banner SVGs (728×90, 300×250, 160×600, 1200×628)
— config object is wired, just edit
`components/affiliates/brandAssets.ts`.
- Hero video (slot is wired).
- Hooking the Apply Now CTA up to a tracked URL once the affiliate
platform is live.

## Cross-PR dependency

The footer "Read the affiliate program terms" link targets
`/affiliates/terms`, which is added by #11954. Until that PR lands, the
link 404s on this branch's preview deployment; once both merge to main,
the pair is complete.

## Screenshots

Desktop (1280w) render attached.

## Screenshots

![Desktop render of /affiliates landing page
(1280w)](https://pub-1fd11710d4c8405b948c9edc4287a3f2.r2.dev/sessions/abdb5f46d61de76335da71e1dda13f2bb5d909244d19cb1c2d931634df264c81/pr-images/1778032141901-3962caf4-f3b6-45f4-9c1d-ef91e3b04441.png)

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-12002-feat-website-draft-Affiliate-Program-landing-page-at-affiliates-3586d73d365081cc9d78cf7ebe04747d)
by [Unito](https://www.unito.io)

---------

Co-authored-by: Glary-Bot <glary-bot@users.noreply.github.com>
Co-authored-by: Miles Ryan <thedatalife@users.noreply.github.com>
2026-06-02 21:41:47 +00:00
Alexander Brown
60db6e85bf chore: Remove unused tags, add a config option to prevent future unused tags (#12569)
Also updates the minor knip version.
2026-06-02 18:59:09 +00:00
Christian Byrne
c5cc09dbc1 feat: draft Affiliate Program Terms page at /affiliates/terms (#11954)
*PR Created by the Glary-Bot Agent*

---

Draft, `noindex`-gated legal page rendering the **Comfy.org Affiliate
Program Terms and Conditions** verbatim from the source document. Treats
the copy as legal-final-pending-signoff: lives in i18n translations so
legal/non-engineers can edit text without a code change, the page is
excluded from search engines (`<meta robots noindex>` + `robots.txt` +
sitemap filter), and a follow-up PR will flip it to indexable once legal
signs off.

## What this adds

- **Route:** `/affiliates/terms` (en) + `/zh-CN/affiliates/terms`
(zh-CN), matching the existing privacy-policy / terms-of-service
localization pattern.
- **Anchor IDs match the spec exactly:** `#1-program-overview`,
`#2-eligible-products`, …, `#11-miscellaneous` — stable deep-linking.
- **Sticky desktop TOC** with active-section highlighting
(IntersectionObserver, smooth scroll, header offset,
`prefers-reduced-motion` aware).
- **Collapsed `<details>` accordion TOC on mobile** that auto-closes
after a click.
- **Effective Date** is a single i18n key
(`affiliate-terms.effective-date`) — currently `[TBD]`. One config var,
consumed by the page footer.
- **Plain accessible legal-doc styling:** site design tokens, no
marketing flourish or gradients, narrow column for readable line length,
high-contrast text.
- **noindex everywhere:** robots `noindex,nofollow` meta via
`BaseLayout.noindex`, `Disallow: /affiliates/terms` added to every UA
block in `robots.txt` (including the AI-bot overrides), and the route
excluded from `@astrojs/sitemap` for both locales.

## Implementation notes

The website does not currently use MDX — it uses i18n translation keys +
Vue `ContentSection` components for legal pages. I followed that
established pattern (per AGENTS.md "Align with rest of subrepo on impl
and design") rather than introducing MDX integration just for this page.
Editing affiliates terms copy is a one-file change in
`src/i18n/translations.ts`, no code touch required, which satisfies the
"Nav or legal can edit without a code change" intent.

A new component `LegalContentSection.vue` is added (rather than reusing
`ContentSection.vue` directly) because legal docs need: (a) a
`<details>` mobile accordion TOC instead of the existing
horizontal-scroll `CategoryNav`, (b) a footer Effective Date, and (c) a
tighter block-type set (paragraph + bullet list only). Privacy /
Terms-of-Service pages are untouched.

## Skipped per spec

Per the original brief, "Competitive analysis" bullets and the "Open
questions for legal review" callout are internal-only and were not
copied into the i18n keys. There is a unit test asserting no key
matching `competitive-analysis|open-questions|legal-review` exists under
the `affiliate-terms.*` namespace.

## ⚠️ Flag for legal review

The source legal copy contains an internal contradiction that I copied
verbatim rather than silently editing:
- **Section 3 (Commission Structure)** says: *"Commission duration: 3
months from the referred customer's first paid subscription"*
- **Section 7 (Termination)** says: *"Commissions on referred customers
will cease at the time of termination, even if within the **12-month**
commission window"*

These two clauses imply different commission windows (3 months vs 12
months). I left the copy as-is for legal to resolve before the indexable
follow-up PR — flagging here so it doesn't get missed.

## Verification

- `pnpm typecheck` (root) — clean
- `pnpm typecheck:website` — clean (91 Astro files, 0 errors)
- `pnpm test:unit` (website) — 35/35 passing including 5 new unit tests
for the affiliate-terms section structure
- `pnpm exec playwright test affiliates-terms` — 8/8 passing (5 desktop
`@smoke`, 3 mobile `@mobile`)
- `pnpm format:check` — clean
- `pnpm build` — clean, both routes generated, sitemap correctly
excludes both locale variants
- All pre-commit hooks pass (stylelint + oxfmt + oxlint + eslint +
typecheck + typecheck:website + check-unused-i18n-keys)

## Manual verification

Screenshots embedded below from the local Astro preview build at desktop
(1280×900) and mobile (Pixel 5 / 393×852) viewports. The mobile
accordion's collapsed and expanded states are both captured.

## Sub-agent review

Ran the Oracle review against `main`. Initial pass flagged the
Last-updated/Effective-Date footer duplication and a missing zh-CN route
— both addressed in commit `8a1ce890d`. The 3-month vs 12-month
contradiction is left for legal (see above).

## Preview URL

The Vercel preview URL with the route appended will be posted as a PR
comment after CI completes:

`<vercel-preview-host>/affiliates/terms`

## Screenshots

![Desktop view at 1280px showing the Affiliate Terms hero, sticky 'On
this page' sidebar TOC with all 11 sections, and the first two sections
rendered with proper inline links and bolded defined
terms](https://pub-1fd11710d4c8405b948c9edc4287a3f2.r2.dev/sessions/27749b93a2505a1e163124b9a7a5d72763303bd73dbd488a0fed576999523401/pr-images/1777973250517-aa672747-ffa2-481e-a55d-3f1773905903.png)

![Mobile view at 393px showing the hero, the collapsed On this page
details accordion with chevron, and section 1 rendered cleanly within
the narrow
viewport](https://pub-1fd11710d4c8405b948c9edc4287a3f2.r2.dev/sessions/27749b93a2505a1e163124b9a7a5d72763303bd73dbd488a0fed576999523401/pr-images/1777973250852-a5373a7a-2428-4f07-9ad7-d18a13f3be08.png)

![Mobile view with the accordion expanded, showing all 11 section links
as tap targets and the active section highlighted in
yellow](https://pub-1fd11710d4c8405b948c9edc4287a3f2.r2.dev/sessions/27749b93a2505a1e163124b9a7a5d72763303bd73dbd488a0fed576999523401/pr-images/1777973251199-2ed02d90-9009-41ee-bf7a-2d681611dde5.png)

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-11954-feat-draft-Affiliate-Program-Terms-page-at-affiliates-terms-3576d73d36508121851ef666a8c4c537)
by [Unito](https://www.unito.io)

---------

Co-authored-by: Glary-Bot <glary-bot@users.noreply.github.com>
Co-authored-by: glary-bot <glary-bot@comfy.org>
2026-06-02 03:18:37 +00:00
imick-io
fef35e7dda fix(website): responsive fixes for pricing, product heroes, and cloud banner (#12570)
## Summary

Responsive polish: stack mobile pricing plans, rework the cloud product
hero so the illustration and text fit at all viewports, shrink the local
product hero illustration below xl, and reduce the cloud banner font
size on mobile.

## Changes

- **What**:
- `pricing/PriceSection.vue`: replace mobile tab-toggle pattern with
stacked plan cards; drop the `activePlanIndex` ref and tab buttons.
- `product/cloud/HeroSection.vue`: rework layout so illustration and
text fit across breakpoints (md/lg sizing, spacing, max-widths).
- `product/local/HeroSection.vue`: shrink illustration container below
xl (`max-w-xs`/`md:max-w-sm`/`lg:max-w-md`).
- `product/shared/CloudBannerSection.vue`: smaller font on mobile
(`text-sm` instead of `text-lg`).

## Review Focus

- Mobile pricing UX: confirm stacked cards are preferable to the prior
tab-toggle for our target viewports.
- Cloud hero layout at md/lg/xl breakpoints — check for overflow or
awkward spacing.

## Screenshots (if applicable)

<!-- Add before/after screenshots of the pricing page (mobile) and
product hero pages. -->

---------

Co-authored-by: github-actions <github-actions@github.com>
2026-06-01 21:30:30 +00:00
nav-tej
e4d481f893 fix(telemetry): harden PostHog init — person_profiles, cookie_domain, before_send (#12479)
## Summary

Hardens PostHog initialization in the cloud app and website with three
missing config options identified during PostHog QA audit.

## Changes

- **What**: Adds `person_profiles: 'identified_only'`, `cookie_domain:
'.comfy.org'`, and `before_send` PII redaction hook to both PostHog init
calls
- **person_profiles**: Prevents anonymous Person records being created
in PostHog for pre-auth visitors — only creates Person after
`identify()` is called (matches website config which already had this)
- **cookie_domain**: Enables cross-subdomain session stitching across
`app.comfy.org`, `docs.comfy.org`, `www.comfy.org` — without this, each
subdomain creates a separate PostHog session
- **before_send**: Last-line PII guard — strips `email`, `prompt`,
`user_email`, `$email` from event properties before transmission. Placed
after `...serverConfig` spread so it cannot be overridden by remote
config.

## Review Focus

- `before_send` runs before GeoIP enrichment — deliberately does NOT
drop `$ip` since country-code targeting needs it for the pricing
experiment
- `person_profiles: 'identified_only'` + anonymous flag evaluation:
PostHog confirmed this still allows flag eval via `$anon_distinct_id`;
stitched retroactively on `identify()`
- `serverConfig` spread is before the three new fields — these take
precedence over any remote config values (intentional for
security/correctness)

Closes MAR-233, MAR-235, MAR-236

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Miles <miles@comfy.org>
Co-authored-by: GitHub Action <action@github.com>
Co-authored-by: nav <nav@mac.lan>
Co-authored-by: Miles Ryan <thedatalife@users.noreply.github.com>
2026-06-01 20:53:00 +00:00
Deep Mehta
9813eee22f fix(website): make comfy.org favicon Google-compliant (#12536)
## Summary

Fix the comfy.org favicon declaration so Google Search can actually
refresh it — the logo has shown the old Astro starter chevron in Google
results for weeks even though the icon files were fixed in May.

## Changes

- **What**: The site declared two SVG favicons gated by
`prefers-color-scheme` media queries, no PNG favicon, and a
`favicon.ico` with only a 64×64 image. Google Search's favicon pipeline
can't resolve a single valid icon from that, so on recrawl it keeps the
last good cached icon (the old Astro chevron) instead of the current
mark. Replaced with the standard, checker-clean set:
- `favicon.svg` — single adaptive SVG (light/dark swap via internal CSS)
replacing the two media-query SVG links
- `favicon-96x96.png` — explicit desktop PNG at a Google-recommended
size (multiple of 48)
  - `favicon.ico` — rebuilt to contain 16/32/48 (was 64×64 only)
  - `site.webmanifest` + `web-app-manifest-192x192.png` / `-512x512.png`
- `<head>` simplified to RealFaviconGenerator's recommended markup +
`theme-color`
- **Breaking**: none. Pure static-asset + `<head>` change, no runtime
code touched.

## Review Focus

- This resolves the 3 errors + 3 warnings RealFaviconGenerator reported
for comfy.org (2 SVG favicons / no desktop PNG / ICO missing 16-32-48 /
no web manifest).
- The old `favicon-light.svg` and `favicon-dark.svg` are left in place
(now unreferenced) to avoid deleting assets in this PR — safe to remove
in a follow-up if desired.
- **Post-merge, required to actually fix Search**: in Google Search
Console, run URL Inspection → Request Indexing on `https://comfy.org/`.
The Search favicon only refreshes when Googlebot recrawls the homepage;
without a clean icon set + a recrawl nudge it will not self-correct.

## Before / After

### Before
<img width="939" height="388" alt="image"
src="https://github.com/user-attachments/assets/5fa95fd6-2248-4ed9-921e-9c516f4c0c3e"
/>

### After
<img width="1145" height="447" alt="image"
src="https://github.com/user-attachments/assets/dc33a99d-f7f6-41d4-a83d-03b3b99d0b0d"
/>

## Screenshots (if applicable)
2026-05-30 05:21:29 +00:00
imick-io
13e67561cf fix(website): tweak gallery contact heading and enterprise card color (#12530)
## Summary
- Add `<br>` after "Built something cool with ComfyUI?" in the gallery
contact heading (en + zh-CN) so the Submit link wraps to a new line.
- Switch the Enterprise product card background from
`bg-illustration-forest` to `bg-secondary-cool-gray`.

## Test plan
- [ ] Visit the gallery contact section and confirm the heading wraps
after "ComfyUI?" in both English and Chinese.
- [ ] Verify the Enterprise card on the product cards section renders
with the cool gray background.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: Alexander Brown <drjkl@comfy.org>
2026-05-29 21:43:36 +00:00
imick-io
a0411d9beb refactor(website): centralize gallery items into src/data/gallery.ts (#12526)
## Summary

Establish a single source of truth for gallery items. Previously the
items array and the `GalleryItem` interface lived inline in
`GallerySection.vue`, with three sibling components importing the type
*out of a `.vue` file* — coupling pure data and types to a presentation
component.

- **One canonical list.** Items now live in `src/data/gallery.ts`
alongside the `GalleryItem` interface.
- **Per-item visibility without deletion.** New optional `visible?:
boolean` field on each item
- **Stable identity.** Each item now carries a required `id` kebab-slug
derived from its title.
- **lookup helper.** `getGalleryItemById(id)` for callers that want a
single item.

The sibling gallery components (`GalleryCard`, `GalleryDetailModal`,
`GalleryItemAttribution`) now import the `GalleryItem` type from
`../../data/gallery` instead of from the `.vue` file.

## Scope note

I also audited the rest of the website for other surfaces that should
consume the centralized data.

**I need this refactor for the new page `models` coming soon.**

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: GitHub Action <action@github.com>
2026-05-29 21:14:07 +00:00
guill
e02ee17d3d fix(website): memoize GitHub stars fetch to one call per build (#12495)
*PR Created by the Glary-Bot Agent*

---

## Problem

The GitHub star badge silently disappears from the comfy.org navigation.
Verified by curl-ing the live homepage:

```
props="{...&quot;github-stars&quot;:[0,&quot;&quot;]}"
```

`SiteNav.vue` only renders the badge when `githubStars` is truthy, so an
empty string hides it.

## Root cause

`apps/website/src/layouts/BaseLayout.astro` `await`s
`fetchGitHubStars('Comfy-Org', 'ComfyUI')` in its frontmatter. Astro
evaluates layout frontmatter **per rendered page** in SSG. With 379
pages (46 source `.astro` files × locales/dynamic routes), the
unauthenticated GitHub REST endpoint is called hundreds of times per
build, blasting past the 60 req/h anonymous rate limit. Once GitHub
returns 403 the existing `try/catch` returns `null`, `githubStars`
becomes `''`, and the badge vanishes — with no log line to indicate why.

## Fix

Cache the in-flight promise in a module-scope `Map` keyed by
`${owner}/${repo}` so every page in a single build shares one request.
Already-resolved counts stay cached, and the existing
`WEBSITE_GITHUB_STARS_OVERRIDE` env-var escape hatch still
short-circuits first.

While in the file:
- Pass an injectable `fetchImpl` so tests can stub without
`vi.spyOn(globalThis, 'fetch')`.
- Replace the implicit-`any` `data.stargazers_count ?? null` with a
narrow `readStargazerCount(data: unknown)` guard.
- In `BaseLayout.astro`, change `rawStars ? ...` to `rawStars !== null ?
...` so a hypothetical 0-star repo wouldn't be hidden (the old check
treated 0 as missing).

## Verification

- `pnpm --filter @comfyorg/website test:unit` → 89/89 pass (5 new test
cases: memoization, per-key isolation, non-2xx → null, throw → null,
override).
- `pnpm typecheck:website` → 0 errors.
- `pnpm format:check` → clean.
- `pnpm --filter @comfyorg/website build` → 379 pages built; with no
override set, output HTML contains `"github-stars":[0,"115K"]` (the live
count) on every page; with `WEBSITE_GITHUB_STARS_OVERRIDE=110000`, it
contains `"110K"` and `fetch` is never called.
- Playwright on the local preview confirms the badge renders at the
top-right of the nav with `aria-label="ComfyUI on GitHub — 110K stars"`.

## Scope

102 lines changed across 3 files (40 non-test). Deliberately leaves the
broader "snapshot fallback / build-data source" refactor to the existing
`codex/website-github-stars-once` branch — this PR just unblocks the
user-visible symptom.

## Screenshots

![Site navigation showing the 110K GitHub star badge restored next to
the DOWNLOAD LOCAL / LAUNCH CLOUD
buttons](https://pub-1fd11710d4c8405b948c9edc4287a3f2.r2.dev/sessions/d921afa7b2cb2a9088080967634aeb3e2e67ee09a8ac13f6e434c1c7589434c1/pr-images/1779918781152-ccaeab7f-9150-4d8b-ae4e-f20bbf49091b.png)

---------

Co-authored-by: Glary-Bot <glary-bot@users.noreply.github.com>
Co-authored-by: Alexander Brown <drjkl@comfy.org>
2026-05-29 03:04:41 +00:00
imick-io
0d0231453a fix(website): stack role title above team and location on careers list (#12510)
## Summary
- Long role titles wrapped awkwardly next to the inline department label
on the careers list, especially on narrow viewports.
- Restructured the role link so the title sits on its own row with the
arrow icon on the right, and the department + location wrap together on
a metadata row beneath (16px gap between them).

## Test plan
- [ ] Open `/careers` on mobile width and confirm long titles (e.g.
"Senior Software Engineer, Frontend") no longer collide with the
department label.
- [ ] Confirm desktop layout still reads cleanly.

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-28 19:49:53 +00:00
Luke Mino-Altherr
db6b7a315c chore: remediate 51 Dependabot vulnerabilities (#12345)
## Summary

Remediate 51 of 63 open Dependabot security alerts by bumping direct
dependencies, bumping parent dependencies, and adding targeted pnpm
overrides for transitive dependencies.

## Changes

- **What**: Two batches of dependency security fixes
- **Batch 1**: Bump catalog minimums for axios, dompurify, happy-dom,
vite, uuid. Fix axios header type narrowing in api.ts.
- **Batch 2**: Bump parent deps (@iconify/tailwind4, vue, knip) to pull
fixed transitive deps. Add tilde-pinned pnpm overrides for protobufjs,
flatted, defu where no parent fix is available. Unexport 6 unused types
flagged by knip upgrade.
- **Dependencies**: vue 3.5.13->3.5.34 required two type fixes
(LazyImage ClassValue, dialogStore deep instantiation)

## Review Focus

- pnpm overrides in package.json: protobufjs ~7.6.0, flatted ~3.4.2,
defu ~6.1.7
- Vue 3.5.34 type narrowing fixes in LazyImage.vue and dialogStore.ts

## Remaining (12 alerts, separate PRs)

- minimatch (4H) - 4 major version lines, needs per-consumer analysis
- picomatch (2M) - two major version lines
- brace-expansion (2M) - multiple major version lines
- astro (2: 1L+1M) - major version bump 5->6
- postcss 8.5.8 (1M) - dev-only, from @vue/compiler-sfc@3.5.28 via
storybook/devtools
- yaml 1.10.2 (1M) - from cosmiconfig->nx, no upstream fix in yaml v1
- lodash/lodash-es (4: 2H+2M) - dev-only, upstream still uses 4.17.x
- @babel/plugin-transform-modules-systemjs (1H) - dev-only via nx
- fast-uri (2H) - dev-only via ajv->nx/stylelint

Fixes #FE-762

---------

Co-authored-by: Austin Mroz <austin@comfy.org>
Co-authored-by: Alexander Brown <drjkl@comfy.org>
2026-05-27 14:07:34 -07:00
Robin Huang
7599c6a1ca chore: remove EA logo from website social proof bar (#12477)
Removes the EA (Electronic Arts) logo from the client social proof bar
on the website. Drops it from the logos list in
`SocialProofBarSection.vue` and deletes the now-unused `EA.svg` asset.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-27 05:05:36 +00:00
imick-io
08ee925811 theme-aware favicon for light and dark mode (#12457)
## Summary

Serve separate SVG favicons via prefers-color-scheme so the icon stays
legible against both light and dark browser chrome. Drop the
unreferenced favicon.svg / favicon.png; keep favicon.ico as the legacy
fallback.

## Changes

- What: apps/website/src/layouts/BaseLayout.astro now links
favicon-light.svg and favicon-dark.svg gated on prefers-color-scheme,
with favicon.ico retained as the legacy fallback. Unreferenced
favicon.svg / favicon.png removed from apps/website/public/.

## Review Focus

- Naming convention: favicon-light.svg is the asset served in light mode
(dark-backgrounded icon for contrast against light chrome);
favicon-dark.svg is served in dark mode. Confirm this matches
expectation.
- Safari fallback: older Safari versions ignore prefers-color-scheme on
<link rel="icon"> and will fall through to favicon.ico — that file is
unchanged and should look acceptable in both modes.

## Screenshots

Dark mode:
<img width="224" height="30" alt="image"
src="https://github.com/user-attachments/assets/5fa3c620-0021-4c90-bc18-013cd6ef45cf"
/>

Light mode:
<img width="227" height="28" alt="image"
src="https://github.com/user-attachments/assets/54a130e1-f976-46e8-b047-e27efe22e479"
/>
2026-05-25 19:20:41 +00:00
imick-io
eeeacc9b03 feat(website): constrain sections to max-w-9xl on wide screens (#12428)
Add max-w-9xl mx-auto to section/container wrappers across the website
so layout stays centered and capped at 96rem on screens wider than
1536px.

## Summary

<!-- One sentence describing what changed and why. -->

## Changes

- **What**: <!-- Core functionality added/modified -->
- **Breaking**: <!-- Any breaking changes (if none, remove this line)
-->
- **Dependencies**: <!-- New dependencies (if none, remove this line)
-->

## Review Focus

<!-- Critical design decisions or edge cases that need attention -->

<!-- If this PR fixes an issue, uncomment and update the line below -->
<!-- Fixes #ISSUE_NUMBER -->

## Screenshots (if applicable)

<!-- Add screenshots or video recording to help explain your changes -->

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-22 21:36:29 +00:00
Daxiong (Lin)
60ce0ee0c3 Add png and ico favicon for comfy.org (#12426) 2026-05-22 11:55:41 -07:00
Alexander Brown
c703db5f6c chore: remove Nx and migrate monorepo workflows to pnpm (#12355)
## Summary
- remove Nx root/config artifacts and workspace 
x metadata
- replace Nx-based root scripts with direct pnpm workspace + native
Vite/Vitest/Playwright commands
- remove Nx dependencies/catalog entries and regenerate lockfile
- clean residual Nx references from CI workflows, tooling config, and
docs

## Validation
- pnpm install --frozen-lockfile
- pnpm lint
- pnpm typecheck
- pnpm build
- pnpm build:cloud
- pnpm build:desktop
- pnpm build:types
- pnpm test:browser -- --list
- pnpm test:unit *(4 pre-existing failing tests)*

ΓöåIssue is synchronized with this [Notion
page](https://www.notion.so/PR-12355-chore-remove-Nx-and-migrate-monorepo-workflows-to-pnpm-3666d73d3650817888b9e85e24a10b22)
by [Unito](https://www.unito.io)

---

**For keeping Nx**
- Better monorepo orchestration (task graph, affected runs, caching).
- Can reduce CI/runtime cost at larger scale.
- Unified interface across tools and packages.

**Against keeping Nx**
- Extra abstraction layer and config complexity.
- Higher maintenance/debugging cost (plugins, cache behavior, drift).
- Native `pnpm` + tool CLIs are simpler and clearer today.

**Bottom line**
- If current pain is low: prefer simplicity and remove Nx.
- If measured scale pain is high: orchestration may be worth it (Nx or
another tool later).

---------

Co-authored-by: Amp <amp@ampcode.com>
2026-05-22 05:37:10 +00:00
Comfy Org PR Bot
9a2bea7283 chore(website): refresh Ashby and cloud nodes snapshots (#12410)
Automated refresh of remote-data snapshots used by the website
build:

- `apps/website/src/data/ashby-roles.snapshot.json` — Ashby job
  board API
- `apps/website/src/data/cloud-nodes.snapshot.json` — Comfy Cloud
  `/api/object_info`

**Flow:**
1. `Release: Website` workflow ran (manual trigger).
2. This PR opens with the regenerated snapshots.
3. `CI: Vercel Website Preview` deploys a preview for review.
4. Merging to `main` triggers the production Vercel deploy.

The snapshot fallback in `apps/website/src/utils/ashby.ts` and
`apps/website/src/utils/cloudNodes.ts` remains intact: builds
without the respective API keys continue to use the committed
snapshot (with a warning annotation in CI).

Triggered by workflow run `26260485885`.

Co-authored-by: christian-byrne <72887196+christian-byrne@users.noreply.github.com>
2026-05-22 00:21:09 +00:00