From 1cb46d04c49bc5e3a1ba1583a2602e3f5baed183 Mon Sep 17 00:00:00 2001 From: Emir Karabeg Date: Sat, 13 Jun 2026 11:31:23 -0700 Subject: [PATCH 1/8] stash --- .agents/skills/add-model/SKILL.md | 2 +- .claude/commands/add-model.md | 2 +- .claude/rules/landing-seo-geo.md | 1 + apps/sim/app/(auth)/auth-layout-client.tsx | 2 +- .../(auth)/components/status-page-layout.tsx | 2 +- .../blog/[slug]/back-link.tsx | 0 .../blog/[slug]/loading.tsx | 0 .../blog/[slug]/page.tsx | 4 +- .../blog/[slug]/share-button.tsx | 0 .../blog/authors/[id]/loading.tsx | 0 .../blog/authors/[id]/page.tsx | 0 .../blog/components/blog-image.tsx | 2 +- .../blog/components/lightbox.tsx | 0 .../app/{(landing) => (home)}/blog/layout.tsx | 6 +- .../{(landing) => (home)}/blog/loading.tsx | 0 .../app/{(landing) => (home)}/blog/page.tsx | 0 .../blog/rss.xml/route.ts | 0 .../blog/sitemap-images.xml/route.ts | 0 .../blog/tags/loading.tsx | 0 .../{(landing) => (home)}/blog/tags/page.tsx | 0 .../components/auth-modal/auth-modal.tsx | 0 .../collaboration/collaboration.tsx | 4 +- .../components/contact/contact-form.tsx | 2 +- .../demo-request/demo-request-modal.tsx | 2 +- .../components/external-redirect.tsx | 0 .../features/components/features-preview.tsx | 0 .../(home)/components/features/features.tsx | 310 ++++++++++ .../components/footer/footer-cta.tsx | 6 +- .../app/(home)/components/footer/footer.tsx | 225 +++++++ .../components/forms/landing-field.tsx | 0 apps/sim/app/(home)/components/hero/hero.tsx | 127 ++++ apps/sim/app/(home)/components/index.ts | 25 + .../components/landing-faq.tsx | 0 .../landing-preview-files.tsx | 4 +- .../landing-preview-home.tsx | 4 +- .../landing-preview-knowledge.tsx | 4 +- .../landing-preview-logs.tsx | 0 .../landing-preview-panel.tsx | 6 +- .../landing-preview-resource.tsx | 0 .../landing-preview-scheduled-tasks.tsx | 4 +- .../landing-preview-sidebar.tsx | 2 +- .../landing-preview-tables.tsx | 4 +- .../landing-preview-workflow.tsx | 4 +- .../preview-block-node.tsx | 2 +- .../landing-preview-workflow/workflow-data.ts | 0 .../landing-preview/landing-preview.tsx | 22 +- .../components/legal-layout.tsx | 4 +- .../navbar/components/blog-dropdown.tsx | 0 .../navbar/components/docs-dropdown.tsx | 0 .../navbar/components/github-stars.tsx | 0 .../app/(home)/components/navbar/navbar.tsx | 503 ++++++++++++++++ .../components/not-found-view.tsx | 2 +- .../components/pricing/pricing.tsx | 6 +- .../components/scroll-to-top.tsx | 0 .../components/structured-data.tsx | 0 .../templates/template-workflows.ts | 2 +- .../components/templates/templates.tsx | 6 +- .../components/testimonials/testimonials.tsx | 18 + .../{(landing) => (home)}/contact/page.tsx | 6 +- .../components/integration-cta-button.tsx | 4 +- .../[slug]/components/integration-faq.tsx | 2 +- .../components/template-card-button.tsx | 2 +- .../integrations/(shell)/[slug]/loading.tsx | 0 .../(shell)/[slug]/opengraph-image.tsx | 2 +- .../integrations/(shell)/[slug]/page.tsx | 8 +- .../integrations/(shell)/layout.tsx | 6 +- .../integrations/(shell)/opengraph-image.tsx | 2 +- .../integrations/(shell)/page.tsx | 8 +- .../integrations/[slug]/loading.tsx | 0 .../components/integration-card.tsx | 4 +- .../components/integration-grid.tsx | 2 +- .../components/integration-icon.tsx | 0 .../components/request-integration-modal.tsx | 0 .../integrations/data/landing-content.ts | 2 +- .../integrations/data/types.ts | 0 .../integrations/not-found.tsx | 2 +- .../landing-analytics.tsx | 0 apps/sim/app/(home)/landing.tsx | 74 +++ apps/sim/app/{(landing) => (home)}/layout.tsx | 0 .../(shell)/[provider]/[model]/loading.tsx | 0 .../[provider]/[model]/opengraph-image.tsx | 4 +- .../(shell)/[provider]/[model]/page.tsx | 6 +- .../models/(shell)/[provider]/loading.tsx | 0 .../(shell)/[provider]/opengraph-image.tsx | 4 +- .../models/(shell)/[provider]/page.tsx | 8 +- .../models/(shell)/layout.tsx | 6 +- .../models/(shell)/opengraph-image.tsx | 4 +- .../models/(shell)/page.tsx | 10 +- .../models/[provider]/[model]/loading.tsx | 0 .../models/[provider]/loading.tsx | 0 .../models/components/consts.ts | 2 +- .../components/model-comparison-charts.tsx | 10 +- .../models/components/model-directory.tsx | 4 +- .../models/components/model-primitives.tsx | 2 +- .../components/model-timeline-chart.tsx | 4 +- .../models/not-found.tsx | 2 +- .../models/utils.test.ts | 0 .../app/{(landing) => (home)}/models/utils.ts | 0 .../app/{(landing) => (home)}/og-utils.tsx | 0 .../{(landing) => (home)}/partners/page.tsx | 4 +- .../{(landing) => (home)}/privacy/loading.tsx | 0 .../{(landing) => (home)}/privacy/page.tsx | 2 +- .../sim/app/{(landing) => (home)}/seo.test.ts | 3 +- .../{(landing) => (home)}/terms/loading.tsx | 0 .../app/{(landing) => (home)}/terms/page.tsx | 2 +- apps/sim/app/(landing)/CLAUDE.md | 94 +++ .../components/features/features.tsx | 348 ++--------- .../(landing)/components/footer/footer.tsx | 230 +------ .../hero-visual/hero-visual.module.css | 152 +++++ .../components/hero-visual/hero-visual.tsx | 322 ++++++++++ .../components/hero-visual/stage-home.tsx | 76 +++ .../hero/components/hero-visual/stage-kb.tsx | 160 +++++ .../components/hero-visual/stage-workflow.tsx | 83 +++ .../components/hero-visual/workflow-block.tsx | 71 +++ .../components/hero-visual/workflow-data.ts | 253 ++++++++ .../components/hero/components/logos.tsx | 77 +++ .../app/(landing)/components/hero/hero.tsx | 222 +++---- apps/sim/app/(landing)/components/index.ts | 31 +- .../lifecycle/components/lifecycle-icons.tsx | 128 ++++ .../components/lifecycle/lifecycle.tsx | 78 +++ .../navbar/components/github-chip.tsx | 30 + .../navbar/components/nav-menu-chip.tsx | 20 + .../navbar/components/navbar-shell.tsx | 58 ++ .../navbar/components/sim-wordmark.tsx | 29 + .../(landing)/components/navbar/navbar.tsx | 560 ++---------------- .../components/testimonials/testimonials.tsx | 16 +- apps/sim/app/(landing)/landing.tsx | 86 +-- apps/sim/app/{ => (landing)}/page.tsx | 12 - apps/sim/app/academy/(catalog)/layout.tsx | 4 +- apps/sim/app/api/stars/route.ts | 44 +- apps/sim/app/changelog/layout.tsx | 4 +- .../chat/components/auth/email/email-auth.tsx | 2 +- .../auth/password/password-auth.tsx | 2 +- apps/sim/app/invite/components/layout.tsx | 2 +- apps/sim/app/not-found.tsx | 2 +- .../[executionId]/resume-page-client.tsx | 2 +- apps/sim/app/sitemap.ts | 4 +- .../emcn/components/chip/chip-chrome.ts | 9 + .../components/emcn/components/chip/chip.tsx | 4 +- apps/sim/components/emcn/components/index.ts | 1 + apps/sim/ee/sso/components/sso-auth.tsx | 2 +- apps/sim/lib/blog/mdx.tsx | 2 +- apps/sim/lib/github/stars.ts | 50 ++ apps/sim/lib/integrations/landing-content.ts | 2 +- apps/sim/lib/integrations/types.ts | 2 +- apps/sim/public/landing/logos/artie.svg | 16 + apps/sim/public/landing/logos/exp-realty.svg | 61 ++ .../public/landing/logos/mobile-health.svg | 67 +++ apps/sim/public/landing/logos/rivian-vw.svg | 217 +++++++ .../landing/logos/russell-investments.svg | 22 + apps/sim/public/landing/logos/volvo.svg | 55 ++ scripts/generate-docs.ts | 5 +- 152 files changed, 3818 insertions(+), 1419 deletions(-) rename apps/sim/app/{(landing) => (home)}/blog/[slug]/back-link.tsx (100%) rename apps/sim/app/{(landing) => (home)}/blog/[slug]/loading.tsx (100%) rename apps/sim/app/{(landing) => (home)}/blog/[slug]/page.tsx (98%) rename apps/sim/app/{(landing) => (home)}/blog/[slug]/share-button.tsx (100%) rename apps/sim/app/{(landing) => (home)}/blog/authors/[id]/loading.tsx (100%) rename apps/sim/app/{(landing) => (home)}/blog/authors/[id]/page.tsx (100%) rename apps/sim/app/{(landing) => (home)}/blog/components/blog-image.tsx (93%) rename apps/sim/app/{(landing) => (home)}/blog/components/lightbox.tsx (100%) rename apps/sim/app/{(landing) => (home)}/blog/layout.tsx (87%) rename apps/sim/app/{(landing) => (home)}/blog/loading.tsx (100%) rename apps/sim/app/{(landing) => (home)}/blog/page.tsx (100%) rename apps/sim/app/{(landing) => (home)}/blog/rss.xml/route.ts (100%) rename apps/sim/app/{(landing) => (home)}/blog/sitemap-images.xml/route.ts (100%) rename apps/sim/app/{(landing) => (home)}/blog/tags/loading.tsx (100%) rename apps/sim/app/{(landing) => (home)}/blog/tags/page.tsx (100%) rename apps/sim/app/{(landing) => (home)}/components/auth-modal/auth-modal.tsx (100%) rename apps/sim/app/{(landing) => (home)}/components/collaboration/collaboration.tsx (98%) rename apps/sim/app/{(landing) => (home)}/components/contact/contact-form.tsx (99%) rename apps/sim/app/{(landing) => (home)}/components/demo-request/demo-request-modal.tsx (99%) rename apps/sim/app/{(landing) => (home)}/components/external-redirect.tsx (100%) rename apps/sim/app/{(landing) => (home)}/components/features/components/features-preview.tsx (100%) create mode 100644 apps/sim/app/(home)/components/features/features.tsx rename apps/sim/app/{(landing) => (home)}/components/footer/footer-cta.tsx (94%) create mode 100644 apps/sim/app/(home)/components/footer/footer.tsx rename apps/sim/app/{(landing) => (home)}/components/forms/landing-field.tsx (100%) create mode 100644 apps/sim/app/(home)/components/hero/hero.tsx create mode 100644 apps/sim/app/(home)/components/index.ts rename apps/sim/app/{(landing) => (home)}/components/landing-faq.tsx (100%) rename apps/sim/app/{(landing) => (home)}/components/landing-preview/components/landing-preview-files/landing-preview-files.tsx (94%) rename apps/sim/app/{(landing) => (home)}/components/landing-preview/components/landing-preview-home/landing-preview-home.tsx (98%) rename apps/sim/app/{(landing) => (home)}/components/landing-preview/components/landing-preview-knowledge/landing-preview-knowledge.tsx (90%) rename apps/sim/app/{(landing) => (home)}/components/landing-preview/components/landing-preview-logs/landing-preview-logs.tsx (100%) rename apps/sim/app/{(landing) => (home)}/components/landing-preview/components/landing-preview-panel/landing-preview-panel.tsx (98%) rename apps/sim/app/{(landing) => (home)}/components/landing-preview/components/landing-preview-resource/landing-preview-resource.tsx (100%) rename apps/sim/app/{(landing) => (home)}/components/landing-preview/components/landing-preview-scheduled-tasks/landing-preview-scheduled-tasks.tsx (89%) rename apps/sim/app/{(landing) => (home)}/components/landing-preview/components/landing-preview-sidebar/landing-preview-sidebar.tsx (98%) rename apps/sim/app/{(landing) => (home)}/components/landing-preview/components/landing-preview-tables/landing-preview-tables.tsx (98%) rename apps/sim/app/{(landing) => (home)}/components/landing-preview/components/landing-preview-workflow/landing-preview-workflow.tsx (95%) rename apps/sim/app/{(landing) => (home)}/components/landing-preview/components/landing-preview-workflow/preview-block-node.tsx (99%) rename apps/sim/app/{(landing) => (home)}/components/landing-preview/components/landing-preview-workflow/workflow-data.ts (100%) rename apps/sim/app/{(landing) => (home)}/components/landing-preview/landing-preview.tsx (86%) rename apps/sim/app/{(landing) => (home)}/components/legal-layout.tsx (90%) rename apps/sim/app/{(landing) => (home)}/components/navbar/components/blog-dropdown.tsx (100%) rename apps/sim/app/{(landing) => (home)}/components/navbar/components/docs-dropdown.tsx (100%) rename apps/sim/app/{(landing) => (home)}/components/navbar/components/github-stars.tsx (100%) create mode 100644 apps/sim/app/(home)/components/navbar/navbar.tsx rename apps/sim/app/{(landing) => (home)}/components/not-found-view.tsx (96%) rename apps/sim/app/{(landing) => (home)}/components/pricing/pricing.tsx (97%) rename apps/sim/app/{(landing) => (home)}/components/scroll-to-top.tsx (100%) rename apps/sim/app/{(landing) => (home)}/components/structured-data.tsx (100%) rename apps/sim/app/{(landing) => (home)}/components/templates/template-workflows.ts (99%) rename apps/sim/app/{(landing) => (home)}/components/templates/templates.tsx (98%) create mode 100644 apps/sim/app/(home)/components/testimonials/testimonials.tsx rename apps/sim/app/{(landing) => (home)}/contact/page.tsx (89%) rename apps/sim/app/{(landing) => (home)}/integrations/(shell)/[slug]/components/integration-cta-button.tsx (78%) rename apps/sim/app/{(landing) => (home)}/integrations/(shell)/[slug]/components/integration-faq.tsx (75%) rename apps/sim/app/{(landing) => (home)}/integrations/(shell)/[slug]/components/template-card-button.tsx (94%) rename apps/sim/app/{(landing) => (home)}/integrations/(shell)/[slug]/loading.tsx (100%) rename apps/sim/app/{(landing) => (home)}/integrations/(shell)/[slug]/opengraph-image.tsx (95%) rename apps/sim/app/{(landing) => (home)}/integrations/(shell)/[slug]/page.tsx (99%) rename apps/sim/app/{(landing) => (home)}/integrations/(shell)/layout.tsx (87%) rename apps/sim/app/{(landing) => (home)}/integrations/(shell)/opengraph-image.tsx (94%) rename apps/sim/app/{(landing) => (home)}/integrations/(shell)/page.tsx (96%) rename apps/sim/app/{(landing) => (home)}/integrations/[slug]/loading.tsx (100%) rename apps/sim/app/{(landing) => (home)}/integrations/components/integration-card.tsx (93%) rename apps/sim/app/{(landing) => (home)}/integrations/components/integration-grid.tsx (97%) rename apps/sim/app/{(landing) => (home)}/integrations/components/integration-icon.tsx (100%) rename apps/sim/app/{(landing) => (home)}/integrations/components/request-integration-modal.tsx (100%) rename apps/sim/app/{(landing) => (home)}/integrations/data/landing-content.ts (95%) rename apps/sim/app/{(landing) => (home)}/integrations/data/types.ts (100%) rename apps/sim/app/{(landing) => (home)}/integrations/not-found.tsx (76%) rename apps/sim/app/{(landing) => (home)}/landing-analytics.tsx (100%) create mode 100644 apps/sim/app/(home)/landing.tsx rename apps/sim/app/{(landing) => (home)}/layout.tsx (100%) rename apps/sim/app/{(landing) => (home)}/models/(shell)/[provider]/[model]/loading.tsx (100%) rename apps/sim/app/{(landing) => (home)}/models/(shell)/[provider]/[model]/opengraph-image.tsx (91%) rename apps/sim/app/{(landing) => (home)}/models/(shell)/[provider]/[model]/page.tsx (98%) rename apps/sim/app/{(landing) => (home)}/models/(shell)/[provider]/loading.tsx (100%) rename apps/sim/app/{(landing) => (home)}/models/(shell)/[provider]/opengraph-image.tsx (92%) rename apps/sim/app/{(landing) => (home)}/models/(shell)/[provider]/page.tsx (97%) rename apps/sim/app/{(landing) => (home)}/models/(shell)/layout.tsx (85%) rename apps/sim/app/{(landing) => (home)}/models/(shell)/opengraph-image.tsx (86%) rename apps/sim/app/{(landing) => (home)}/models/(shell)/page.tsx (96%) rename apps/sim/app/{(landing) => (home)}/models/[provider]/[model]/loading.tsx (100%) rename apps/sim/app/{(landing) => (home)}/models/[provider]/loading.tsx (100%) rename apps/sim/app/{(landing) => (home)}/models/components/consts.ts (76%) rename apps/sim/app/{(landing) => (home)}/models/components/model-comparison-charts.tsx (96%) rename apps/sim/app/{(landing) => (home)}/models/components/model-directory.tsx (98%) rename apps/sim/app/{(landing) => (home)}/models/components/model-primitives.tsx (99%) rename apps/sim/app/{(landing) => (home)}/models/components/model-timeline-chart.tsx (97%) rename apps/sim/app/{(landing) => (home)}/models/not-found.tsx (75%) rename apps/sim/app/{(landing) => (home)}/models/utils.test.ts (100%) rename apps/sim/app/{(landing) => (home)}/models/utils.ts (100%) rename apps/sim/app/{(landing) => (home)}/og-utils.tsx (100%) rename apps/sim/app/{(landing) => (home)}/partners/page.tsx (98%) rename apps/sim/app/{(landing) => (home)}/privacy/loading.tsx (100%) rename apps/sim/app/{(landing) => (home)}/privacy/page.tsx (99%) rename apps/sim/app/{(landing) => (home)}/seo.test.ts (98%) rename apps/sim/app/{(landing) => (home)}/terms/loading.tsx (100%) rename apps/sim/app/{(landing) => (home)}/terms/page.tsx (99%) create mode 100644 apps/sim/app/(landing)/CLAUDE.md create mode 100644 apps/sim/app/(landing)/components/hero/components/hero-visual/hero-visual.module.css create mode 100644 apps/sim/app/(landing)/components/hero/components/hero-visual/hero-visual.tsx create mode 100644 apps/sim/app/(landing)/components/hero/components/hero-visual/stage-home.tsx create mode 100644 apps/sim/app/(landing)/components/hero/components/hero-visual/stage-kb.tsx create mode 100644 apps/sim/app/(landing)/components/hero/components/hero-visual/stage-workflow.tsx create mode 100644 apps/sim/app/(landing)/components/hero/components/hero-visual/workflow-block.tsx create mode 100644 apps/sim/app/(landing)/components/hero/components/hero-visual/workflow-data.ts create mode 100644 apps/sim/app/(landing)/components/hero/components/logos.tsx create mode 100644 apps/sim/app/(landing)/components/lifecycle/components/lifecycle-icons.tsx create mode 100644 apps/sim/app/(landing)/components/lifecycle/lifecycle.tsx create mode 100644 apps/sim/app/(landing)/components/navbar/components/github-chip.tsx create mode 100644 apps/sim/app/(landing)/components/navbar/components/nav-menu-chip.tsx create mode 100644 apps/sim/app/(landing)/components/navbar/components/navbar-shell.tsx create mode 100644 apps/sim/app/(landing)/components/navbar/components/sim-wordmark.tsx rename apps/sim/app/{ => (landing)}/page.tsx (79%) create mode 100644 apps/sim/lib/github/stars.ts create mode 100644 apps/sim/public/landing/logos/artie.svg create mode 100644 apps/sim/public/landing/logos/exp-realty.svg create mode 100644 apps/sim/public/landing/logos/mobile-health.svg create mode 100644 apps/sim/public/landing/logos/rivian-vw.svg create mode 100644 apps/sim/public/landing/logos/russell-investments.svg create mode 100644 apps/sim/public/landing/logos/volvo.svg diff --git a/.agents/skills/add-model/SKILL.md b/.agents/skills/add-model/SKILL.md index f97c966e1f3..b03ed269707 100644 --- a/.agents/skills/add-model/SKILL.md +++ b/.agents/skills/add-model/SKILL.md @@ -106,7 +106,7 @@ Within a family, newest first (matches existing convention: GPT-5.5 above GPT-5. ## Step 4: Repo-side touchpoints beyond the entry -Adding the `models.ts` entry is most of the job because nearly every consumer is **data-driven** and picks the model up automatically: the ~40 query helpers in `models.ts` / `providers/utils.ts`, the public `/models` catalog (`app/(landing)/models/utils.ts` iterates `PROVIDER_DEFINITIONS`), the agent-block model dropdown, and copilot's `isKnownModelId` / `suggestModelIdsForUnknownModel` validation. The touchpoints below are the exceptions — they are **not** data-driven, so check each one. +Adding the `models.ts` entry is most of the job because nearly every consumer is **data-driven** and picks the model up automatically: the ~40 query helpers in `models.ts` / `providers/utils.ts`, the public `/models` catalog (`app/(home)/models/utils.ts` iterates `PROVIDER_DEFINITIONS`), the agent-block model dropdown, and copilot's `isKnownModelId` / `suggestModelIdsForUnknownModel` validation. The touchpoints below are the exceptions — they are **not** data-driven, so check each one. ### Hosted = auto-billed, by provider diff --git a/.claude/commands/add-model.md b/.claude/commands/add-model.md index c52e1b451f9..31c80162050 100644 --- a/.claude/commands/add-model.md +++ b/.claude/commands/add-model.md @@ -106,7 +106,7 @@ Within a family, newest first (matches existing convention: GPT-5.5 above GPT-5. ## Step 4: Repo-side touchpoints beyond the entry -Adding the `models.ts` entry is most of the job because nearly every consumer is **data-driven** and picks the model up automatically: the ~40 query helpers in `models.ts` / `providers/utils.ts`, the public `/models` catalog (`app/(landing)/models/utils.ts` iterates `PROVIDER_DEFINITIONS`), the agent-block model dropdown, and copilot's `isKnownModelId` / `suggestModelIdsForUnknownModel` validation. The touchpoints below are the exceptions — they are **not** data-driven, so check each one. +Adding the `models.ts` entry is most of the job because nearly every consumer is **data-driven** and picks the model up automatically: the ~40 query helpers in `models.ts` / `providers/utils.ts`, the public `/models` catalog (`app/(home)/models/utils.ts` iterates `PROVIDER_DEFINITIONS`), the agent-block model dropdown, and copilot's `isKnownModelId` / `suggestModelIdsForUnknownModel` validation. The touchpoints below are the exceptions — they are **not** data-driven, so check each one. ### Hosted = auto-billed, by provider diff --git a/.claude/rules/landing-seo-geo.md b/.claude/rules/landing-seo-geo.md index b29af45a31e..af87a71aa05 100644 --- a/.claude/rules/landing-seo-geo.md +++ b/.claude/rules/landing-seo-geo.md @@ -1,6 +1,7 @@ --- paths: - "apps/sim/app/(landing)/**/*.tsx" + - "apps/sim/app/(home)/**/*.tsx" --- # Landing Page — SEO / GEO diff --git a/apps/sim/app/(auth)/auth-layout-client.tsx b/apps/sim/app/(auth)/auth-layout-client.tsx index 89aeb3a89e7..3aee420922f 100644 --- a/apps/sim/app/(auth)/auth-layout-client.tsx +++ b/apps/sim/app/(auth)/auth-layout-client.tsx @@ -2,7 +2,7 @@ import { useEffect } from 'react' import AuthBackground from '@/app/(auth)/components/auth-background' -import Navbar from '@/app/(landing)/components/navbar/navbar' +import Navbar from '@/app/(home)/components/navbar/navbar' export default function AuthLayoutClient({ children }: { children: React.ReactNode }) { useEffect(() => { diff --git a/apps/sim/app/(auth)/components/status-page-layout.tsx b/apps/sim/app/(auth)/components/status-page-layout.tsx index b26def8d71a..417c5a582da 100644 --- a/apps/sim/app/(auth)/components/status-page-layout.tsx +++ b/apps/sim/app/(auth)/components/status-page-layout.tsx @@ -1,6 +1,6 @@ import type { ReactNode } from 'react' import AuthBackground from '@/app/(auth)/components/auth-background' -import Navbar from '@/app/(landing)/components/navbar/navbar' +import Navbar from '@/app/(home)/components/navbar/navbar' import { SupportFooter } from './support-footer' export interface StatusPageLayoutProps { diff --git a/apps/sim/app/(landing)/blog/[slug]/back-link.tsx b/apps/sim/app/(home)/blog/[slug]/back-link.tsx similarity index 100% rename from apps/sim/app/(landing)/blog/[slug]/back-link.tsx rename to apps/sim/app/(home)/blog/[slug]/back-link.tsx diff --git a/apps/sim/app/(landing)/blog/[slug]/loading.tsx b/apps/sim/app/(home)/blog/[slug]/loading.tsx similarity index 100% rename from apps/sim/app/(landing)/blog/[slug]/loading.tsx rename to apps/sim/app/(home)/blog/[slug]/loading.tsx diff --git a/apps/sim/app/(landing)/blog/[slug]/page.tsx b/apps/sim/app/(home)/blog/[slug]/page.tsx similarity index 98% rename from apps/sim/app/(landing)/blog/[slug]/page.tsx rename to apps/sim/app/(home)/blog/[slug]/page.tsx index cce6ee8dfb4..74527188e31 100644 --- a/apps/sim/app/(landing)/blog/[slug]/page.tsx +++ b/apps/sim/app/(home)/blog/[slug]/page.tsx @@ -6,8 +6,8 @@ import { FAQ } from '@/lib/blog/faq' import { getAllPostMeta, getPostBySlug, getRelatedPosts } from '@/lib/blog/registry' import { buildPostGraphJsonLd, buildPostMetadata } from '@/lib/blog/seo' import { getBaseUrl } from '@/lib/core/utils/urls' -import { BackLink } from '@/app/(landing)/blog/[slug]/back-link' -import { ShareButton } from '@/app/(landing)/blog/[slug]/share-button' +import { BackLink } from '@/app/(home)/blog/[slug]/back-link' +import { ShareButton } from '@/app/(home)/blog/[slug]/share-button' export const dynamicParams = false diff --git a/apps/sim/app/(landing)/blog/[slug]/share-button.tsx b/apps/sim/app/(home)/blog/[slug]/share-button.tsx similarity index 100% rename from apps/sim/app/(landing)/blog/[slug]/share-button.tsx rename to apps/sim/app/(home)/blog/[slug]/share-button.tsx diff --git a/apps/sim/app/(landing)/blog/authors/[id]/loading.tsx b/apps/sim/app/(home)/blog/authors/[id]/loading.tsx similarity index 100% rename from apps/sim/app/(landing)/blog/authors/[id]/loading.tsx rename to apps/sim/app/(home)/blog/authors/[id]/loading.tsx diff --git a/apps/sim/app/(landing)/blog/authors/[id]/page.tsx b/apps/sim/app/(home)/blog/authors/[id]/page.tsx similarity index 100% rename from apps/sim/app/(landing)/blog/authors/[id]/page.tsx rename to apps/sim/app/(home)/blog/authors/[id]/page.tsx diff --git a/apps/sim/app/(landing)/blog/components/blog-image.tsx b/apps/sim/app/(home)/blog/components/blog-image.tsx similarity index 93% rename from apps/sim/app/(landing)/blog/components/blog-image.tsx rename to apps/sim/app/(home)/blog/components/blog-image.tsx index 84be2e6b2f5..5a1d215fe92 100644 --- a/apps/sim/app/(landing)/blog/components/blog-image.tsx +++ b/apps/sim/app/(home)/blog/components/blog-image.tsx @@ -3,7 +3,7 @@ import { useState } from 'react' import NextImage from 'next/image' import { cn } from '@/lib/core/utils/cn' -import { Lightbox } from '@/app/(landing)/blog/components/lightbox' +import { Lightbox } from '@/app/(home)/blog/components/lightbox' interface BlogImageProps { src: string diff --git a/apps/sim/app/(landing)/blog/components/lightbox.tsx b/apps/sim/app/(home)/blog/components/lightbox.tsx similarity index 100% rename from apps/sim/app/(landing)/blog/components/lightbox.tsx rename to apps/sim/app/(home)/blog/components/lightbox.tsx diff --git a/apps/sim/app/(landing)/blog/layout.tsx b/apps/sim/app/(home)/blog/layout.tsx similarity index 87% rename from apps/sim/app/(landing)/blog/layout.tsx rename to apps/sim/app/(home)/blog/layout.tsx index a82cb763a4e..6eb35c53c82 100644 --- a/apps/sim/app/(landing)/blog/layout.tsx +++ b/apps/sim/app/(home)/blog/layout.tsx @@ -1,8 +1,8 @@ import { getNavBlogPosts } from '@/lib/blog/registry' import { SITE_URL } from '@/lib/core/utils/urls' -import Footer from '@/app/(landing)/components/footer/footer' -import Navbar from '@/app/(landing)/components/navbar/navbar' -import { ScrollToTop } from '@/app/(landing)/components/scroll-to-top' +import Footer from '@/app/(home)/components/footer/footer' +import Navbar from '@/app/(home)/components/navbar/navbar' +import { ScrollToTop } from '@/app/(home)/components/scroll-to-top' export default async function StudioLayout({ children }: { children: React.ReactNode }) { const blogPosts = await getNavBlogPosts() diff --git a/apps/sim/app/(landing)/blog/loading.tsx b/apps/sim/app/(home)/blog/loading.tsx similarity index 100% rename from apps/sim/app/(landing)/blog/loading.tsx rename to apps/sim/app/(home)/blog/loading.tsx diff --git a/apps/sim/app/(landing)/blog/page.tsx b/apps/sim/app/(home)/blog/page.tsx similarity index 100% rename from apps/sim/app/(landing)/blog/page.tsx rename to apps/sim/app/(home)/blog/page.tsx diff --git a/apps/sim/app/(landing)/blog/rss.xml/route.ts b/apps/sim/app/(home)/blog/rss.xml/route.ts similarity index 100% rename from apps/sim/app/(landing)/blog/rss.xml/route.ts rename to apps/sim/app/(home)/blog/rss.xml/route.ts diff --git a/apps/sim/app/(landing)/blog/sitemap-images.xml/route.ts b/apps/sim/app/(home)/blog/sitemap-images.xml/route.ts similarity index 100% rename from apps/sim/app/(landing)/blog/sitemap-images.xml/route.ts rename to apps/sim/app/(home)/blog/sitemap-images.xml/route.ts diff --git a/apps/sim/app/(landing)/blog/tags/loading.tsx b/apps/sim/app/(home)/blog/tags/loading.tsx similarity index 100% rename from apps/sim/app/(landing)/blog/tags/loading.tsx rename to apps/sim/app/(home)/blog/tags/loading.tsx diff --git a/apps/sim/app/(landing)/blog/tags/page.tsx b/apps/sim/app/(home)/blog/tags/page.tsx similarity index 100% rename from apps/sim/app/(landing)/blog/tags/page.tsx rename to apps/sim/app/(home)/blog/tags/page.tsx diff --git a/apps/sim/app/(landing)/components/auth-modal/auth-modal.tsx b/apps/sim/app/(home)/components/auth-modal/auth-modal.tsx similarity index 100% rename from apps/sim/app/(landing)/components/auth-modal/auth-modal.tsx rename to apps/sim/app/(home)/components/auth-modal/auth-modal.tsx diff --git a/apps/sim/app/(landing)/components/collaboration/collaboration.tsx b/apps/sim/app/(home)/components/collaboration/collaboration.tsx similarity index 98% rename from apps/sim/app/(landing)/components/collaboration/collaboration.tsx rename to apps/sim/app/(home)/components/collaboration/collaboration.tsx index 2667c14a3df..15e57d68bce 100644 --- a/apps/sim/app/(landing)/components/collaboration/collaboration.tsx +++ b/apps/sim/app/(home)/components/collaboration/collaboration.tsx @@ -5,10 +5,10 @@ import dynamic from 'next/dynamic' import Image from 'next/image' import Link from 'next/link' import { Badge } from '@/components/emcn' -import { trackLandingCta } from '@/app/(landing)/landing-analytics' +import { trackLandingCta } from '@/app/(home)/landing-analytics' const AuthModal = dynamic( - () => import('@/app/(landing)/components/auth-modal/auth-modal').then((m) => m.AuthModal), + () => import('@/app/(home)/components/auth-modal/auth-modal').then((m) => m.AuthModal), { loading: () => null } ) diff --git a/apps/sim/app/(landing)/components/contact/contact-form.tsx b/apps/sim/app/(home)/components/contact/contact-form.tsx similarity index 99% rename from apps/sim/app/(landing)/components/contact/contact-form.tsx rename to apps/sim/app/(home)/components/contact/contact-form.tsx index 9474c9b9ab2..d3ea78d219c 100644 --- a/apps/sim/app/(landing)/components/contact/contact-form.tsx +++ b/apps/sim/app/(home)/components/contact/contact-form.tsx @@ -18,7 +18,7 @@ import { import { flattenFieldErrors } from '@/lib/api/contracts/primitives' import { getEnv } from '@/lib/core/config/env' import { captureClientEvent } from '@/lib/posthog/client' -import { LandingField } from '@/app/(landing)/components/forms/landing-field' +import { LandingField } from '@/app/(home)/components/forms/landing-field' type ContactField = keyof ContactRequestPayload type ContactErrors = Partial> diff --git a/apps/sim/app/(landing)/components/demo-request/demo-request-modal.tsx b/apps/sim/app/(home)/components/demo-request/demo-request-modal.tsx similarity index 99% rename from apps/sim/app/(landing)/components/demo-request/demo-request-modal.tsx rename to apps/sim/app/(home)/components/demo-request/demo-request-modal.tsx index 3c254742348..9dcb9e72778 100644 --- a/apps/sim/app/(landing)/components/demo-request/demo-request-modal.tsx +++ b/apps/sim/app/(home)/components/demo-request/demo-request-modal.tsx @@ -24,7 +24,7 @@ import { } from '@/lib/api/contracts/demo-requests' import { flattenFieldErrors } from '@/lib/api/contracts/primitives' import { captureClientEvent } from '@/lib/posthog/client' -import { LandingField } from '@/app/(landing)/components/forms/landing-field' +import { LandingField } from '@/app/(home)/components/forms/landing-field' interface DemoRequestModalProps { children: React.ReactNode diff --git a/apps/sim/app/(landing)/components/external-redirect.tsx b/apps/sim/app/(home)/components/external-redirect.tsx similarity index 100% rename from apps/sim/app/(landing)/components/external-redirect.tsx rename to apps/sim/app/(home)/components/external-redirect.tsx diff --git a/apps/sim/app/(landing)/components/features/components/features-preview.tsx b/apps/sim/app/(home)/components/features/components/features-preview.tsx similarity index 100% rename from apps/sim/app/(landing)/components/features/components/features-preview.tsx rename to apps/sim/app/(home)/components/features/components/features-preview.tsx diff --git a/apps/sim/app/(home)/components/features/features.tsx b/apps/sim/app/(home)/components/features/features.tsx new file mode 100644 index 00000000000..c86d36a197a --- /dev/null +++ b/apps/sim/app/(home)/components/features/features.tsx @@ -0,0 +1,310 @@ +'use client' + +import { useRef, useState } from 'react' +import { + domAnimation, + LazyMotion, + type MotionValue, + m, + useScroll, + useTransform, +} from 'framer-motion' +import dynamic from 'next/dynamic' +import Image from 'next/image' +import { Badge } from '@/components/emcn' +import { FeaturesPreview } from '@/app/(home)/components/features/components/features-preview' +import { trackLandingCta } from '@/app/(home)/landing-analytics' + +const AuthModal = dynamic( + () => import('@/app/(home)/components/auth-modal/auth-modal').then((m) => m.AuthModal), + { loading: () => null } +) + +function hexToRgba(hex: string, alpha: number): string { + const r = Number.parseInt(hex.slice(1, 3), 16) + const g = Number.parseInt(hex.slice(3, 5), 16) + const b = Number.parseInt(hex.slice(5, 7), 16) + return `rgba(${r},${g},${b},${alpha})` +} + +interface FeatureTab { + label: string + mobileLabel?: string + color: string + badgeColor?: string + title: string + description: string + cta: string + segments: number[][] + hideOnMobile?: boolean +} + +const FEATURE_TABS: FeatureTab[] = [ + { + label: 'Mothership', + color: '#FA4EDF', + title: 'Your AI command center', + description: + 'Direct your entire AI workforce from one place. Build agents, spin up workflows, query tables, and manage every resource across your workspace — in natural language.', + cta: 'Explore mothership', + segments: [ + [0.3, 8], + [0.25, 10], + [0.45, 12], + [0.5, 8], + [0.65, 10], + [0.8, 12], + [0.75, 8], + [0.95, 10], + [1, 12], + [0.85, 10], + ], + }, + { + label: 'Tables', + color: '#2ABBF8', + title: 'A database, built in', + description: + 'Filter, sort, and edit data inline, then wire it directly into your workflows. Agents query, insert, and update rows on every run — no external database needed.', + cta: 'Explore tables', + segments: [ + [0.25, 12], + [0.4, 10], + [0.35, 8], + [0.55, 12], + [0.7, 10], + [0.85, 8], + [1, 14], + [0.9, 12], + [1, 14], + ], + }, + { + label: 'Files', + color: '#FFCC02', + badgeColor: '#EAB308', + title: 'Upload, create, and share', + description: + 'Create or upload documents, spreadsheets, and media that agents can read, write, and reference across workflows. One shared store your entire team and every agent can pull from.', + cta: 'Explore files', + segments: [ + [0.25, 10], + [0.4, 8], + [0.35, 12], + [0.5, 10], + [0.65, 8], + [0.75, 10], + [0.9, 12], + [1, 10], + [0.85, 10], + [1, 10], + ], + }, + { + label: 'Logs', + hideOnMobile: true, + color: '#FF6B35', + title: 'Full visibility, every run', + description: + 'Trace every execution block by block — inputs, outputs, cost, and duration. Filter by status or workflow, replay snapshots, and export reports to keep your team accountable.', + cta: 'Explore logs', + segments: [ + [0.25, 10], + [0.35, 8], + [0.3, 10], + [0.5, 10], + [0.65, 8], + [0.8, 12], + [0.9, 10], + [1, 10], + [0.85, 12], + [1, 10], + ], + }, +] + +const HEADING_TEXT = 'One workspace to build, deploy, and manage AI agents. ' +const HEADING_LETTERS = HEADING_TEXT.split('') + +const LETTER_REVEAL_SPAN = 0.85 +const LETTER_FADE_IN = 0.04 + +interface ScrollLetterProps { + scrollYProgress: MotionValue + charIndex: number + children: string +} + +function ScrollLetter({ scrollYProgress, charIndex, children }: ScrollLetterProps) { + const threshold = (charIndex / HEADING_LETTERS.length) * LETTER_REVEAL_SPAN + const opacity = useTransform(scrollYProgress, [threshold, threshold + LETTER_FADE_IN], [0.4, 1]) + + return {children} +} + +export default function Features() { + const sectionRef = useRef(null) + const [activeTab, setActiveTab] = useState(0) + + const { scrollYProgress } = useScroll({ + target: sectionRef, + offset: ['start 0.9', 'start 0.2'], + }) + + return ( + +
+ + +
+
+ + Workspace + +

+ Sim's workspace includes four core features: Mothership, an AI command center for + natural-language control of your entire workspace; Tables, a built-in database for + filtering, sorting, and wiring data directly into workflows; Files, a shared document + store for uploading, creating, and sharing documents, spreadsheets, and media across + teams and agents; and Logs, full execution tracing with inputs, outputs, cost, and + duration for every run. +

+

+ {HEADING_LETTERS.map((char, i) => ( + + {char} + + ))} + + Build agents, connect your data, and monitor every run, all in one workspace. + +

+
+ +
+
+
+ ) +} diff --git a/apps/sim/app/(landing)/components/footer/footer-cta.tsx b/apps/sim/app/(home)/components/footer/footer-cta.tsx similarity index 94% rename from apps/sim/app/(landing)/components/footer/footer-cta.tsx rename to apps/sim/app/(home)/components/footer/footer-cta.tsx index 31355a75f35..aad04821707 100644 --- a/apps/sim/app/(landing)/components/footer/footer-cta.tsx +++ b/apps/sim/app/(home)/components/footer/footer-cta.tsx @@ -6,12 +6,12 @@ import dynamic from 'next/dynamic' import { cn } from '@/lib/core/utils/cn' import { handleKeyboardActivation } from '@/lib/core/utils/keyboard' import { captureClientEvent } from '@/lib/posthog/client' -import { useLandingSubmit } from '@/app/(landing)/components/landing-preview/components/landing-preview-panel/landing-preview-panel' -import { trackLandingCta } from '@/app/(landing)/landing-analytics' +import { useLandingSubmit } from '@/app/(home)/components/landing-preview/components/landing-preview-panel/landing-preview-panel' +import { trackLandingCta } from '@/app/(home)/landing-analytics' import { useAnimatedPlaceholder } from '@/hooks/use-animated-placeholder' const AuthModal = dynamic( - () => import('@/app/(landing)/components/auth-modal/auth-modal').then((m) => m.AuthModal), + () => import('@/app/(home)/components/auth-modal/auth-modal').then((m) => m.AuthModal), { loading: () => null } ) diff --git a/apps/sim/app/(home)/components/footer/footer.tsx b/apps/sim/app/(home)/components/footer/footer.tsx new file mode 100644 index 00000000000..dc8d578a2d2 --- /dev/null +++ b/apps/sim/app/(home)/components/footer/footer.tsx @@ -0,0 +1,225 @@ +import Image from 'next/image' +import Link from 'next/link' +import { cn } from '@/lib/core/utils/cn' +import { FooterCTA } from '@/app/(home)/components/footer/footer-cta' + +const LINK_CLASS = + 'text-sm text-[var(--landing-text-muted)] transition-colors hover:text-[var(--landing-text)]' + +interface FooterItem { + label: string + href: string + external?: boolean + externalArrow?: boolean +} + +const PRODUCT_LINKS: FooterItem[] = [ + { label: 'Mothership', href: 'https://docs.sim.ai/mothership', external: true }, + { label: 'Workflows', href: 'https://docs.sim.ai', external: true }, + { label: 'Knowledge Base', href: 'https://docs.sim.ai/knowledgebase', external: true }, + { label: 'Tables', href: 'https://docs.sim.ai/tables', external: true }, + { label: 'MCP', href: 'https://docs.sim.ai/agents/mcp', external: true }, + { label: 'API', href: 'https://docs.sim.ai/api-reference/getting-started', external: true }, + { label: 'Self Hosting', href: 'https://docs.sim.ai/platform/self-hosting', external: true }, + { label: 'Status', href: 'https://status.sim.ai', external: true, externalArrow: true }, +] + +const RESOURCES_LINKS: FooterItem[] = [ + { label: 'Blog', href: '/blog' }, + { label: 'Docs', href: 'https://docs.sim.ai', external: true }, + { label: 'Models', href: '/models' }, + { label: 'Partners', href: '/partners' }, + { label: 'Careers', href: 'https://jobs.ashbyhq.com/sim', external: true, externalArrow: true }, + { label: 'Changelog', href: '/changelog' }, + { label: 'Contact', href: '/contact' }, +] + +const BLOCK_LINKS: FooterItem[] = [ + { label: 'Agent', href: 'https://docs.sim.ai/workflows/blocks/agent', external: true }, + { label: 'Router', href: 'https://docs.sim.ai/workflows/blocks/router', external: true }, + { label: 'Function', href: 'https://docs.sim.ai/workflows/blocks/function', external: true }, + { label: 'Condition', href: 'https://docs.sim.ai/workflows/blocks/condition', external: true }, + { label: 'API Block', href: 'https://docs.sim.ai/workflows/blocks/api', external: true }, + { label: 'Workflow', href: 'https://docs.sim.ai/workflows/blocks/workflow', external: true }, + { label: 'Parallel', href: 'https://docs.sim.ai/workflows/blocks/parallel', external: true }, + { label: 'Guardrails', href: 'https://docs.sim.ai/workflows/blocks/guardrails', external: true }, + { label: 'Evaluator', href: 'https://docs.sim.ai/workflows/blocks/evaluator', external: true }, + { label: 'Loop', href: 'https://docs.sim.ai/workflows/blocks/loop', external: true }, +] + +const INTEGRATION_LINKS: FooterItem[] = [ + { label: 'All Integrations', href: '/integrations' }, + { label: 'Confluence', href: 'https://docs.sim.ai/integrations/confluence', external: true }, + { label: 'Slack', href: 'https://docs.sim.ai/integrations/slack', external: true }, + { label: 'GitHub', href: 'https://docs.sim.ai/integrations/github', external: true }, + { label: 'Gmail', href: 'https://docs.sim.ai/integrations/gmail', external: true }, + { label: 'HubSpot', href: 'https://docs.sim.ai/integrations/hubspot', external: true }, + { label: 'Salesforce', href: 'https://docs.sim.ai/integrations/salesforce', external: true }, + { label: 'Notion', href: 'https://docs.sim.ai/integrations/notion', external: true }, + { label: 'Google Drive', href: 'https://docs.sim.ai/integrations/google_drive', external: true }, + { + label: 'Google Sheets', + href: 'https://docs.sim.ai/integrations/google_sheets', + external: true, + }, + { label: 'Supabase', href: 'https://docs.sim.ai/integrations/supabase', external: true }, + { label: 'Stripe', href: 'https://docs.sim.ai/integrations/stripe', external: true }, + { label: 'Jira', href: 'https://docs.sim.ai/integrations/jira', external: true }, + { label: 'Linear', href: 'https://docs.sim.ai/integrations/linear', external: true }, + { label: 'Airtable', href: 'https://docs.sim.ai/integrations/airtable', external: true }, + { label: 'Firecrawl', href: 'https://docs.sim.ai/integrations/firecrawl', external: true }, + { label: 'Discord', href: 'https://docs.sim.ai/integrations/discord', external: true }, + { + label: 'Microsoft Teams', + href: 'https://docs.sim.ai/integrations/microsoft_teams', + external: true, + }, + { label: 'Telegram', href: 'https://docs.sim.ai/integrations/telegram', external: true }, +] + +const SOCIAL_LINKS: FooterItem[] = [ + { label: 'X (Twitter)', href: 'https://x.com/simdotai', external: true, externalArrow: true }, + { + label: 'LinkedIn', + href: 'https://www.linkedin.com/company/simstudioai/', + external: true, + externalArrow: true, + }, + { label: 'Discord', href: 'https://discord.gg/Hr4UWYEcTT', external: true, externalArrow: true }, + { + label: 'GitHub', + href: 'https://github.com/simstudioai/sim', + external: true, + externalArrow: true, + }, +] + +const LEGAL_LINKS: FooterItem[] = [ + { label: 'Terms of Service', href: '/terms' }, + { label: 'Privacy Policy', href: '/privacy' }, +] + +function ChevronArrow({ external }: { external?: boolean }) { + return ( + + + + + ) +} + +function FooterColumn({ title, items }: { title: string; items: FooterItem[] }) { + return ( +
+

{title}

+
+ {items.map(({ label, href, external, externalArrow }) => + external ? ( + + {label} + {externalArrow && } + + ) : ( + + {label} + + ) + )} +
+
+ ) +} + +interface FooterProps { + hideCTA?: boolean +} + +export default function Footer({ hideCTA }: FooterProps) { + return ( +
+ {!hideCTA && } +
+
+ ) +} diff --git a/apps/sim/app/(landing)/components/forms/landing-field.tsx b/apps/sim/app/(home)/components/forms/landing-field.tsx similarity index 100% rename from apps/sim/app/(landing)/components/forms/landing-field.tsx rename to apps/sim/app/(home)/components/forms/landing-field.tsx diff --git a/apps/sim/app/(home)/components/hero/hero.tsx b/apps/sim/app/(home)/components/hero/hero.tsx new file mode 100644 index 00000000000..8608ad9c869 --- /dev/null +++ b/apps/sim/app/(home)/components/hero/hero.tsx @@ -0,0 +1,127 @@ +'use client' + +import dynamic from 'next/dynamic' +import { cn } from '@/lib/core/utils/cn' +import { trackLandingCta } from '@/app/(home)/landing-analytics' + +const AuthModal = dynamic( + () => import('@/app/(home)/components/auth-modal/auth-modal').then((m) => m.AuthModal), + { loading: () => null } +) + +const DemoRequestModal = dynamic( + () => + import('@/app/(home)/components/demo-request/demo-request-modal').then( + (m) => m.DemoRequestModal + ), + { loading: () => null } +) + +const LandingPreview = dynamic( + () => + import('@/app/(home)/components/landing-preview/landing-preview').then( + (mod) => mod.LandingPreview + ), + { + ssr: false, + loading: () =>
, + } +) + +const CTA_BASE = + 'inline-flex items-center h-[32px] rounded-[5px] border px-2.5 font-[430] font-season text-sm' + +export default function Hero() { + return ( +
+

+ Sim is the open-source AI workspace where teams build, deploy, and manage AI agents. Connect + 1,000+ integrations and every major LLM, including OpenAI, Anthropic Claude, Google Gemini, + Mistral, and xAI Grok, to create agents that automate real work. Build agents visually with + the workflow builder, conversationally through Mothership, or programmatically with the API. + Trusted by over 100,000 builders at startups and Fortune 500 companies. SOC2 compliant. +

+ +
+

+ Build AI Agents +

+

+ Sim is the AI Workspace for Agent Builders +

+ +
+ + + + + + +
+
+ +
+
+ ) +} diff --git a/apps/sim/app/(home)/components/index.ts b/apps/sim/app/(home)/components/index.ts new file mode 100644 index 00000000000..cd42fd0a288 --- /dev/null +++ b/apps/sim/app/(home)/components/index.ts @@ -0,0 +1,25 @@ +import Collaboration from '@/app/(home)/components/collaboration/collaboration' +import ExternalRedirect from '@/app/(home)/components/external-redirect' +import Features from '@/app/(home)/components/features/features' +import Footer from '@/app/(home)/components/footer/footer' +import Hero from '@/app/(home)/components/hero/hero' +import LegalLayout from '@/app/(home)/components/legal-layout' +import Navbar from '@/app/(home)/components/navbar/navbar' +import Pricing from '@/app/(home)/components/pricing/pricing' +import StructuredData from '@/app/(home)/components/structured-data' +import Templates from '@/app/(home)/components/templates/templates' +import Testimonials from '@/app/(home)/components/testimonials/testimonials' + +export { + Collaboration, + ExternalRedirect, + Features, + Footer, + Hero, + LegalLayout, + Navbar, + Pricing, + StructuredData, + Templates, + Testimonials, +} diff --git a/apps/sim/app/(landing)/components/landing-faq.tsx b/apps/sim/app/(home)/components/landing-faq.tsx similarity index 100% rename from apps/sim/app/(landing)/components/landing-faq.tsx rename to apps/sim/app/(home)/components/landing-faq.tsx diff --git a/apps/sim/app/(landing)/components/landing-preview/components/landing-preview-files/landing-preview-files.tsx b/apps/sim/app/(home)/components/landing-preview/components/landing-preview-files/landing-preview-files.tsx similarity index 94% rename from apps/sim/app/(landing)/components/landing-preview/components/landing-preview-files/landing-preview-files.tsx rename to apps/sim/app/(home)/components/landing-preview/components/landing-preview-files/landing-preview-files.tsx index 8d3ecc0a309..fde214d9f6f 100644 --- a/apps/sim/app/(landing)/components/landing-preview/components/landing-preview-files/landing-preview-files.tsx +++ b/apps/sim/app/(home)/components/landing-preview/components/landing-preview-files/landing-preview-files.tsx @@ -3,11 +3,11 @@ import { DocxIcon, PdfIcon } from '@/components/icons/document-icons' import type { PreviewColumn, PreviewRow, -} from '@/app/(landing)/components/landing-preview/components/landing-preview-resource/landing-preview-resource' +} from '@/app/(home)/components/landing-preview/components/landing-preview-resource/landing-preview-resource' import { LandingPreviewResource, ownerCell, -} from '@/app/(landing)/components/landing-preview/components/landing-preview-resource/landing-preview-resource' +} from '@/app/(home)/components/landing-preview/components/landing-preview-resource/landing-preview-resource' /** Generic audio/zip icon using basic SVG since no dedicated component exists */ function AudioIcon({ className }: { className?: string }) { diff --git a/apps/sim/app/(landing)/components/landing-preview/components/landing-preview-home/landing-preview-home.tsx b/apps/sim/app/(home)/components/landing-preview/components/landing-preview-home/landing-preview-home.tsx similarity index 98% rename from apps/sim/app/(landing)/components/landing-preview/components/landing-preview-home/landing-preview-home.tsx rename to apps/sim/app/(home)/components/landing-preview/components/landing-preview-home/landing-preview-home.tsx index 3f411f608c5..197c575e3ec 100644 --- a/apps/sim/app/(landing)/components/landing-preview/components/landing-preview-home/landing-preview-home.tsx +++ b/apps/sim/app/(home)/components/landing-preview/components/landing-preview-home/landing-preview-home.tsx @@ -6,8 +6,8 @@ import { ArrowUp, Table } from 'lucide-react' import { Blimp, Checkbox, ChevronDown } from '@/components/emcn' import { TypeBoolean, TypeNumber, TypeText } from '@/components/emcn/icons' import { captureClientEvent } from '@/lib/posthog/client' -import { useLandingSubmit } from '@/app/(landing)/components/landing-preview/components/landing-preview-panel/landing-preview-panel' -import { EASE_OUT } from '@/app/(landing)/components/landing-preview/components/landing-preview-workflow/workflow-data' +import { useLandingSubmit } from '@/app/(home)/components/landing-preview/components/landing-preview-panel/landing-preview-panel' +import { EASE_OUT } from '@/app/(home)/components/landing-preview/components/landing-preview-workflow/workflow-data' import { useAnimatedPlaceholder } from '@/hooks/use-animated-placeholder' const C = { diff --git a/apps/sim/app/(landing)/components/landing-preview/components/landing-preview-knowledge/landing-preview-knowledge.tsx b/apps/sim/app/(home)/components/landing-preview/components/landing-preview-knowledge/landing-preview-knowledge.tsx similarity index 90% rename from apps/sim/app/(landing)/components/landing-preview/components/landing-preview-knowledge/landing-preview-knowledge.tsx rename to apps/sim/app/(home)/components/landing-preview/components/landing-preview-knowledge/landing-preview-knowledge.tsx index 8bfa219ec41..b135d9ef9bc 100644 --- a/apps/sim/app/(landing)/components/landing-preview/components/landing-preview-knowledge/landing-preview-knowledge.tsx +++ b/apps/sim/app/(home)/components/landing-preview/components/landing-preview-knowledge/landing-preview-knowledge.tsx @@ -13,8 +13,8 @@ import { import type { PreviewColumn, PreviewRow, -} from '@/app/(landing)/components/landing-preview/components/landing-preview-resource/landing-preview-resource' -import { LandingPreviewResource } from '@/app/(landing)/components/landing-preview/components/landing-preview-resource/landing-preview-resource' +} from '@/app/(home)/components/landing-preview/components/landing-preview-resource/landing-preview-resource' +import { LandingPreviewResource } from '@/app/(home)/components/landing-preview/components/landing-preview-resource/landing-preview-resource' const DB_ICON = diff --git a/apps/sim/app/(landing)/components/landing-preview/components/landing-preview-logs/landing-preview-logs.tsx b/apps/sim/app/(home)/components/landing-preview/components/landing-preview-logs/landing-preview-logs.tsx similarity index 100% rename from apps/sim/app/(landing)/components/landing-preview/components/landing-preview-logs/landing-preview-logs.tsx rename to apps/sim/app/(home)/components/landing-preview/components/landing-preview-logs/landing-preview-logs.tsx diff --git a/apps/sim/app/(landing)/components/landing-preview/components/landing-preview-panel/landing-preview-panel.tsx b/apps/sim/app/(home)/components/landing-preview/components/landing-preview-panel/landing-preview-panel.tsx similarity index 98% rename from apps/sim/app/(landing)/components/landing-preview/components/landing-preview-panel/landing-preview-panel.tsx rename to apps/sim/app/(home)/components/landing-preview/components/landing-preview-panel/landing-preview-panel.tsx index 6028edde6de..6c46ce82f30 100644 --- a/apps/sim/app/(landing)/components/landing-preview/components/landing-preview-panel/landing-preview-panel.tsx +++ b/apps/sim/app/(home)/components/landing-preview/components/landing-preview-panel/landing-preview-panel.tsx @@ -18,11 +18,11 @@ import { type PreviewWorkflow, TYPE_INTERVAL_MS, TYPE_START_BUFFER_MS, -} from '@/app/(landing)/components/landing-preview/components/landing-preview-workflow/workflow-data' -import { trackLandingCta } from '@/app/(landing)/landing-analytics' +} from '@/app/(home)/components/landing-preview/components/landing-preview-workflow/workflow-data' +import { trackLandingCta } from '@/app/(home)/landing-analytics' const AuthModal = dynamic( - () => import('@/app/(landing)/components/auth-modal/auth-modal').then((m) => m.AuthModal), + () => import('@/app/(home)/components/auth-modal/auth-modal').then((m) => m.AuthModal), { loading: () => null } ) diff --git a/apps/sim/app/(landing)/components/landing-preview/components/landing-preview-resource/landing-preview-resource.tsx b/apps/sim/app/(home)/components/landing-preview/components/landing-preview-resource/landing-preview-resource.tsx similarity index 100% rename from apps/sim/app/(landing)/components/landing-preview/components/landing-preview-resource/landing-preview-resource.tsx rename to apps/sim/app/(home)/components/landing-preview/components/landing-preview-resource/landing-preview-resource.tsx diff --git a/apps/sim/app/(landing)/components/landing-preview/components/landing-preview-scheduled-tasks/landing-preview-scheduled-tasks.tsx b/apps/sim/app/(home)/components/landing-preview/components/landing-preview-scheduled-tasks/landing-preview-scheduled-tasks.tsx similarity index 89% rename from apps/sim/app/(landing)/components/landing-preview/components/landing-preview-scheduled-tasks/landing-preview-scheduled-tasks.tsx rename to apps/sim/app/(home)/components/landing-preview/components/landing-preview-scheduled-tasks/landing-preview-scheduled-tasks.tsx index 0519cc8b7c4..a2bf6f7419c 100644 --- a/apps/sim/app/(landing)/components/landing-preview/components/landing-preview-scheduled-tasks/landing-preview-scheduled-tasks.tsx +++ b/apps/sim/app/(home)/components/landing-preview/components/landing-preview-scheduled-tasks/landing-preview-scheduled-tasks.tsx @@ -2,8 +2,8 @@ import { Calendar } from '@/components/emcn/icons' import type { PreviewColumn, PreviewRow, -} from '@/app/(landing)/components/landing-preview/components/landing-preview-resource/landing-preview-resource' -import { LandingPreviewResource } from '@/app/(landing)/components/landing-preview/components/landing-preview-resource/landing-preview-resource' +} from '@/app/(home)/components/landing-preview/components/landing-preview-resource/landing-preview-resource' +import { LandingPreviewResource } from '@/app/(home)/components/landing-preview/components/landing-preview-resource/landing-preview-resource' const CAL_ICON = diff --git a/apps/sim/app/(landing)/components/landing-preview/components/landing-preview-sidebar/landing-preview-sidebar.tsx b/apps/sim/app/(home)/components/landing-preview/components/landing-preview-sidebar/landing-preview-sidebar.tsx similarity index 98% rename from apps/sim/app/(landing)/components/landing-preview/components/landing-preview-sidebar/landing-preview-sidebar.tsx rename to apps/sim/app/(home)/components/landing-preview/components/landing-preview-sidebar/landing-preview-sidebar.tsx index 85f12f9bd00..3c2503b4148 100644 --- a/apps/sim/app/(landing)/components/landing-preview/components/landing-preview-sidebar/landing-preview-sidebar.tsx +++ b/apps/sim/app/(home)/components/landing-preview/components/landing-preview-sidebar/landing-preview-sidebar.tsx @@ -12,7 +12,7 @@ import { Workflow, } from '@/components/emcn/icons' import { cn } from '@/lib/core/utils/cn' -import type { PreviewWorkflow } from '@/app/(landing)/components/landing-preview/components/landing-preview-workflow/workflow-data' +import type { PreviewWorkflow } from '@/app/(home)/components/landing-preview/components/landing-preview-workflow/workflow-data' export type SidebarView = | 'home' diff --git a/apps/sim/app/(landing)/components/landing-preview/components/landing-preview-tables/landing-preview-tables.tsx b/apps/sim/app/(home)/components/landing-preview/components/landing-preview-tables/landing-preview-tables.tsx similarity index 98% rename from apps/sim/app/(landing)/components/landing-preview/components/landing-preview-tables/landing-preview-tables.tsx rename to apps/sim/app/(home)/components/landing-preview/components/landing-preview-tables/landing-preview-tables.tsx index 4d9c5bcef30..e8e25ec5639 100644 --- a/apps/sim/app/(landing)/components/landing-preview/components/landing-preview-tables/landing-preview-tables.tsx +++ b/apps/sim/app/(home)/components/landing-preview/components/landing-preview-tables/landing-preview-tables.tsx @@ -16,11 +16,11 @@ import { cn } from '@/lib/core/utils/cn' import type { PreviewColumn, PreviewRow, -} from '@/app/(landing)/components/landing-preview/components/landing-preview-resource/landing-preview-resource' +} from '@/app/(home)/components/landing-preview/components/landing-preview-resource/landing-preview-resource' import { LandingPreviewResource, ownerCell, -} from '@/app/(landing)/components/landing-preview/components/landing-preview-resource/landing-preview-resource' +} from '@/app/(home)/components/landing-preview/components/landing-preview-resource/landing-preview-resource' const CELL = 'border-[var(--border)] border-r border-b px-2 py-[7px] align-middle select-none' const CELL_CHECKBOX = diff --git a/apps/sim/app/(landing)/components/landing-preview/components/landing-preview-workflow/landing-preview-workflow.tsx b/apps/sim/app/(home)/components/landing-preview/components/landing-preview-workflow/landing-preview-workflow.tsx similarity index 95% rename from apps/sim/app/(landing)/components/landing-preview/components/landing-preview-workflow/landing-preview-workflow.tsx rename to apps/sim/app/(home)/components/landing-preview/components/landing-preview-workflow/landing-preview-workflow.tsx index 4d85c9b6cbe..3417d844acb 100644 --- a/apps/sim/app/(landing)/components/landing-preview/components/landing-preview-workflow/landing-preview-workflow.tsx +++ b/apps/sim/app/(home)/components/landing-preview/components/landing-preview-workflow/landing-preview-workflow.tsx @@ -16,12 +16,12 @@ import ReactFlow, { ReactFlowProvider, } from 'reactflow' import 'reactflow/dist/style.css' -import { PreviewBlockNode } from '@/app/(landing)/components/landing-preview/components/landing-preview-workflow/preview-block-node' +import { PreviewBlockNode } from '@/app/(home)/components/landing-preview/components/landing-preview-workflow/preview-block-node' import { EASE_OUT, type PreviewWorkflow, toReactFlowElements, -} from '@/app/(landing)/components/landing-preview/components/landing-preview-workflow/workflow-data' +} from '@/app/(home)/components/landing-preview/components/landing-preview-workflow/workflow-data' interface FitViewOptions { padding?: number diff --git a/apps/sim/app/(landing)/components/landing-preview/components/landing-preview-workflow/preview-block-node.tsx b/apps/sim/app/(home)/components/landing-preview/components/landing-preview-workflow/preview-block-node.tsx similarity index 99% rename from apps/sim/app/(landing)/components/landing-preview/components/landing-preview-workflow/preview-block-node.tsx rename to apps/sim/app/(home)/components/landing-preview/components/landing-preview-workflow/preview-block-node.tsx index 0e2af73d5da..d4645a7bc5a 100644 --- a/apps/sim/app/(landing)/components/landing-preview/components/landing-preview-workflow/preview-block-node.tsx +++ b/apps/sim/app/(home)/components/landing-preview/components/landing-preview-workflow/preview-block-node.tsx @@ -39,7 +39,7 @@ import { BLOCK_STAGGER, EASE_OUT, type PreviewTool, -} from '@/app/(landing)/components/landing-preview/components/landing-preview-workflow/workflow-data' +} from '@/app/(home)/components/landing-preview/components/landing-preview-workflow/workflow-data' /** Map block type strings to their icon components. */ const BLOCK_ICONS: Record> = { diff --git a/apps/sim/app/(landing)/components/landing-preview/components/landing-preview-workflow/workflow-data.ts b/apps/sim/app/(home)/components/landing-preview/components/landing-preview-workflow/workflow-data.ts similarity index 100% rename from apps/sim/app/(landing)/components/landing-preview/components/landing-preview-workflow/workflow-data.ts rename to apps/sim/app/(home)/components/landing-preview/components/landing-preview-workflow/workflow-data.ts diff --git a/apps/sim/app/(landing)/components/landing-preview/landing-preview.tsx b/apps/sim/app/(home)/components/landing-preview/landing-preview.tsx similarity index 86% rename from apps/sim/app/(landing)/components/landing-preview/landing-preview.tsx rename to apps/sim/app/(home)/components/landing-preview/landing-preview.tsx index 8d0fb801f62..650c1a41ddb 100644 --- a/apps/sim/app/(landing)/components/landing-preview/landing-preview.tsx +++ b/apps/sim/app/(home)/components/landing-preview/landing-preview.tsx @@ -2,21 +2,21 @@ import { useCallback, useEffect, useRef, useState } from 'react' import { AnimatePresence, domAnimation, LazyMotion, m, type Variants } from 'framer-motion' -import { LandingPreviewFiles } from '@/app/(landing)/components/landing-preview/components/landing-preview-files/landing-preview-files' -import { LandingPreviewHome } from '@/app/(landing)/components/landing-preview/components/landing-preview-home/landing-preview-home' -import { LandingPreviewKnowledge } from '@/app/(landing)/components/landing-preview/components/landing-preview-knowledge/landing-preview-knowledge' -import { LandingPreviewLogs } from '@/app/(landing)/components/landing-preview/components/landing-preview-logs/landing-preview-logs' -import { LandingPreviewPanel } from '@/app/(landing)/components/landing-preview/components/landing-preview-panel/landing-preview-panel' -import { LandingPreviewScheduledTasks } from '@/app/(landing)/components/landing-preview/components/landing-preview-scheduled-tasks/landing-preview-scheduled-tasks' -import type { SidebarView } from '@/app/(landing)/components/landing-preview/components/landing-preview-sidebar/landing-preview-sidebar' -import { LandingPreviewSidebar } from '@/app/(landing)/components/landing-preview/components/landing-preview-sidebar/landing-preview-sidebar' -import { LandingPreviewTables } from '@/app/(landing)/components/landing-preview/components/landing-preview-tables/landing-preview-tables' -import { LandingPreviewWorkflow } from '@/app/(landing)/components/landing-preview/components/landing-preview-workflow/landing-preview-workflow' +import { LandingPreviewFiles } from '@/app/(home)/components/landing-preview/components/landing-preview-files/landing-preview-files' +import { LandingPreviewHome } from '@/app/(home)/components/landing-preview/components/landing-preview-home/landing-preview-home' +import { LandingPreviewKnowledge } from '@/app/(home)/components/landing-preview/components/landing-preview-knowledge/landing-preview-knowledge' +import { LandingPreviewLogs } from '@/app/(home)/components/landing-preview/components/landing-preview-logs/landing-preview-logs' +import { LandingPreviewPanel } from '@/app/(home)/components/landing-preview/components/landing-preview-panel/landing-preview-panel' +import { LandingPreviewScheduledTasks } from '@/app/(home)/components/landing-preview/components/landing-preview-scheduled-tasks/landing-preview-scheduled-tasks' +import type { SidebarView } from '@/app/(home)/components/landing-preview/components/landing-preview-sidebar/landing-preview-sidebar' +import { LandingPreviewSidebar } from '@/app/(home)/components/landing-preview/components/landing-preview-sidebar/landing-preview-sidebar' +import { LandingPreviewTables } from '@/app/(home)/components/landing-preview/components/landing-preview-tables/landing-preview-tables' +import { LandingPreviewWorkflow } from '@/app/(home)/components/landing-preview/components/landing-preview-workflow/landing-preview-workflow' import { EASE_OUT, getWorkflowStepDuration, PREVIEW_WORKFLOWS, -} from '@/app/(landing)/components/landing-preview/components/landing-preview-workflow/workflow-data' +} from '@/app/(home)/components/landing-preview/components/landing-preview-workflow/workflow-data' const containerVariants: Variants = { hidden: {}, diff --git a/apps/sim/app/(landing)/components/legal-layout.tsx b/apps/sim/app/(home)/components/legal-layout.tsx similarity index 90% rename from apps/sim/app/(landing)/components/legal-layout.tsx rename to apps/sim/app/(home)/components/legal-layout.tsx index 3f5ebdee8de..a829a67b47f 100644 --- a/apps/sim/app/(landing)/components/legal-layout.tsx +++ b/apps/sim/app/(home)/components/legal-layout.tsx @@ -1,7 +1,7 @@ import { getNavBlogPosts } from '@/lib/blog/registry' import { isHosted } from '@/lib/core/config/feature-flags' -import Footer from '@/app/(landing)/components/footer/footer' -import Navbar from '@/app/(landing)/components/navbar/navbar' +import Footer from '@/app/(home)/components/footer/footer' +import Navbar from '@/app/(home)/components/navbar/navbar' interface LegalLayoutProps { title: string diff --git a/apps/sim/app/(landing)/components/navbar/components/blog-dropdown.tsx b/apps/sim/app/(home)/components/navbar/components/blog-dropdown.tsx similarity index 100% rename from apps/sim/app/(landing)/components/navbar/components/blog-dropdown.tsx rename to apps/sim/app/(home)/components/navbar/components/blog-dropdown.tsx diff --git a/apps/sim/app/(landing)/components/navbar/components/docs-dropdown.tsx b/apps/sim/app/(home)/components/navbar/components/docs-dropdown.tsx similarity index 100% rename from apps/sim/app/(landing)/components/navbar/components/docs-dropdown.tsx rename to apps/sim/app/(home)/components/navbar/components/docs-dropdown.tsx diff --git a/apps/sim/app/(landing)/components/navbar/components/github-stars.tsx b/apps/sim/app/(home)/components/navbar/components/github-stars.tsx similarity index 100% rename from apps/sim/app/(landing)/components/navbar/components/github-stars.tsx rename to apps/sim/app/(home)/components/navbar/components/github-stars.tsx diff --git a/apps/sim/app/(home)/components/navbar/navbar.tsx b/apps/sim/app/(home)/components/navbar/navbar.tsx new file mode 100644 index 00000000000..81ad241abc9 --- /dev/null +++ b/apps/sim/app/(home)/components/navbar/navbar.tsx @@ -0,0 +1,503 @@ +'use client' + +import { useCallback, useContext, useEffect, useRef, useState, useSyncExternalStore } from 'react' +import dynamic from 'next/dynamic' +import Image from 'next/image' +import Link from 'next/link' +import { GithubOutlineIcon } from '@/components/icons' +import { cn } from '@/lib/core/utils/cn' +import { SessionContext } from '@/app/_shell/providers/session-provider' +import { + BlogDropdown, + type NavBlogPost, +} from '@/app/(home)/components/navbar/components/blog-dropdown' +import { DocsDropdown } from '@/app/(home)/components/navbar/components/docs-dropdown' +import { GitHubStars } from '@/app/(home)/components/navbar/components/github-stars' +import { trackLandingCta } from '@/app/(home)/landing-analytics' +import { getBrandConfig } from '@/ee/whitelabeling' + +const AuthModal = dynamic( + () => import('@/app/(home)/components/auth-modal/auth-modal').then((m) => m.AuthModal), + { loading: () => null } +) + +type DropdownId = 'docs' | 'blog' | null + +interface NavLink { + label: string + href: string + external?: boolean + icon?: 'chevron' + dropdown?: 'docs' | 'blog' +} + +const NAV_LINKS: NavLink[] = [ + { label: 'Docs', href: 'https://docs.sim.ai', external: true, icon: 'chevron', dropdown: 'docs' }, + { label: 'Blog', href: '/blog', icon: 'chevron', dropdown: 'blog' }, + { label: 'Integrations', href: '/integrations' }, + { label: 'Models', href: '/models' }, + { label: 'Pricing', href: '/#pricing' }, +] + +const LOGO_CELL = 'flex items-center pl-5 lg:pl-16 pr-5' +const LINK_CELL = 'flex items-center px-3.5' + +const emptySubscribe = () => () => {} +const getLocationSearch = () => window.location.search +const getServerLocationSearch = () => '' + +const EMPTY_BLOG_POSTS: NavBlogPost[] = [] + +interface NavbarProps { + logoOnly?: boolean + blogPosts?: NavBlogPost[] +} + +export default function Navbar({ logoOnly = false, blogPosts = EMPTY_BLOG_POSTS }: NavbarProps) { + const brand = getBrandConfig() + const sessionCtx = useContext(SessionContext) + const session = sessionCtx?.data ?? null + const isSessionPending = sessionCtx?.isPending ?? true + const isAuthenticated = Boolean(session?.user?.id) + const locationSearch = useSyncExternalStore( + emptySubscribe, + getLocationSearch, + getServerLocationSearch + ) + const isBrowsingHome = new URLSearchParams(locationSearch).has('home') + const useHomeLinks = isAuthenticated || isBrowsingHome + const logoHref = useHomeLinks ? '/?home' : '/' + const mounted = useSyncExternalStore( + emptySubscribe, + () => true, + () => false + ) + const shouldShow = mounted && !isSessionPending + const [activeDropdown, setActiveDropdown] = useState(null) + const [mobileMenuOpen, setMobileMenuOpen] = useState(false) + const closeTimerRef = useRef | null>(null) + + const openDropdown = useCallback((id: DropdownId) => { + if (closeTimerRef.current) { + clearTimeout(closeTimerRef.current) + closeTimerRef.current = null + } + setActiveDropdown(id) + }, []) + + const scheduleClose = useCallback(() => { + if (closeTimerRef.current) clearTimeout(closeTimerRef.current) + closeTimerRef.current = setTimeout(() => { + setActiveDropdown(null) + closeTimerRef.current = null + }, 100) + }, []) + + useEffect(() => { + return () => { + if (closeTimerRef.current) clearTimeout(closeTimerRef.current) + } + }, []) + + useEffect(() => { + document.body.style.overflow = mobileMenuOpen ? 'hidden' : '' + return () => { + document.body.style.overflow = '' + } + }, [mobileMenuOpen]) + + useEffect(() => { + const mq = window.matchMedia('(min-width: 1024px)') + const handler = () => { + if (mq.matches) setMobileMenuOpen(false) + } + mq.addEventListener('change', handler) + return () => mq.removeEventListener('change', handler) + }, []) + + return ( + + ) +} + +interface NavChevronProps { + open: boolean +} + +/** Matches the exact geometry of the emcn ChevronDown SVG — transform origins are intentional. */ +function NavChevron({ open }: NavChevronProps) { + return ( + + + + + ) +} + +function MobileMenuIcon({ open }: { open: boolean }) { + if (open) { + return ( + + + + ) + } + return ( + + + + ) +} + +function ExternalArrowIcon() { + return ( + + + + ) +} diff --git a/apps/sim/app/(landing)/components/not-found-view.tsx b/apps/sim/app/(home)/components/not-found-view.tsx similarity index 96% rename from apps/sim/app/(landing)/components/not-found-view.tsx rename to apps/sim/app/(home)/components/not-found-view.tsx index 69a0f2d6778..48c9f58f203 100644 --- a/apps/sim/app/(landing)/components/not-found-view.tsx +++ b/apps/sim/app/(home)/components/not-found-view.tsx @@ -2,7 +2,7 @@ import Link from 'next/link' import { getNavBlogPosts } from '@/lib/blog/registry' import AuthBackground from '@/app/(auth)/components/auth-background' import { AUTH_PRIMARY_CTA_BASE } from '@/app/(auth)/components/auth-button-classes' -import Navbar from '@/app/(landing)/components/navbar/navbar' +import Navbar from '@/app/(home)/components/navbar/navbar' /** * Shared 404 view used by every `not-found.tsx` under the landing surface. diff --git a/apps/sim/app/(landing)/components/pricing/pricing.tsx b/apps/sim/app/(home)/components/pricing/pricing.tsx similarity index 97% rename from apps/sim/app/(landing)/components/pricing/pricing.tsx rename to apps/sim/app/(home)/components/pricing/pricing.tsx index d989f714167..4b1fc07cdef 100644 --- a/apps/sim/app/(landing)/components/pricing/pricing.tsx +++ b/apps/sim/app/(home)/components/pricing/pricing.tsx @@ -2,16 +2,16 @@ import dynamic from 'next/dynamic' import { Badge } from '@/components/emcn' -import { trackLandingCta } from '@/app/(landing)/landing-analytics' +import { trackLandingCta } from '@/app/(home)/landing-analytics' const AuthModal = dynamic( - () => import('@/app/(landing)/components/auth-modal/auth-modal').then((m) => m.AuthModal), + () => import('@/app/(home)/components/auth-modal/auth-modal').then((m) => m.AuthModal), { loading: () => null } ) const DemoRequestModal = dynamic( () => - import('@/app/(landing)/components/demo-request/demo-request-modal').then( + import('@/app/(home)/components/demo-request/demo-request-modal').then( (m) => m.DemoRequestModal ), { loading: () => null } diff --git a/apps/sim/app/(landing)/components/scroll-to-top.tsx b/apps/sim/app/(home)/components/scroll-to-top.tsx similarity index 100% rename from apps/sim/app/(landing)/components/scroll-to-top.tsx rename to apps/sim/app/(home)/components/scroll-to-top.tsx diff --git a/apps/sim/app/(landing)/components/structured-data.tsx b/apps/sim/app/(home)/components/structured-data.tsx similarity index 100% rename from apps/sim/app/(landing)/components/structured-data.tsx rename to apps/sim/app/(home)/components/structured-data.tsx diff --git a/apps/sim/app/(landing)/components/templates/template-workflows.ts b/apps/sim/app/(home)/components/templates/template-workflows.ts similarity index 99% rename from apps/sim/app/(landing)/components/templates/template-workflows.ts rename to apps/sim/app/(home)/components/templates/template-workflows.ts index 6e0cf6e270d..8d23b947211 100644 --- a/apps/sim/app/(landing)/components/templates/template-workflows.ts +++ b/apps/sim/app/(home)/components/templates/template-workflows.ts @@ -1,4 +1,4 @@ -import type { PreviewWorkflow } from '@/app/(landing)/components/landing-preview/components/landing-preview-workflow/workflow-data' +import type { PreviewWorkflow } from '@/app/(home)/components/landing-preview/components/landing-preview-workflow/workflow-data' /** * OCR Invoice to DB — Start → Agent (Textract) → Supabase diff --git a/apps/sim/app/(landing)/components/templates/templates.tsx b/apps/sim/app/(home)/components/templates/templates.tsx similarity index 98% rename from apps/sim/app/(landing)/components/templates/templates.tsx rename to apps/sim/app/(home)/components/templates/templates.tsx index d8acf137c94..7215df024e2 100644 --- a/apps/sim/app/(landing)/components/templates/templates.tsx +++ b/apps/sim/app/(home)/components/templates/templates.tsx @@ -8,15 +8,15 @@ import { useRouter } from 'next/navigation' import { Badge, ChevronDown } from '@/components/emcn' import { LandingWorkflowSeedStorage } from '@/lib/core/utils/browser-storage' import { cn } from '@/lib/core/utils/cn' -import { TEMPLATE_WORKFLOWS } from '@/app/(landing)/components/templates/template-workflows' -import { trackLandingCta } from '@/app/(landing)/landing-analytics' +import { TEMPLATE_WORKFLOWS } from '@/app/(home)/components/templates/template-workflows' +import { trackLandingCta } from '@/app/(home)/landing-analytics' const logger = createLogger('LandingTemplates') const LandingPreviewWorkflow = dynamic( () => import( - '@/app/(landing)/components/landing-preview/components/landing-preview-workflow/landing-preview-workflow' + '@/app/(home)/components/landing-preview/components/landing-preview-workflow/landing-preview-workflow' ).then((mod) => mod.LandingPreviewWorkflow), { ssr: false, diff --git a/apps/sim/app/(home)/components/testimonials/testimonials.tsx b/apps/sim/app/(home)/components/testimonials/testimonials.tsx new file mode 100644 index 00000000000..d24ccbf8634 --- /dev/null +++ b/apps/sim/app/(home)/components/testimonials/testimonials.tsx @@ -0,0 +1,18 @@ +/** + * Testimonials section — social proof via user quotes. + * + * SEO: + * - `
`. + * - `

` for the section title. + * - Each testimonial: `
` with `
Author
`. + * - Profile images use `loading="lazy"` (below the fold). + * + * GEO: + * - Keep quote text as plain text in `
` — not split across `` elements. + * - Include full author name + handle (LLMs weigh attributed quotes higher). + * - Testimonials mentioning "Sim" by name carry more citation weight. + * - Review data here aligns with `review` entries in structured-data.tsx. + */ +export default function Testimonials() { + return null +} diff --git a/apps/sim/app/(landing)/contact/page.tsx b/apps/sim/app/(home)/contact/page.tsx similarity index 89% rename from apps/sim/app/(landing)/contact/page.tsx rename to apps/sim/app/(home)/contact/page.tsx index 6d2b00ef700..660e0efbee9 100644 --- a/apps/sim/app/(landing)/contact/page.tsx +++ b/apps/sim/app/(home)/contact/page.tsx @@ -2,9 +2,9 @@ import type { Metadata } from 'next' import { getNavBlogPosts } from '@/lib/blog/registry' import { isHosted } from '@/lib/core/config/feature-flags' import { SITE_URL } from '@/lib/core/utils/urls' -import { ContactForm } from '@/app/(landing)/components/contact/contact-form' -import Footer from '@/app/(landing)/components/footer/footer' -import Navbar from '@/app/(landing)/components/navbar/navbar' +import { ContactForm } from '@/app/(home)/components/contact/contact-form' +import Footer from '@/app/(home)/components/footer/footer' +import Navbar from '@/app/(home)/components/navbar/navbar' export const metadata: Metadata = { title: 'Contact Us', diff --git a/apps/sim/app/(landing)/integrations/(shell)/[slug]/components/integration-cta-button.tsx b/apps/sim/app/(home)/integrations/(shell)/[slug]/components/integration-cta-button.tsx similarity index 78% rename from apps/sim/app/(landing)/integrations/(shell)/[slug]/components/integration-cta-button.tsx rename to apps/sim/app/(home)/integrations/(shell)/[slug]/components/integration-cta-button.tsx index b746d7a5277..efff04325e0 100644 --- a/apps/sim/app/(landing)/integrations/(shell)/[slug]/components/integration-cta-button.tsx +++ b/apps/sim/app/(home)/integrations/(shell)/[slug]/components/integration-cta-button.tsx @@ -1,7 +1,7 @@ 'use client' -import { AuthModal } from '@/app/(landing)/components/auth-modal/auth-modal' -import { trackLandingCta } from '@/app/(landing)/landing-analytics' +import { AuthModal } from '@/app/(home)/components/auth-modal/auth-modal' +import { trackLandingCta } from '@/app/(home)/landing-analytics' interface IntegrationCtaButtonProps { children: React.ReactNode diff --git a/apps/sim/app/(landing)/integrations/(shell)/[slug]/components/integration-faq.tsx b/apps/sim/app/(home)/integrations/(shell)/[slug]/components/integration-faq.tsx similarity index 75% rename from apps/sim/app/(landing)/integrations/(shell)/[slug]/components/integration-faq.tsx rename to apps/sim/app/(home)/integrations/(shell)/[slug]/components/integration-faq.tsx index 339b3cc26e1..fcee3676c60 100644 --- a/apps/sim/app/(landing)/integrations/(shell)/[slug]/components/integration-faq.tsx +++ b/apps/sim/app/(home)/integrations/(shell)/[slug]/components/integration-faq.tsx @@ -1,5 +1,5 @@ import type { FAQItem } from '@/lib/integrations' -import { LandingFAQ } from '@/app/(landing)/components/landing-faq' +import { LandingFAQ } from '@/app/(home)/components/landing-faq' interface IntegrationFAQProps { faqs: FAQItem[] diff --git a/apps/sim/app/(landing)/integrations/(shell)/[slug]/components/template-card-button.tsx b/apps/sim/app/(home)/integrations/(shell)/[slug]/components/template-card-button.tsx similarity index 94% rename from apps/sim/app/(landing)/integrations/(shell)/[slug]/components/template-card-button.tsx rename to apps/sim/app/(home)/integrations/(shell)/[slug]/components/template-card-button.tsx index b7d8dc85593..72f7b07ea37 100644 --- a/apps/sim/app/(landing)/integrations/(shell)/[slug]/components/template-card-button.tsx +++ b/apps/sim/app/(home)/integrations/(shell)/[slug]/components/template-card-button.tsx @@ -3,7 +3,7 @@ import { useRouter } from 'next/navigation' import { LandingPromptStorage } from '@/lib/core/utils/browser-storage' import { cn } from '@/lib/core/utils/cn' -import { trackLandingCta } from '@/app/(landing)/landing-analytics' +import { trackLandingCta } from '@/app/(home)/landing-analytics' interface TemplateCardButtonProps { /** diff --git a/apps/sim/app/(landing)/integrations/(shell)/[slug]/loading.tsx b/apps/sim/app/(home)/integrations/(shell)/[slug]/loading.tsx similarity index 100% rename from apps/sim/app/(landing)/integrations/(shell)/[slug]/loading.tsx rename to apps/sim/app/(home)/integrations/(shell)/[slug]/loading.tsx diff --git a/apps/sim/app/(landing)/integrations/(shell)/[slug]/opengraph-image.tsx b/apps/sim/app/(home)/integrations/(shell)/[slug]/opengraph-image.tsx similarity index 95% rename from apps/sim/app/(landing)/integrations/(shell)/[slug]/opengraph-image.tsx rename to apps/sim/app/(home)/integrations/(shell)/[slug]/opengraph-image.tsx index d709cd9d4d3..04f78bd9342 100644 --- a/apps/sim/app/(landing)/integrations/(shell)/[slug]/opengraph-image.tsx +++ b/apps/sim/app/(home)/integrations/(shell)/[slug]/opengraph-image.tsx @@ -1,7 +1,7 @@ import { notFound } from 'next/navigation' import integrationsJson from '@/lib/integrations/integrations.json' import type { AuthType, Integration } from '@/lib/integrations/types' -import { createLandingOgImage } from '@/app/(landing)/og-utils' +import { createLandingOgImage } from '@/app/(home)/og-utils' export const contentType = 'image/png' export const size = { diff --git a/apps/sim/app/(landing)/integrations/(shell)/[slug]/page.tsx b/apps/sim/app/(home)/integrations/(shell)/[slug]/page.tsx similarity index 99% rename from apps/sim/app/(landing)/integrations/(shell)/[slug]/page.tsx rename to apps/sim/app/(home)/integrations/(shell)/[slug]/page.tsx index 0b7c616dd80..b21eb6eb7e9 100644 --- a/apps/sim/app/(landing)/integrations/(shell)/[slug]/page.tsx +++ b/apps/sim/app/(home)/integrations/(shell)/[slug]/page.tsx @@ -13,10 +13,10 @@ import { INTEGRATIONS_UPDATED_AT, type Integration, } from '@/lib/integrations' -import { IntegrationCtaButton } from '@/app/(landing)/integrations/(shell)/[slug]/components/integration-cta-button' -import { IntegrationFAQ } from '@/app/(landing)/integrations/(shell)/[slug]/components/integration-faq' -import { TemplateCardButton } from '@/app/(landing)/integrations/(shell)/[slug]/components/template-card-button' -import { IntegrationIcon } from '@/app/(landing)/integrations/components/integration-icon' +import { IntegrationCtaButton } from '@/app/(home)/integrations/(shell)/[slug]/components/integration-cta-button' +import { IntegrationFAQ } from '@/app/(home)/integrations/(shell)/[slug]/components/integration-faq' +import { TemplateCardButton } from '@/app/(home)/integrations/(shell)/[slug]/components/template-card-button' +import { IntegrationIcon } from '@/app/(home)/integrations/components/integration-icon' import { getTemplatesForBlock } from '@/blocks/registry' const allIntegrations = INTEGRATIONS diff --git a/apps/sim/app/(landing)/integrations/(shell)/layout.tsx b/apps/sim/app/(home)/integrations/(shell)/layout.tsx similarity index 87% rename from apps/sim/app/(landing)/integrations/(shell)/layout.tsx rename to apps/sim/app/(home)/integrations/(shell)/layout.tsx index c21291ff46a..7f33e1b45ba 100644 --- a/apps/sim/app/(landing)/integrations/(shell)/layout.tsx +++ b/apps/sim/app/(home)/integrations/(shell)/layout.tsx @@ -1,8 +1,8 @@ import { getNavBlogPosts } from '@/lib/blog/registry' import { SITE_URL } from '@/lib/core/utils/urls' -import Footer from '@/app/(landing)/components/footer/footer' -import Navbar from '@/app/(landing)/components/navbar/navbar' -import { ScrollToTop } from '@/app/(landing)/components/scroll-to-top' +import Footer from '@/app/(home)/components/footer/footer' +import Navbar from '@/app/(home)/components/navbar/navbar' +import { ScrollToTop } from '@/app/(home)/components/scroll-to-top' export default async function IntegrationsLayout({ children }: { children: React.ReactNode }) { const blogPosts = await getNavBlogPosts() diff --git a/apps/sim/app/(landing)/integrations/(shell)/opengraph-image.tsx b/apps/sim/app/(home)/integrations/(shell)/opengraph-image.tsx similarity index 94% rename from apps/sim/app/(landing)/integrations/(shell)/opengraph-image.tsx rename to apps/sim/app/(home)/integrations/(shell)/opengraph-image.tsx index c58f742ed13..cfadfedf224 100644 --- a/apps/sim/app/(landing)/integrations/(shell)/opengraph-image.tsx +++ b/apps/sim/app/(home)/integrations/(shell)/opengraph-image.tsx @@ -1,6 +1,6 @@ import integrationsJson from '@/lib/integrations/integrations.json' import type { Integration } from '@/lib/integrations/types' -import { createLandingOgImage } from '@/app/(landing)/og-utils' +import { createLandingOgImage } from '@/app/(home)/og-utils' export const contentType = 'image/png' export const size = { diff --git a/apps/sim/app/(landing)/integrations/(shell)/page.tsx b/apps/sim/app/(home)/integrations/(shell)/page.tsx similarity index 96% rename from apps/sim/app/(landing)/integrations/(shell)/page.tsx rename to apps/sim/app/(home)/integrations/(shell)/page.tsx index b311e3f315f..daac4c9851d 100644 --- a/apps/sim/app/(landing)/integrations/(shell)/page.tsx +++ b/apps/sim/app/(home)/integrations/(shell)/page.tsx @@ -8,10 +8,10 @@ import { type Integration, POPULAR_WORKFLOWS, } from '@/lib/integrations' -import { LandingFAQ } from '@/app/(landing)/components/landing-faq' -import { IntegrationCard } from '@/app/(landing)/integrations/components/integration-card' -import { IntegrationGrid } from '@/app/(landing)/integrations/components/integration-grid' -import { RequestIntegrationModal } from '@/app/(landing)/integrations/components/request-integration-modal' +import { LandingFAQ } from '@/app/(home)/components/landing-faq' +import { IntegrationCard } from '@/app/(home)/integrations/components/integration-card' +import { IntegrationGrid } from '@/app/(home)/integrations/components/integration-grid' +import { RequestIntegrationModal } from '@/app/(home)/integrations/components/request-integration-modal' const allIntegrations = INTEGRATIONS const INTEGRATION_COUNT = allIntegrations.length diff --git a/apps/sim/app/(landing)/integrations/[slug]/loading.tsx b/apps/sim/app/(home)/integrations/[slug]/loading.tsx similarity index 100% rename from apps/sim/app/(landing)/integrations/[slug]/loading.tsx rename to apps/sim/app/(home)/integrations/[slug]/loading.tsx diff --git a/apps/sim/app/(landing)/integrations/components/integration-card.tsx b/apps/sim/app/(home)/integrations/components/integration-card.tsx similarity index 93% rename from apps/sim/app/(landing)/integrations/components/integration-card.tsx rename to apps/sim/app/(home)/integrations/components/integration-card.tsx index a845fa2ce8a..89f3307c9a2 100644 --- a/apps/sim/app/(landing)/integrations/components/integration-card.tsx +++ b/apps/sim/app/(home)/integrations/components/integration-card.tsx @@ -1,8 +1,8 @@ import type { ComponentType, SVGProps } from 'react' import Link from 'next/link' import type { Integration } from '@/lib/integrations' -import { IntegrationIcon } from '@/app/(landing)/integrations/components/integration-icon' -import { ChevronArrow } from '@/app/(landing)/models/components/model-primitives' +import { IntegrationIcon } from '@/app/(home)/integrations/components/integration-icon' +import { ChevronArrow } from '@/app/(home)/models/components/model-primitives' const HOVER_BG = 'transition-colors hover:bg-[var(--landing-bg-elevated)]' as const diff --git a/apps/sim/app/(landing)/integrations/components/integration-grid.tsx b/apps/sim/app/(home)/integrations/components/integration-grid.tsx similarity index 97% rename from apps/sim/app/(landing)/integrations/components/integration-grid.tsx rename to apps/sim/app/(home)/integrations/components/integration-grid.tsx index b1f3b0bb547..fb75b3704e6 100644 --- a/apps/sim/app/(landing)/integrations/components/integration-grid.tsx +++ b/apps/sim/app/(home)/integrations/components/integration-grid.tsx @@ -3,7 +3,7 @@ import { useState } from 'react' import { ChipInput, Search } from '@/components/emcn' import { blockTypeToIconMap, formatIntegrationType, type Integration } from '@/lib/integrations' -import { IntegrationRow } from '@/app/(landing)/integrations/components/integration-card' +import { IntegrationRow } from '@/app/(home)/integrations/components/integration-card' const PILL_BASE = 'rounded-[5px] border border-[var(--landing-border-strong)] px-[9px] py-0.5 text-[13.5px] text-[var(--landing-text)] transition-colors' as const diff --git a/apps/sim/app/(landing)/integrations/components/integration-icon.tsx b/apps/sim/app/(home)/integrations/components/integration-icon.tsx similarity index 100% rename from apps/sim/app/(landing)/integrations/components/integration-icon.tsx rename to apps/sim/app/(home)/integrations/components/integration-icon.tsx diff --git a/apps/sim/app/(landing)/integrations/components/request-integration-modal.tsx b/apps/sim/app/(home)/integrations/components/request-integration-modal.tsx similarity index 100% rename from apps/sim/app/(landing)/integrations/components/request-integration-modal.tsx rename to apps/sim/app/(home)/integrations/components/request-integration-modal.tsx diff --git a/apps/sim/app/(landing)/integrations/data/landing-content.ts b/apps/sim/app/(home)/integrations/data/landing-content.ts similarity index 95% rename from apps/sim/app/(landing)/integrations/data/landing-content.ts rename to apps/sim/app/(home)/integrations/data/landing-content.ts index 03466f74ac3..dbc9673d93a 100644 --- a/apps/sim/app/(landing)/integrations/data/landing-content.ts +++ b/apps/sim/app/(home)/integrations/data/landing-content.ts @@ -6,7 +6,7 @@ * augmentation. Has no app imports so the build script can import it safely. */ -import type { IntegrationLandingContent } from '@/app/(landing)/integrations/data/types' +import type { IntegrationLandingContent } from '@/app/(home)/integrations/data/types' export const INTEGRATION_LANDING_CONTENT: Record = { slack: { diff --git a/apps/sim/app/(landing)/integrations/data/types.ts b/apps/sim/app/(home)/integrations/data/types.ts similarity index 100% rename from apps/sim/app/(landing)/integrations/data/types.ts rename to apps/sim/app/(home)/integrations/data/types.ts diff --git a/apps/sim/app/(landing)/integrations/not-found.tsx b/apps/sim/app/(home)/integrations/not-found.tsx similarity index 76% rename from apps/sim/app/(landing)/integrations/not-found.tsx rename to apps/sim/app/(home)/integrations/not-found.tsx index 549bf6aca0f..c1e35ba5bc2 100644 --- a/apps/sim/app/(landing)/integrations/not-found.tsx +++ b/apps/sim/app/(home)/integrations/not-found.tsx @@ -1,5 +1,5 @@ import type { Metadata } from 'next' -import NotFoundView from '@/app/(landing)/components/not-found-view' +import NotFoundView from '@/app/(home)/components/not-found-view' export const metadata: Metadata = { title: 'Page Not Found', diff --git a/apps/sim/app/(landing)/landing-analytics.tsx b/apps/sim/app/(home)/landing-analytics.tsx similarity index 100% rename from apps/sim/app/(landing)/landing-analytics.tsx rename to apps/sim/app/(home)/landing-analytics.tsx diff --git a/apps/sim/app/(home)/landing.tsx b/apps/sim/app/(home)/landing.tsx new file mode 100644 index 00000000000..c6456d4d96e --- /dev/null +++ b/apps/sim/app/(home)/landing.tsx @@ -0,0 +1,74 @@ +import { getNavBlogPosts } from '@/lib/blog/registry' +import { martianMono } from '@/app/_styles/fonts/martian-mono/martian-mono' +import { season } from '@/app/_styles/fonts/season/season' +import { + Collaboration, + Features, + Footer, + Hero, + Navbar, + Pricing, + StructuredData, + Templates, + Testimonials, +} from '@/app/(home)/components' +import { LandingAnalytics } from '@/app/(home)/landing-analytics' + +/** + * Landing page root component. + * + * ## SEO Architecture + * - Single `

` inside Hero (only one per page). + * - Heading hierarchy: H1 (Hero) -> H2 (each section) -> H3 (sub-items). + * - Semantic landmarks: `
`, `
`, `