diff --git a/apps/sim/app/(landing)/components/featured-customer/featured-customer-card.tsx b/apps/sim/app/(landing)/components/featured-customer/featured-customer-card.tsx index 0b8520a57e1..d4e35f0c036 100644 --- a/apps/sim/app/(landing)/components/featured-customer/featured-customer-card.tsx +++ b/apps/sim/app/(landing)/components/featured-customer/featured-customer-card.tsx @@ -52,7 +52,7 @@ export function FeaturedCustomerCard({ story, active, emphasized }: FeaturedCust /** * The film streams only while the slide is on screen in a visible tab: - * `play()` defeats `preload='metadata'`, so calling it at mount would pull + * `play()` defeats `preload='none'`, so calling it at mount would pull * the whole file for a section well below the fold. Autoplay may still be * blocked, in which case the poster remains the fallback. */ @@ -82,8 +82,8 @@ export function FeaturedCustomerCard({ story, active, emphasized }: FeaturedCust
@@ -103,7 +103,7 @@ export function FeaturedCustomerCard({ story, active, emphasized }: FeaturedCust loop muted playsInline - preload='metadata' + preload='none' src={story.media.src} tabIndex={-1} className='pointer-events-none absolute inset-0 size-full object-cover motion-reduce:hidden' diff --git a/apps/sim/app/(landing)/components/featured-customer/featured-customer.test.tsx b/apps/sim/app/(landing)/components/featured-customer/featured-customer.test.tsx index fb3ea91cb76..fc854b8dc42 100644 --- a/apps/sim/app/(landing)/components/featured-customer/featured-customer.test.tsx +++ b/apps/sim/app/(landing)/components/featured-customer/featured-customer.test.tsx @@ -85,10 +85,17 @@ describe('FeaturedCustomer', () => { expect(rivian.querySelector('video')?.getAttribute('src')).toBe( '/landing/customer-stories/rivian-r2-loop.mp4' ) - expect(expRealty.querySelector('video')).toBeNull() + const expVideo = expRealty.querySelector('video') as HTMLVideoElement + expect(expVideo.getAttribute('src')).toBe('/landing/customer-stories/exp-house-color-loop.mp4') + expect(expVideo.getAttribute('preload')).toBe('none') + expect(expVideo.muted).toBe(true) + expect(vi.mocked(video.play).mock.contexts).not.toContain(expVideo) expect( [...expRealty.querySelectorAll('img')].map((image) => image.getAttribute('src')) - ).toEqual(['/landing/logos/exp-realty.svg']) + ).toEqual([ + '/landing/customer-stories/exp-house-color-poster.jpg', + '/landing/logos/exp-realty.svg', + ]) const controls = nextButton.parentElement as HTMLElement expect(controls.className).toContain('justify-end') @@ -122,6 +129,7 @@ describe('FeaturedCustomer', () => { expect(rivian.querySelector('article')?.getAttribute('aria-hidden')).toBe('true') expect(rivian.className).toContain('-translate-x-[calc(100%_+_1.5rem)]') expect(expRealty.getAttribute('aria-current')).toBe('true') + expect(vi.mocked(video.play).mock.contexts).toContain(expVideo) expect(expRealty.querySelector('article')?.getAttribute('aria-hidden')).toBe('false') expect(expRealty.className).toContain('translate-x-0') expect(expRealty.className).toContain('opacity-100') @@ -140,10 +148,15 @@ describe('FeaturedCustomer', () => { expect(expRealty.querySelector('img[alt="eXp Realty"]')).not.toBeNull() expect(host.querySelector('video')).toBe(video) expect(video.currentTime).toBe(12) - expect(video.pause).toHaveBeenCalledOnce() + expect( + vi.mocked(video.pause).mock.contexts.filter((context) => context === video) + ).toHaveLength(1) expect( [...expRealty.querySelectorAll('img')].map((image) => image.getAttribute('src')) - ).toEqual(['/landing/logos/exp-realty.svg']) + ).toEqual([ + '/landing/customer-stories/exp-house-color-poster.jpg', + '/landing/logos/exp-realty.svg', + ]) expect( [...host.querySelectorAll('[data-testid="customer-tooltip"]')].map((node) => node.textContent) ).toEqual(['View Rivian customer story']) @@ -156,7 +169,9 @@ describe('FeaturedCustomer', () => { expect(expRealty.getAttribute('aria-current')).toBeNull() expect(rivian.querySelector('video')).toBe(video) expect(video.currentTime).toBe(12) - expect(video.play).toHaveBeenCalledTimes(2) + expect(vi.mocked(video.play).mock.contexts.filter((context) => context === video)).toHaveLength( + 2 + ) act(() => { root.unmount() @@ -173,7 +188,9 @@ describe('FeaturedCustomer', () => { act(() => root.render()) const video = host.querySelector('video') as HTMLVideoElement expect(video.play).not.toHaveBeenCalled() - expect(video.pause).toHaveBeenCalledOnce() + expect( + vi.mocked(video.pause).mock.contexts.filter((context) => context === video) + ).toHaveLength(1) motionPreference.reduced = false act(() => root.render()) @@ -181,7 +198,9 @@ describe('FeaturedCustomer', () => { motionPreference.reduced = true act(() => root.render()) - expect(video.pause).toHaveBeenCalledTimes(2) + expect( + vi.mocked(video.pause).mock.contexts.filter((context) => context === video) + ).toHaveLength(2) act(() => root.unmount()) }) diff --git a/apps/sim/app/(landing)/components/featured-customer/featured-customer.tsx b/apps/sim/app/(landing)/components/featured-customer/featured-customer.tsx index 87b84700eb4..391fca73637 100644 --- a/apps/sim/app/(landing)/components/featured-customer/featured-customer.tsx +++ b/apps/sim/app/(landing)/components/featured-customer/featured-customer.tsx @@ -35,7 +35,12 @@ const CUSTOMER_STORIES: FeaturedCustomerStory[] = [ id: 'exp-realty', company: 'eXp Realty', caption: 'Bring teams, shared knowledge, and AI agents into one workspace with Sim.', - media: { kind: 'brand' }, + media: { + kind: 'video', + poster: '/landing/customer-stories/exp-house-color-poster.jpg', + src: '/landing/customer-stories/exp-house-color-loop.mp4', + alt: 'An eXp Realty sign and the exterior of a modern home', + }, logo: { src: '/landing/logos/exp-realty.svg', alt: 'eXp Realty', aspect: 1.84, height: 32 }, }, ] diff --git a/apps/sim/app/(landing)/components/hero/components/hero-platform-loop/hero-resource-panel.tsx b/apps/sim/app/(landing)/components/hero/components/hero-platform-loop/hero-resource-panel.tsx index a5d484f3285..d6bdb2a11a7 100644 --- a/apps/sim/app/(landing)/components/hero/components/hero-platform-loop/hero-resource-panel.tsx +++ b/apps/sim/app/(landing)/components/hero/components/hero-platform-loop/hero-resource-panel.tsx @@ -1,6 +1,6 @@ 'use client' -import { type ComponentType, useState } from 'react' +import type { ComponentType } from 'react' import { Button, cn, @@ -21,6 +21,8 @@ import { Workflow, } from '@sim/emcn/icons' import { HeroWorkflowStage } from '@/app/(landing)/components/hero/components/hero-platform-loop/hero-workflow-stage' +import type { LeadRecord } from '@/app/(landing)/tables/components/tables-records-preview/data' +import { TablesRecordsTable } from '@/app/(landing)/tables/components/tables-records-preview/tables-records-table' import { RESOURCE_HEADER_CLASSES, RESOURCE_TAB_ICON_BUTTON_CLASS, @@ -41,11 +43,11 @@ const HERO_RESOURCES: readonly HeroResourceDefinition[] = [ { id: 'brief', title: 'lead-enrichment-brief.md', icon: FileText }, ] as const -const TABLE_ROWS = [ - { id: 'northstar', lead: 'Maya Chen', company: 'Northstar', score: '94', status: 'Qualified' }, - { id: 'arcadia', lead: 'Jon Bell', company: 'Arcadia', score: '88', status: 'Qualified' }, - { id: 'hearth', lead: 'Priya Shah', company: 'Hearth', score: '79', status: 'Review' }, - { id: 'lattice', lead: 'Noah Kim', company: 'Lattice', score: '72', status: 'Review' }, +const TABLE_ROWS: readonly LeadRecord[] = [ + { id: 'northstar', contact: 'Maya Chen', company: 'Northstar', score: 94, status: 'Qualified' }, + { id: 'arcadia', contact: 'Jon Bell', company: 'Arcadia', score: 88, status: 'Qualified' }, + { id: 'hearth', contact: 'Priya Shah', company: 'Hearth', score: 79, status: 'Review' }, + { id: 'lattice', contact: 'Noah Kim', company: 'Lattice', score: 72, status: 'Review' }, ] as const interface HeroResourcePanelProps { @@ -60,52 +62,6 @@ interface HeroResourcePanelProps { onRunWorkflow: () => void } -function HeroTableResource() { - const [selectedId, setSelectedId] = useState('northstar') - - return ( -
-
- Qualified leads - 4 rows -
-
- Lead - Company - Score - Status -
-
- {TABLE_ROWS.map((row) => ( - - ))} -
-
- ) -} - function HeroFileResource() { return (
@@ -237,7 +193,7 @@ export function HeroResourcePanel({ {activeId === 'workflow' ? ( ) : activeId === 'table' ? ( - + ) : activeId === 'brief' ? ( ) : ( diff --git a/apps/sim/app/(landing)/components/hero/components/hero-platform-loop/production-workflow-stage.tsx b/apps/sim/app/(landing)/components/hero/components/hero-platform-loop/production-workflow-stage.tsx index 190e33863e1..18e64a2a105 100644 --- a/apps/sim/app/(landing)/components/hero/components/hero-platform-loop/production-workflow-stage.tsx +++ b/apps/sim/app/(landing)/components/hero/components/hero-platform-loop/production-workflow-stage.tsx @@ -14,6 +14,7 @@ import { Circle, Minus, Plus, Square, Unlock } from '@sim/emcn/icons' import { CanvasSentenceView, InlineChip, + useCanvasColorMode, WorkflowBlockView, WorkflowEdgeView, } from '@sim/workflow-renderer' @@ -482,6 +483,7 @@ function ProductionWorkflowCanvas({ scripted, viewportInset, }: ProductionWorkflowStageProps) { + const colorMode = useCanvasColorMode() const { getNode, getViewport, setCenter, setViewport } = useReactFlow() const containerRef = useRef(null) const focusFrameRef = useRef(0) @@ -738,6 +740,7 @@ function ProductionWorkflowCanvas({ )} > setSelectedId(node.id) : undefined} proOptions={{ hideAttribution: true }} - className={REACT_FLOW_STYLES} + className={cn( + REACT_FLOW_STYLES, + interactive ? '[--xy-background-color:var(--bg)]' : '[--xy-background-color:transparent]' + )} /> {interactive && } {interactive && ( diff --git a/apps/sim/app/(landing)/components/navbar/components/mobile-nav/mobile-nav.tsx b/apps/sim/app/(landing)/components/navbar/components/mobile-nav/mobile-nav.tsx index 7f00d954553..d778c8e2d87 100644 --- a/apps/sim/app/(landing)/components/navbar/components/mobile-nav/mobile-nav.tsx +++ b/apps/sim/app/(landing)/components/navbar/components/mobile-nav/mobile-nav.tsx @@ -145,16 +145,6 @@ export function MobileNav({ stars }: MobileNavProps) { {menu.label} - {menu.index && ( - updateOpen(false)} - className={SHEET_ROW} - > - {menu.index.label} - - )} {menu.sections.map((section) => (
{section.items.map((item) => { diff --git a/apps/sim/app/(landing)/components/navbar/components/nav-menu-chip/components/nav-menu-preview/components/models-menu-preview/models-menu-preview.tsx b/apps/sim/app/(landing)/components/navbar/components/nav-menu-chip/components/nav-menu-preview/components/models-menu-preview/models-menu-preview.tsx index 505130f40c8..eb422972338 100644 --- a/apps/sim/app/(landing)/components/navbar/components/nav-menu-chip/components/nav-menu-preview/components/models-menu-preview/models-menu-preview.tsx +++ b/apps/sim/app/(landing)/components/navbar/components/nav-menu-chip/components/nav-menu-preview/components/models-menu-preview/models-menu-preview.tsx @@ -1,16 +1,23 @@ +import 'server-only' + import { BrainCircuit, Search } from '@sim/emcn/icons' -import { AnthropicIcon, GeminiIcon, OpenAIIcon } from '@/components/icons' import { MenuPreviewFrame } from '@/app/(landing)/components/navbar/components/nav-menu-chip/components/nav-menu-preview/components/menu-preview-frame' import { MenuPreviewHeader, MenuPreviewToolbar, } from '@/app/(landing)/components/navbar/components/nav-menu-chip/components/nav-menu-preview/components/menu-preview-header/menu-preview-header' +import { MODEL_CATALOG_PROVIDERS } from '@/app/(landing)/models/utils' -const MODELS = [ - { name: 'GPT-6 Astra', provider: 'OpenAI', icon: OpenAIIcon }, - { name: 'Claude Sonnet 5', provider: 'Anthropic', icon: AnthropicIcon }, - { name: 'Gemini 3.6 Flash', provider: 'Google', icon: GeminiIcon }, -] as const +const FEATURED_MODELS = MODEL_CATALOG_PROVIDERS.flatMap((provider) => + provider.models + .filter((model) => model.featured) + .map((model) => ({ + id: model.id, + name: model.displayName, + provider: provider.name, + icon: provider.icon ?? BrainCircuit, + })) +) /** A quiet model directory extending past the preview's right and bottom edges. */ export function ModelsMenuPreview() { @@ -25,8 +32,8 @@ export function ModelsMenuPreview() {
- {MODELS.map(({ name, provider, icon: Icon }) => ( -
+ {FEATURED_MODELS.map(({ id, name, provider, icon: Icon }) => ( +

{name}

diff --git a/apps/sim/app/(landing)/components/navbar/components/nav-menu-chip/components/nav-menu-preview/nav-menu-preview.tsx b/apps/sim/app/(landing)/components/navbar/components/nav-menu-chip/components/nav-menu-preview/nav-menu-preview.tsx index ac5c4d7f9b3..52d7193703c 100644 --- a/apps/sim/app/(landing)/components/navbar/components/nav-menu-chip/components/nav-menu-preview/nav-menu-preview.tsx +++ b/apps/sim/app/(landing)/components/navbar/components/nav-menu-chip/components/nav-menu-preview/nav-menu-preview.tsx @@ -1,3 +1,4 @@ +import type { ReactNode } from 'react' import { ArrowRight, BookOpen } from '@sim/emcn/icons' import { BlogMenuPreview } from '@/app/(landing)/components/navbar/components/nav-menu-chip/components/nav-menu-preview/components/blog-menu-preview' import { ChangelogMenuPreview } from '@/app/(landing)/components/navbar/components/nav-menu-chip/components/nav-menu-preview/components/changelog-menu-preview' @@ -8,7 +9,6 @@ import { IntegrationsMenuPreview } from '@/app/(landing)/components/navbar/compo import { KnowledgeMenuPreview } from '@/app/(landing)/components/navbar/components/nav-menu-chip/components/nav-menu-preview/components/knowledge-menu-preview' import { LibraryMenuPreview } from '@/app/(landing)/components/navbar/components/nav-menu-chip/components/nav-menu-preview/components/library-menu-preview' import { LogsMenuPreview } from '@/app/(landing)/components/navbar/components/nav-menu-chip/components/nav-menu-preview/components/logs-menu-preview' -import { ModelsMenuPreview } from '@/app/(landing)/components/navbar/components/nav-menu-chip/components/nav-menu-preview/components/models-menu-preview' import { OverviewMenuPreview } from '@/app/(landing)/components/navbar/components/nav-menu-chip/components/nav-menu-preview/components/overview-menu-preview' import { TablesMenuPreview } from '@/app/(landing)/components/navbar/components/nav-menu-chip/components/nav-menu-preview/components/tables-menu-preview' import { WorkflowMenuPreview } from '@/app/(landing)/components/navbar/components/nav-menu-chip/components/nav-menu-preview/components/workflow-menu-preview' @@ -19,6 +19,7 @@ import type { interface NavMenuPreviewProps { item: NavMenuItemData + modelsPreview: ReactNode } interface PreviewGraphicProps { @@ -26,7 +27,7 @@ interface PreviewGraphicProps { } interface ProductGraphicProps extends PreviewGraphicProps { - kind: NavMenuPreviewKind + kind: Exclude } const PREVIEW_ROW = @@ -79,8 +80,6 @@ function PreviewGraphic({ kind, details }: ProductGraphicProps) { return case 'library': return - case 'models': - return case 'overview': return case 'workflows': @@ -102,13 +101,17 @@ function PreviewGraphic({ kind, details }: ProductGraphicProps) { } } -export function NavMenuPreview({ item }: NavMenuPreviewProps) { +export function NavMenuPreview({ item, modelsPreview }: NavMenuPreviewProps) { return (
- + {item.preview.kind === 'models' ? ( + modelsPreview + ) : ( + + )}
) } diff --git a/apps/sim/app/(landing)/components/navbar/components/nav-menu-chip/constants.ts b/apps/sim/app/(landing)/components/navbar/components/nav-menu-chip/constants.ts index 0310e61df18..5030ff0928c 100644 --- a/apps/sim/app/(landing)/components/navbar/components/nav-menu-chip/constants.ts +++ b/apps/sim/app/(landing)/components/navbar/components/nav-menu-chip/constants.ts @@ -209,7 +209,6 @@ export const RESOURCES_MENU: NavMenu = { */ export const CUSTOMERS_MENU: NavMenu = { label: 'Customers', - index: { label: 'All customers', href: '/customers' }, eyebrow: 'Customers', heading: 'Teams building with Sim', description: 'How enterprise teams build, govern, and operate AI agents with Sim.', diff --git a/apps/sim/app/(landing)/components/navbar/components/nav-menu-chip/nav-menu-chip.test.tsx b/apps/sim/app/(landing)/components/navbar/components/nav-menu-chip/nav-menu-chip.test.tsx index cdd4168099b..1d6352e9652 100644 --- a/apps/sim/app/(landing)/components/navbar/components/nav-menu-chip/nav-menu-chip.test.tsx +++ b/apps/sim/app/(landing)/components/navbar/components/nav-menu-chip/nav-menu-chip.test.tsx @@ -37,7 +37,13 @@ vi.mock('@/app/(landing)/components/navbar/components/navbar-shell', () => ({ })) vi.mock( '@/app/(landing)/components/navbar/components/nav-menu-chip/components/nav-menu-card', - () => ({ NavMenuCard: () => null }) + () => ({ + NavMenuCard: ({ item, prefetch }: { item: NavMenuItemData; prefetch?: boolean | null }) => ( + + {item.title} + + ), + }) ) vi.mock( '@/app/(landing)/components/navbar/components/nav-menu-chip/components/nav-menu-logo-marquee', @@ -67,7 +73,7 @@ beforeEach(() => { host = document.createElement('div') document.body.append(host) root = createRoot(host) - act(() => root.render()) + act(() => root.render(Models
} />)) }) afterEach(() => { @@ -100,7 +106,7 @@ function expectSelected(href: string, kind: string) { describe('NavMenuCluster feature selection', () => { it('prefetches destinations only while their menu is open', () => { const overview = element('a[href="/platform"]') - const customers = element('#nav-customers-menu a[href="/customers"]') + const customers = element('#nav-customers-menu a[href="/customers/rivian"]') expect(overview.dataset.prefetch).toBe('disabled') expect(customers.dataset.prefetch).toBe('disabled') diff --git a/apps/sim/app/(landing)/components/navbar/components/nav-menu-chip/nav-menu-chip.tsx b/apps/sim/app/(landing)/components/navbar/components/nav-menu-chip/nav-menu-chip.tsx index 4060b3975f9..80afd4e6fc2 100644 --- a/apps/sim/app/(landing)/components/navbar/components/nav-menu-chip/nav-menu-chip.tsx +++ b/apps/sim/app/(landing)/components/navbar/components/nav-menu-chip/nav-menu-chip.tsx @@ -1,10 +1,8 @@ 'use client' -import { useEffect, useRef, useState } from 'react' +import { type ReactNode, useEffect, useRef, useState } from 'react' import { ChipChevronDown, chipContentLabelClass, chipVariants, cn } from '@sim/emcn' -import Link from 'next/link' import { flushSync } from 'react-dom' -import { ChevronArrow } from '@/app/(landing)/components/chevron-arrow' import { HOME_INSET, LANDING_CONTENT_WIDTH, @@ -21,6 +19,7 @@ import { useNavbarMenu } from '@/app/(landing)/components/navbar/hooks/use-navba interface NavMenuClusterProps { /** Non-empty group of mega-menus that share one stable panel. */ menus: readonly [NavMenu, ...NavMenu[]] + modelsPreview: ReactNode } const PANEL_BASE = @@ -61,7 +60,7 @@ const floatingPanelIdFor = (menu: NavMenu) => `nav-${menu.label.toLowerCase()}-m * panel under its trigger instead of the shared surface, which keeps the * last surface menu so it can fade out with its content intact. */ -export function NavMenuCluster({ menus }: NavMenuClusterProps) { +export function NavMenuCluster({ menus, modelsPreview }: NavMenuClusterProps) { const rootRef = useRef(null) const { open, updateOpen } = useNavbarMenu('desktop') const [activeMenu, setActiveMenu] = useState(menus[0]) @@ -209,17 +208,6 @@ export function NavMenuCluster({ menus }: NavMenuClusterProps) { )}
{menu.marquee === 'customers' && } - {menu.index && ( - - {menu.index.label} - - - )}
)} @@ -282,7 +270,7 @@ export function NavMenuCluster({ menus }: NavMenuClusterProps) { ))}
- +
diff --git a/apps/sim/app/(landing)/components/navbar/components/nav-menu-chip/types.ts b/apps/sim/app/(landing)/components/navbar/components/nav-menu-chip/types.ts index 61d75d2c422..cf8a1f3561e 100644 --- a/apps/sim/app/(landing)/components/navbar/components/nav-menu-chip/types.ts +++ b/apps/sim/app/(landing)/components/navbar/components/nav-menu-chip/types.ts @@ -85,8 +85,6 @@ export interface NavMenuSection { export interface NavMenu { /** Trigger label and accessible name of the panel. */ label: string - /** Index destination shown alongside a menu's featured links. */ - index?: { label: string; href: string } /** Small label above the menu heading. */ eyebrow: string /** Menu-level positioning statement. */ diff --git a/apps/sim/app/(landing)/components/navbar/navbar.tsx b/apps/sim/app/(landing)/components/navbar/navbar.tsx index 5a6fbbd364e..3bd927b3160 100644 --- a/apps/sim/app/(landing)/components/navbar/navbar.tsx +++ b/apps/sim/app/(landing)/components/navbar/navbar.tsx @@ -13,6 +13,7 @@ import { NavMenuCluster, SimWordmark, } from '@/app/(landing)/components/navbar/components' +import { ModelsMenuPreview } from '@/app/(landing)/components/navbar/components/nav-menu-chip/components/nav-menu-preview/components/models-menu-preview' import { DEMO_HREF } from '@/app/(landing)/constants' /** @@ -60,7 +61,7 @@ export function Navbar({ stars }: NavbarProps) {
- + } />
-
+
} filename={example.filename} diff --git a/apps/sim/app/(landing)/enterprise/components/enterprise-platform-loop/enterprise-home-stage.tsx b/apps/sim/app/(landing)/enterprise/components/enterprise-platform-loop/enterprise-home-stage.tsx index 0ab291f45ab..3a6b538ce57 100644 --- a/apps/sim/app/(landing)/enterprise/components/enterprise-platform-loop/enterprise-home-stage.tsx +++ b/apps/sim/app/(landing)/enterprise/components/enterprise-platform-loop/enterprise-home-stage.tsx @@ -52,7 +52,7 @@ interface ComposerProps { */ function Composer({ children, active }: ComposerProps) { return ( -
+

{children}

diff --git a/apps/sim/app/(landing)/enterprise/components/feature-graphics/audit-trail-graphic.tsx b/apps/sim/app/(landing)/enterprise/components/feature-graphics/audit-trail-graphic.tsx index 16b0093323d..1860c3f478f 100644 --- a/apps/sim/app/(landing)/enterprise/components/feature-graphics/audit-trail-graphic.tsx +++ b/apps/sim/app/(landing)/enterprise/components/feature-graphics/audit-trail-graphic.tsx @@ -138,7 +138,7 @@ export function AuditTrailGraphic({ entries = ENTRIES }: AuditTrailGraphicProps 'flex items-center gap-3 px-3 py-2.5', newest && cn( - 'rounded-xl border border-[var(--border-1)] bg-[var(--white)] shadow-xs', + 'rounded-xl border border-[var(--border-1)] bg-[var(--white)] shadow-xs dark:bg-[var(--surface-4)]', styles.stampIn ) )} diff --git a/apps/sim/app/(landing)/enterprise/components/feature-graphics/it-platform-teams-graphic.tsx b/apps/sim/app/(landing)/enterprise/components/feature-graphics/it-platform-teams-graphic.tsx index 1707e0dbf5d..d92847a3704 100644 --- a/apps/sim/app/(landing)/enterprise/components/feature-graphics/it-platform-teams-graphic.tsx +++ b/apps/sim/app/(landing)/enterprise/components/feature-graphics/it-platform-teams-graphic.tsx @@ -107,7 +107,7 @@ export function ItPlatformTeamsGraphic({
-
+
{cardTitle} diff --git a/apps/sim/app/(landing)/enterprise/components/feature-graphics/run-monitoring-graphic.tsx b/apps/sim/app/(landing)/enterprise/components/feature-graphics/run-monitoring-graphic.tsx index 23a0c0dc469..22a775e7499 100644 --- a/apps/sim/app/(landing)/enterprise/components/feature-graphics/run-monitoring-graphic.tsx +++ b/apps/sim/app/(landing)/enterprise/components/feature-graphics/run-monitoring-graphic.tsx @@ -145,7 +145,7 @@ export function RunMonitoringGraphic({
{outputLabel} -
+
{`{ "${outputPairs[0].key}": `} {outputPairs[0].value} diff --git a/apps/sim/app/(landing)/enterprise/components/feature-graphics/staging-graphic.tsx b/apps/sim/app/(landing)/enterprise/components/feature-graphics/staging-graphic.tsx index 26157cfea69..27f1c279279 100644 --- a/apps/sim/app/(landing)/enterprise/components/feature-graphics/staging-graphic.tsx +++ b/apps/sim/app/(landing)/enterprise/components/feature-graphics/staging-graphic.tsx @@ -107,7 +107,7 @@ export function StagingGraphic({
-
+
{changeTag} diff --git a/apps/sim/app/(landing)/enterprise/components/feature-graphics/technical-teams-graphic.tsx b/apps/sim/app/(landing)/enterprise/components/feature-graphics/technical-teams-graphic.tsx index cbddeac12eb..1eadc07d7f1 100644 --- a/apps/sim/app/(landing)/enterprise/components/feature-graphics/technical-teams-graphic.tsx +++ b/apps/sim/app/(landing)/enterprise/components/feature-graphics/technical-teams-graphic.tsx @@ -114,7 +114,7 @@ export function TechnicalTeamsGraphic({ ))}
-
+
))} -
+
{footerLabel} diff --git a/apps/sim/app/(landing)/solutions/components/feature-graphics/knowledge-answer-graphic.tsx b/apps/sim/app/(landing)/solutions/components/feature-graphics/knowledge-answer-graphic.tsx index 79cd1e6c58e..59f7da35103 100644 --- a/apps/sim/app/(landing)/solutions/components/feature-graphics/knowledge-answer-graphic.tsx +++ b/apps/sim/app/(landing)/solutions/components/feature-graphics/knowledge-answer-graphic.tsx @@ -59,7 +59,7 @@ export function KnowledgeAnswerGraphic({
@@ -77,7 +77,7 @@ export function KnowledgeAnswerGraphic({
diff --git a/apps/sim/app/(landing)/solutions/finance/components/feature-graphics/reconcile-graphic.tsx b/apps/sim/app/(landing)/solutions/finance/components/feature-graphics/reconcile-graphic.tsx index c42beb382dc..47285a83a62 100644 --- a/apps/sim/app/(landing)/solutions/finance/components/feature-graphics/reconcile-graphic.tsx +++ b/apps/sim/app/(landing)/solutions/finance/components/feature-graphics/reconcile-graphic.tsx @@ -85,7 +85,7 @@ export function ReconcileGraphic() {
diff --git a/apps/sim/app/(landing)/tables/components/tables-records-preview/components/lead-record-list/lead-record-list.tsx b/apps/sim/app/(landing)/tables/components/tables-records-preview/components/lead-record-list/lead-record-list.tsx index 3d4fedb1acf..c9e3e525b97 100644 --- a/apps/sim/app/(landing)/tables/components/tables-records-preview/components/lead-record-list/lead-record-list.tsx +++ b/apps/sim/app/(landing)/tables/components/tables-records-preview/components/lead-record-list/lead-record-list.tsx @@ -21,8 +21,13 @@ const COLUMNS = [ export function LeadRecordList({ rows, selectedId, onSelect, showContact }: LeadRecordListProps) { const columns = showContact ? COLUMNS : COLUMNS.slice(0, 3) return ( -
- +
+
diff --git a/apps/sim/app/(landing)/tables/components/tables-records-preview/tables-records-preview.tsx b/apps/sim/app/(landing)/tables/components/tables-records-preview/tables-records-preview.tsx index b134303c7cb..2401e673318 100644 --- a/apps/sim/app/(landing)/tables/components/tables-records-preview/tables-records-preview.tsx +++ b/apps/sim/app/(landing)/tables/components/tables-records-preview/tables-records-preview.tsx @@ -1,109 +1,17 @@ -'use client' - -import { useRef, useState } from 'react' -import { - Chip, - DropdownMenu, - DropdownMenuContent, - DropdownMenuItem, - DropdownMenuTrigger, -} from '@sim/emcn' -import { Check, ChevronDown, Columns3, ListFilter, Table } from '@sim/emcn/icons' -import { - MenuPreviewHeader, - MenuPreviewToolbar, -} from '@/app/(landing)/components/navbar/components/nav-menu-chip/components/nav-menu-preview/components/menu-preview-header/menu-preview-header' import { EdgeFade } from '@/app/(landing)/components/shared/edge-fade' -import { usePreviewDialogFocus } from '@/app/(landing)/hooks/use-preview-dialog-focus' -import { LeadRecordDetail } from '@/app/(landing)/tables/components/tables-records-preview/components/lead-record-detail' -import { LeadRecordList } from '@/app/(landing)/tables/components/tables-records-preview/components/lead-record-list' -import { - type LeadRecord, - ROWS, -} from '@/app/(landing)/tables/components/tables-records-preview/data' +import { TablesRecordsTable } from '@/app/(landing)/tables/components/tables-records-preview/tables-records-table' -/** The native ruled Tables grid and Edit Row dialog, backed only by local demo records. */ +/** A framed view of the same interactive Tables surface used in the homepage resource pane. */ export function TablesRecordsPreview() { - const filterButtonRef = useRef(null) - const [rows, setRows] = useState(ROWS) - const [selectedId, setSelectedId] = useState(null) - const [status, setStatus] = useState(null) - const [showContact, setShowContact] = useState(true) - const selected = rows.find((row) => row.id === selectedId) - const visibleRows = rows.filter((row) => !status || row.status === status) - const dialogOpenerRef = usePreviewDialogFocus(Boolean(selected), filterButtonRef) - return (
-
- - - - - - - Filter - - - - setStatus(null)} active={status === null}> - All statuses - - {(['Qualified', 'Review'] as const).map((value) => ( - setStatus(value)} - active={status === value} - > - {value} - - ))} - - - - - - Columns - - - setShowContact((value) => !value)}> - {showContact && }Contact - - - - - - { - dialogOpenerRef.current = opener - setSelectedId(id) - }} - showContact={showContact} - /> +
+
- {selected && ( - setSelectedId(null)} - onSave={(record) => { - setRows((current) => current.map((row) => (row.id === record.id ? record : row))) - setSelectedId(null) - }} - /> - )}
) } diff --git a/apps/sim/app/(landing)/tables/components/tables-records-preview/tables-records-table.tsx b/apps/sim/app/(landing)/tables/components/tables-records-preview/tables-records-table.tsx new file mode 100644 index 00000000000..808da77d971 --- /dev/null +++ b/apps/sim/app/(landing)/tables/components/tables-records-preview/tables-records-table.tsx @@ -0,0 +1,106 @@ +'use client' + +import { useRef, useState } from 'react' +import { + Chip, + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuTrigger, +} from '@sim/emcn' +import { Check, ChevronDown, Columns3, ListFilter, Table } from '@sim/emcn/icons' +import { + MenuPreviewHeader, + MenuPreviewToolbar, +} from '@/app/(landing)/components/navbar/components/nav-menu-chip/components/nav-menu-preview/components/menu-preview-header/menu-preview-header' +import { usePreviewDialogFocus } from '@/app/(landing)/hooks/use-preview-dialog-focus' +import { LeadRecordDetail } from '@/app/(landing)/tables/components/tables-records-preview/components/lead-record-detail' +import { LeadRecordList } from '@/app/(landing)/tables/components/tables-records-preview/components/lead-record-list' +import { + type LeadRecord, + ROWS, +} from '@/app/(landing)/tables/components/tables-records-preview/data' + +interface TablesRecordsTableProps { + initialRows?: readonly LeadRecord[] +} + +/** The native ruled Tables grid and Edit Row dialog, backed only by local demo records. */ +export function TablesRecordsTable({ initialRows = ROWS }: TablesRecordsTableProps) { + const filterButtonRef = useRef(null) + const [rows, setRows] = useState(initialRows) + const [selectedId, setSelectedId] = useState(null) + const [status, setStatus] = useState(null) + const [showContact, setShowContact] = useState(true) + const selected = rows.find((row) => row.id === selectedId) + const visibleRows = rows.filter((row) => !status || row.status === status) + const dialogOpenerRef = usePreviewDialogFocus(Boolean(selected), filterButtonRef) + + return ( +
+ + + + + + + Filter + + + + setStatus(null)} active={status === null}> + All statuses + + {(['Qualified', 'Review'] as const).map((value) => ( + setStatus(value)} + active={status === value} + > + {value} + + ))} + + + + + + Columns + + + setShowContact((value) => !value)}> + {showContact && }Contact + + + + + + { + dialogOpenerRef.current = opener + setSelectedId(id) + }} + showContact={showContact} + /> + {selected && ( + setSelectedId(null)} + onSave={(record) => { + setRows((current) => current.map((row) => (row.id === record.id ? record : row))) + setSelectedId(null) + }} + /> + )} +
+ ) +} diff --git a/apps/sim/public/landing/customer-stories/exp-house-color-loop.mp4 b/apps/sim/public/landing/customer-stories/exp-house-color-loop.mp4 new file mode 100644 index 00000000000..54103b50671 Binary files /dev/null and b/apps/sim/public/landing/customer-stories/exp-house-color-loop.mp4 differ diff --git a/apps/sim/public/landing/customer-stories/exp-house-color-poster.jpg b/apps/sim/public/landing/customer-stories/exp-house-color-poster.jpg new file mode 100644 index 00000000000..12cd7002f7f Binary files /dev/null and b/apps/sim/public/landing/customer-stories/exp-house-color-poster.jpg differ