diff --git a/.github/actions/upsert-comment-section/action.yaml b/.github/actions/upsert-comment-section/action.yaml new file mode 100644 index 0000000000..853af0aeb3 --- /dev/null +++ b/.github/actions/upsert-comment-section/action.yaml @@ -0,0 +1,79 @@ +name: Upsert Comment Section +description: > + Manage a consolidated PR comment with independently-updatable sections. + All website CI workflows share the marker . + Valid section names: "e2e", "preview", "screenshot-update". + +inputs: + pr-number: + description: PR number to comment on + required: true + section-name: + description: 'Section identifier: "e2e", "preview", or "screenshot-update"' + required: true + section-content: + description: Markdown content for this section + required: true + comment-marker: + description: Top-level HTML comment marker (must be for all callers) + required: true + token: + description: GitHub token with pull-requests write permission + required: true + +runs: + using: composite + steps: + - uses: actions/github-script@v8 + env: + INPUT_PR_NUMBER: ${{ inputs.pr-number }} + INPUT_SECTION_NAME: ${{ inputs.section-name }} + INPUT_SECTION_CONTENT: ${{ inputs.section-content }} + INPUT_COMMENT_MARKER: ${{ inputs.comment-marker }} + with: + github-token: ${{ inputs.token }} + script: | + const prNumber = Number(process.env.INPUT_PR_NUMBER) + const sectionName = process.env.INPUT_SECTION_NAME + const sectionContent = process.env.INPUT_SECTION_CONTENT + const commentMarker = process.env.INPUT_COMMENT_MARKER + + const sectionStart = `` + const sectionEnd = `` + const sectionBlock = `${sectionStart}\n${sectionContent}\n${sectionEnd}` + + // Escape special regex characters in delimiter strings + const escapeRegex = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&') + + const comments = await github.paginate( + github.rest.issues.listComments, + { ...context.repo, issue_number: prNumber } + ) + + const existing = comments.find( + (c) => + c.user?.login === 'github-actions[bot]' && + c.body?.includes(commentMarker) + ) + + if (!existing) { + return github.rest.issues.createComment({ + ...context.repo, + issue_number: prNumber, + body: `${commentMarker}\n${sectionBlock}` + }) + } + + const body = existing.body ?? '' + const sectionRegex = new RegExp( + `${escapeRegex(sectionStart)}[\\s\\S]*?${escapeRegex(sectionEnd)}` + ) + const updated = sectionRegex.test(body) + ? body.replace(sectionRegex, sectionBlock) + : body.trimEnd() + '\n\n' + sectionBlock + + return github.rest.issues.updateComment({ + ...context.repo, + comment_id: existing.id, + body: updated + }) diff --git a/.github/workflows/ci-website-e2e.yaml b/.github/workflows/ci-website-e2e.yaml index 93f61f5b0f..3e56e1dba9 100644 --- a/.github/workflows/ci-website-e2e.yaml +++ b/.github/workflows/ci-website-e2e.yaml @@ -27,35 +27,17 @@ jobs: image: mcr.microsoft.com/playwright:v1.58.1-noble timeout-minutes: 15 permissions: - pull-requests: write contents: read + outputs: + test-outcome: ${{ steps.tests.outcome }} + report-url: ${{ steps.deploy.outputs.url }} + screenshot-failures: ${{ steps.failures.outputs.screenshot }} + other-failures: ${{ steps.failures.outputs.other }} + # Evaluated at job level (not from a step) — static expression. + is-pr: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.repo.fork == false }} steps: - uses: actions/checkout@v6 - - name: Post starting comment - if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.fork == false - uses: actions/github-script@v8 - with: - script: | - const marker = '' - const body = [ - marker, - '## 🌐 Website E2E', - '', - '> [!NOTE]', - `> Tests are running… [View workflow run](${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId})` - ].join('\n') - const { data: comments } = await github.rest.issues.listComments({ - ...context.repo, - issue_number: context.issue.number - }) - const existing = comments.find(c => c.body.includes(marker)) - if (existing) { - await github.rest.issues.updateComment({ ...context.repo, comment_id: existing.id, body }) - } else { - await github.rest.issues.createComment({ ...context.repo, issue_number: context.issue.number, body }) - } - - name: Install pnpm run: corepack enable && corepack prepare @@ -134,15 +116,20 @@ jobs: core.setOutput('screenshot', screenshotFailures) core.setOutput('other', failed.length - screenshotFailures) - - name: Post result comment and summary + - name: Write job summary if: always() && !cancelled() uses: actions/github-script@v8 + env: + TEST_OUTCOME: ${{ steps.tests.outcome }} + REPORT_URL: ${{ steps.deploy.outputs.url }} + SCREENSHOT_FAILURES: ${{ steps.failures.outputs.screenshot }} + OTHER_FAILURES: ${{ steps.failures.outputs.other }} with: script: | - const passed = '${{ steps.tests.outcome }}' === 'success' - const reportUrl = '${{ steps.deploy.outputs.url }}' - const screenshotFailures = parseInt('${{ steps.failures.outputs.screenshot }}') || 0 - const otherFailures = parseInt('${{ steps.failures.outputs.other }}') || 0 + const passed = process.env.TEST_OUTCOME === 'success' + const reportUrl = process.env.REPORT_URL + const screenshotFailures = parseInt(process.env.SCREENSHOT_FAILURES) || 0 + const otherFailures = parseInt(process.env.OTHER_FAILURES) || 0 const lines = ['## 🌐 Website E2E', ''] @@ -152,7 +139,87 @@ jobs: lines.push('> [!CAUTION]', '> Some tests failed.') } - // Results table + const rows = [ + ['Status', passed ? '✅ Passed' : '❌ Failed'], + ['Report', reportUrl ? `[View Report](${reportUrl})` : '_unavailable_'] + ] + if (!passed) { + rows.push( + ['Screenshot diffs', String(screenshotFailures)], + ['Other failures', String(otherFailures)] + ) + } + lines.push( + '', + '| | |', + '|---|---|', + ...rows.map(([k, v]) => `| **${k}** | ${v} |`) + ) + + await core.summary.addRaw(lines.join('\n')).write() + + post-starting-comment: + # Safe to comment from pull_request trigger: fork PRs are excluded by the guard below. + # This avoids a ci-*/pr-* workflow_run split for a comment that must appear immediately. + if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.fork == false + runs-on: ubuntu-latest + permissions: + pull-requests: write + contents: read + concurrency: + group: website-pr-comment-${{ github.event.pull_request.number }} + cancel-in-progress: false + steps: + - uses: actions/checkout@v6 + - uses: ./.github/actions/upsert-comment-section + with: + pr-number: ${{ github.event.pull_request.number }} + section-name: e2e + comment-marker: '' + token: ${{ secrets.GITHUB_TOKEN }} + section-content: |- + ## 🌐 Website E2E + + + > [!NOTE] + > Tests are running… [View workflow run](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}) + + post-result-comment: + needs: website-e2e + if: always() && !cancelled() && needs.website-e2e.outputs.is-pr == 'true' + runs-on: ubuntu-latest + permissions: + pull-requests: write + contents: read + concurrency: + group: website-pr-comment-${{ github.event.pull_request.number }} + cancel-in-progress: false + steps: + - uses: actions/checkout@v6 + + - name: Build e2e section content + id: content + uses: actions/github-script@v8 + env: + TEST_OUTCOME: ${{ needs.website-e2e.outputs.test-outcome }} + REPORT_URL: ${{ needs.website-e2e.outputs.report-url }} + SCREENSHOT_FAILURES: ${{ needs.website-e2e.outputs.screenshot-failures }} + OTHER_FAILURES: ${{ needs.website-e2e.outputs.other-failures }} + with: + script: | + const passed = process.env.TEST_OUTCOME === 'success' + const reportUrl = process.env.REPORT_URL + const screenshotFailures = parseInt(process.env.SCREENSHOT_FAILURES) || 0 + const otherFailures = parseInt(process.env.OTHER_FAILURES) || 0 + + const lines = ['## 🌐 Website E2E', '', ''] + + if (passed) { + lines.push('> [!TIP]', '> All tests passed.') + } else { + lines.push('> [!CAUTION]', '> Some tests failed.') + } + const rows = [ ['Status', passed ? '✅ Passed' : '❌ Failed'], ['Report', reportUrl ? `[View Report](${reportUrl})` : '_unavailable_'] @@ -182,20 +249,12 @@ jobs: ) } - const summary = lines.join('\n') - await core.summary.addRaw(summary).write() + core.setOutput('section-content', lines.join('\n')) - if (context.eventName === 'pull_request' && !context.payload.pull_request.head.repo.fork) { - const marker = '' - const body = `${marker}\n${summary}` - const { data: comments } = await github.rest.issues.listComments({ - ...context.repo, - issue_number: context.issue.number - }) - const existing = comments.find(c => c.body.includes(marker)) - if (existing) { - await github.rest.issues.updateComment({ ...context.repo, comment_id: existing.id, body }) - } else { - await github.rest.issues.createComment({ ...context.repo, issue_number: context.issue.number, body }) - } - } + - uses: ./.github/actions/upsert-comment-section + with: + pr-number: ${{ github.event.pull_request.number }} + section-name: e2e + comment-marker: '' + token: ${{ secrets.GITHUB_TOKEN }} + section-content: ${{ steps.content.outputs.section-content }} diff --git a/.github/workflows/pr-update-website-screenshots.yaml b/.github/workflows/pr-update-website-screenshots.yaml index e66bbb07cf..30b7537561 100644 --- a/.github/workflows/pr-update-website-screenshots.yaml +++ b/.github/workflows/pr-update-website-screenshots.yaml @@ -16,7 +16,11 @@ jobs: container: image: mcr.microsoft.com/playwright:v1.58.1-noble timeout-minutes: 15 + permissions: + contents: write + pull-requests: read # Trigger: (1) label, (2) /slash-command, or (3) checkbox in E2E status comment + # ⚠️ This condition is duplicated on `post-starting-comment` — keep them in sync. if: > ( github.event_name == 'pull_request' && github.event.label.name == 'Update Website Screenshots' ) || @@ -34,6 +38,11 @@ jobs: github.actor != 'github-actions[bot]' && contains(github.event.comment.body, '') && contains(github.event.comment.body, '- [x] Update website screenshots') ) + outputs: + pr-number: ${{ steps.pr-info.outputs.pr-number }} + update-outcome: ${{ steps.update-screenshots.outcome }} + has-changes: ${{ steps.commit.outputs.has-changes }} + changed-count: ${{ steps.commit.outputs.changed-count }} steps: - name: Verify sender permissions if: > @@ -53,9 +62,11 @@ jobs: - name: Get PR info id: pr-info uses: actions/github-script@v8 + env: + PR_NUMBER: ${{ github.event.number || github.event.issue.number }} with: script: | - const prNumber = ${{ github.event.number || github.event.issue.number }} + const prNumber = Number(process.env.PR_NUMBER) const { data: pr } = await github.rest.pulls.get({ ...context.repo, pull_number: prNumber @@ -90,7 +101,10 @@ jobs: git config --global user.name 'github-actions' git config --global user.email 'github-actions@github.com' - if [ -z "$(git status --porcelain=v1 --untracked-files=all -- apps/website/e2e/)" ]; then + CHANGED=$(git status --porcelain=v1 --untracked-files=all -- apps/website/e2e/ | wc -l) + echo "changed-count=${CHANGED}" >> $GITHUB_OUTPUT + + if [ "$CHANGED" -eq 0 ]; then echo "No screenshot changes to commit" echo "has-changes=false" >> $GITHUB_OUTPUT exit 0 @@ -112,14 +126,114 @@ jobs: - name: Remove label if: always() && github.event_name == 'pull_request' uses: actions/github-script@v8 + env: + PR_NUMBER: ${{ steps.pr-info.outputs.pr-number }} with: script: | try { await github.rest.issues.removeLabel({ ...context.repo, - issue_number: ${{ steps.pr-info.outputs.pr-number }}, + issue_number: Number(process.env.PR_NUMBER), name: 'Update Website Screenshots' }) } catch (e) { // Label may already be removed } + + post-starting-comment: + # Runs in parallel with update-screenshots to show "in progress" immediately. + # ⚠️ This condition is duplicated from `update-screenshots` — keep them in sync. + if: > + ( github.event_name == 'pull_request' && + github.event.label.name == 'Update Website Screenshots' ) || + ( github.event.issue.pull_request && + github.event_name == 'issue_comment' && + ( + github.event.comment.author_association == 'OWNER' || + github.event.comment.author_association == 'MEMBER' || + github.event.comment.author_association == 'COLLABORATOR' + ) && + startsWith(github.event.comment.body, '/update-website-screenshots') ) || + ( github.event.issue.pull_request && + github.event_name == 'issue_comment' && + github.event.comment.user.login == 'github-actions[bot]' && + github.actor != 'github-actions[bot]' && + contains(github.event.comment.body, '') && + contains(github.event.comment.body, '- [x] Update website screenshots') ) + runs-on: ubuntu-latest + permissions: + pull-requests: write + contents: read + concurrency: + group: website-pr-comment-${{ github.event.number || github.event.issue.number }} + cancel-in-progress: false + steps: + - uses: actions/checkout@v6 + - uses: ./.github/actions/upsert-comment-section + with: + pr-number: ${{ github.event.number || github.event.issue.number }} + section-name: screenshot-update + comment-marker: '' + token: ${{ secrets.GITHUB_TOKEN }} + section-content: |- + ## 📸 Screenshot Update + + > [!NOTE] + > Updating screenshots… [View workflow run](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}) + + post-result-comment: + needs: update-screenshots + if: always() && !cancelled() && needs.update-screenshots.result != 'skipped' + runs-on: ubuntu-latest + permissions: + pull-requests: write + contents: read + concurrency: + group: website-pr-comment-${{ needs.update-screenshots.outputs.pr-number }} + cancel-in-progress: false + steps: + - uses: actions/checkout@v6 + + - name: Build screenshot-update section content + id: content + uses: actions/github-script@v8 + env: + UPDATE_OUTCOME: ${{ needs.update-screenshots.outputs.update-outcome }} + HAS_CHANGES: ${{ needs.update-screenshots.outputs.has-changes }} + CHANGED_COUNT: ${{ needs.update-screenshots.outputs.changed-count }} + with: + script: | + const outcome = process.env.UPDATE_OUTCOME + const hasChanges = process.env.HAS_CHANGES === 'true' + const changedCount = parseInt(process.env.CHANGED_COUNT) || 0 + const runUrl = `${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}` + + const lines = ['## 📸 Screenshot Update', ''] + + if (outcome !== 'success') { + lines.push( + '> [!CAUTION]', + `> Screenshot update failed. [View workflow run](${runUrl})` + ) + } else if (!hasChanges) { + lines.push( + '> [!TIP]', + '> All screenshots are already up to date.' + ) + } else { + const s = changedCount === 1 ? '' : 's' + lines.push( + '> [!TIP]', + `> Updated ${changedCount} screenshot${s} and pushed to the branch.` + ) + } + + core.setOutput('section-content', lines.join('\n')) + + - uses: ./.github/actions/upsert-comment-section + with: + pr-number: ${{ needs.update-screenshots.outputs.pr-number }} + section-name: screenshot-update + comment-marker: '' + token: ${{ secrets.GITHUB_TOKEN }} + section-content: ${{ steps.content.outputs.section-content }} diff --git a/.github/workflows/pr-vercel-website-preview.yaml b/.github/workflows/pr-vercel-website-preview.yaml index 167383ecb0..1f718f5047 100644 --- a/.github/workflows/pr-vercel-website-preview.yaml +++ b/.github/workflows/pr-vercel-website-preview.yaml @@ -7,11 +7,6 @@ on: types: - completed -permissions: - contents: read - pull-requests: write - actions: read - concurrency: group: ${{ github.workflow }}-${{ github.event.workflow_run.head_repository.full_name }}-${{ github.event.workflow_run.head_branch }} cancel-in-progress: true @@ -19,6 +14,16 @@ concurrency: jobs: comment: runs-on: ubuntu-latest + permissions: + contents: read + pull-requests: write + actions: read + # Uses head_branch as proxy for PR number (unavailable at job-level in workflow_run). + # Preview and E2E comment writes are NOT mutually serialized — the race window is + # small and self-healing on next push. + concurrency: + group: website-pr-comment-${{ github.event.workflow_run.head_branch }} + cancel-in-progress: false if: > github.repository == 'Comfy-Org/ComfyUI_frontend' && github.event.workflow_run.event == 'pull_request' && @@ -37,28 +42,29 @@ jobs: id: pr-meta uses: ./.github/actions/resolve-pr-from-workflow-run - - name: Write report + - name: Read preview URLs if: steps.pr-meta.outputs.skip != 'true' - env: - DEPLOYED_AT: ${{ github.event.workflow_run.updated_at }} - HEAD_SHA: ${{ github.event.workflow_run.head_sha }} + id: urls run: | - STABLE_URL=$(cat temp/vercel-preview/stable-url.txt) - UNIQUE_URL=$(cat temp/vercel-preview/url.txt) - SHORT_SHA="${HEAD_SHA:0:7}" - cat > preview-report.md <> "$GITHUB_OUTPUT" + echo "unique-url=$(cat temp/vercel-preview/url.txt)" >> "$GITHUB_OUTPUT" + echo "short-sha=${HEAD_SHA:0:7}" >> "$GITHUB_OUTPUT" + env: + HEAD_SHA: ${{ github.event.workflow_run.head_sha }} - This commit: $UNIQUE_URL - - Last updated: $DEPLOYED_AT for \`$SHORT_SHA\` - EOF - - - name: Post PR comment + - name: Post preview comment if: steps.pr-meta.outputs.skip != 'true' - uses: ./.github/actions/post-pr-report-comment + uses: ./.github/actions/upsert-comment-section with: pr-number: ${{ steps.pr-meta.outputs.number }} - report-file: ./preview-report.md - comment-marker: '' + section-name: preview + comment-marker: '' token: ${{ secrets.GITHUB_TOKEN }} + section-content: |- + ## 🔗 Website Preview + + **Website Preview:** ${{ steps.urls.outputs.stable-url }} + + This commit: ${{ steps.urls.outputs.unique-url }} + + Last updated: ${{ github.event.workflow_run.updated_at }} for `${{ steps.urls.outputs.short-sha }}` diff --git a/apps/website/e2e/visual-responsive.spec.ts b/apps/website/e2e/visual-responsive.spec.ts index 2bd9c5cf34..1954901d85 100644 --- a/apps/website/e2e/visual-responsive.spec.ts +++ b/apps/website/e2e/visual-responsive.spec.ts @@ -122,17 +122,6 @@ test.describe('About', { tag: '@visual' }, () => { } }) -const OVERFLOW_SKIP = new Set([ - '/ 3-lg', - '/ 4-xl', - '/cloud 2-md', - '/cloud 3-lg', - '/cloud 4-xl', - '/download 2-md', - '/download 3-lg', - '/download 4-xl' -]) - test.describe('Overflow guards', { tag: '@visual' }, () => { const pages = [ '/', @@ -146,10 +135,7 @@ test.describe('Overflow guards', { tag: '@visual' }, () => { ] for (const url of pages) { for (const vp of VIEWPORTS) { - const key = `${url} ${vp.name}` - test(`${url} ${vp.name} no overflow`, async ({ page }) => { - test.skip(OVERFLOW_SKIP.has(key), 'Known overflow bug at this viewport') await page.setViewportSize({ width: vp.width, height: vp.height }) await page.goto(url) await assertNoOverflow(page) diff --git a/apps/website/e2e/visual-responsive.spec.ts-snapshots/home-get-started-3-lg-visual-linux.png b/apps/website/e2e/visual-responsive.spec.ts-snapshots/home-get-started-3-lg-visual-linux.png index 6d2b92d576..574eb38a02 100644 Binary files a/apps/website/e2e/visual-responsive.spec.ts-snapshots/home-get-started-3-lg-visual-linux.png and b/apps/website/e2e/visual-responsive.spec.ts-snapshots/home-get-started-3-lg-visual-linux.png differ diff --git a/apps/website/e2e/visual-responsive.spec.ts-snapshots/home-get-started-4-xl-visual-linux.png b/apps/website/e2e/visual-responsive.spec.ts-snapshots/home-get-started-4-xl-visual-linux.png index b5c23301c5..8093050e83 100644 Binary files a/apps/website/e2e/visual-responsive.spec.ts-snapshots/home-get-started-4-xl-visual-linux.png and b/apps/website/e2e/visual-responsive.spec.ts-snapshots/home-get-started-4-xl-visual-linux.png differ diff --git a/apps/website/e2e/visual-responsive.spec.ts-snapshots/home-product-cards-3-lg-visual-linux.png b/apps/website/e2e/visual-responsive.spec.ts-snapshots/home-product-cards-3-lg-visual-linux.png index d7049036f2..1a0b83ef45 100644 Binary files a/apps/website/e2e/visual-responsive.spec.ts-snapshots/home-product-cards-3-lg-visual-linux.png and b/apps/website/e2e/visual-responsive.spec.ts-snapshots/home-product-cards-3-lg-visual-linux.png differ diff --git a/apps/website/e2e/visual-responsive.spec.ts-snapshots/home-product-cards-4-xl-visual-linux.png b/apps/website/e2e/visual-responsive.spec.ts-snapshots/home-product-cards-4-xl-visual-linux.png index 3ecca8280e..35f66b2859 100644 Binary files a/apps/website/e2e/visual-responsive.spec.ts-snapshots/home-product-cards-4-xl-visual-linux.png and b/apps/website/e2e/visual-responsive.spec.ts-snapshots/home-product-cards-4-xl-visual-linux.png differ diff --git a/apps/website/e2e/visual-responsive.spec.ts-snapshots/pricing-tiers-3-lg-visual-linux.png b/apps/website/e2e/visual-responsive.spec.ts-snapshots/pricing-tiers-3-lg-visual-linux.png index 6e10eee00a..a7f3a9e53d 100644 Binary files a/apps/website/e2e/visual-responsive.spec.ts-snapshots/pricing-tiers-3-lg-visual-linux.png and b/apps/website/e2e/visual-responsive.spec.ts-snapshots/pricing-tiers-3-lg-visual-linux.png differ diff --git a/apps/website/e2e/visual-responsive.spec.ts-snapshots/pricing-tiers-4-xl-visual-linux.png b/apps/website/e2e/visual-responsive.spec.ts-snapshots/pricing-tiers-4-xl-visual-linux.png index cf5e4db42e..aafcacda74 100644 Binary files a/apps/website/e2e/visual-responsive.spec.ts-snapshots/pricing-tiers-4-xl-visual-linux.png and b/apps/website/e2e/visual-responsive.spec.ts-snapshots/pricing-tiers-4-xl-visual-linux.png differ diff --git a/apps/website/src/components/common/SiteNav.vue b/apps/website/src/components/common/SiteNav.vue index b7165da498..5e5c3e9b36 100644 --- a/apps/website/src/components/common/SiteNav.vue +++ b/apps/website/src/components/common/SiteNav.vue @@ -204,13 +204,12 @@ onMounted(() => { /> - - diff --git a/apps/website/src/components/product/enterprise/TeamSection.vue b/apps/website/src/components/product/enterprise/TeamSection.vue index 9305ea2cd6..f03f723ce9 100644 --- a/apps/website/src/components/product/enterprise/TeamSection.vue +++ b/apps/website/src/components/product/enterprise/TeamSection.vue @@ -21,17 +21,12 @@ const features = computed(() => [ { title: t('enterprise.team.feature2.title', locale), description: t('enterprise.team.feature2.description', locale), - image: 'https://media.comfy.org/website/enterprise/dark-fluid-texture.webp', - ctaText: t('enterprise.team.feature2.cta', locale), - ctaHref: routes.value.cloud + image: 'https://media.comfy.org/website/enterprise/dark-fluid-texture.webp' }, { title: t('enterprise.team.feature3.title', locale), description: t('enterprise.team.feature3.description', locale), - image: - 'https://media.comfy.org/website/enterprise/isometric-interface.webp', - ctaText: t('enterprise.hero.contactSales', locale), - ctaHref: routes.value.contact + image: 'https://media.comfy.org/website/enterprise/isometric-interface.webp' } ]) diff --git a/apps/website/src/components/product/local/EcoSystemSection.vue b/apps/website/src/components/product/local/EcoSystemSection.vue index c5a2515daf..f9fac310bf 100644 --- a/apps/website/src/components/product/local/EcoSystemSection.vue +++ b/apps/website/src/components/product/local/EcoSystemSection.vue @@ -40,17 +40,16 @@ const { locale = 'en' } = defineProps<{ locale?: Locale }>() - -
-
- - 4x - -
+
+
diff --git a/apps/website/src/components/product/shared/ReasonSection.vue b/apps/website/src/components/product/shared/ReasonSection.vue index 3b1ce573b2..48426a4f9a 100644 --- a/apps/website/src/components/product/shared/ReasonSection.vue +++ b/apps/website/src/components/product/shared/ReasonSection.vue @@ -29,14 +29,14 @@ const {