From 7da8f94a456616319e668dc5cb7462b81eb6896e Mon Sep 17 00:00:00 2001 From: Bill Leoutsakos Date: Thu, 24 Sep 2026 11:45:04 -0700 Subject: [PATCH 1/2] improvement(ui): share product page heading recipe --- .../app/o/[organizationId]/home/organization-home.tsx | 4 ++-- .../o/[organizationId]/search/search-results-view.tsx | 10 ++++++++-- .../workspace/[workspaceId]/components/error/error.tsx | 6 ++---- apps/sim/app/workspace/[workspaceId]/home/home.tsx | 4 ++-- packages/emcn/src/components/index.ts | 1 + .../emcn/src/components/page-heading/page-heading.ts | 3 +++ 6 files changed, 18 insertions(+), 10 deletions(-) create mode 100644 packages/emcn/src/components/page-heading/page-heading.ts diff --git a/apps/sim/app/o/[organizationId]/home/organization-home.tsx b/apps/sim/app/o/[organizationId]/home/organization-home.tsx index 1ea4df9bb9c..d8cdfe99765 100644 --- a/apps/sim/app/o/[organizationId]/home/organization-home.tsx +++ b/apps/sim/app/o/[organizationId]/home/organization-home.tsx @@ -1,7 +1,7 @@ 'use client' import { useCallback, useEffect, useState, useSyncExternalStore } from 'react' -import { toast } from '@sim/emcn' +import { cn, pageHeadingClassName, toast } from '@sim/emcn' import { useQueryClient } from '@tanstack/react-query' import Link from 'next/link' import { useQueryStates } from 'nuqs' @@ -382,7 +382,7 @@ function OrganizationHomeContent({
{/* Asymmetric padding biases the group up so the full cluster (heading + input + steps) sits at the optical center */}
-

+

{requestMode === 'assistant' ? `Search ${organization.name}` : requestMode === 'plan' diff --git a/apps/sim/app/o/[organizationId]/search/search-results-view.tsx b/apps/sim/app/o/[organizationId]/search/search-results-view.tsx index 76fc79dd50f..6a3fa1e55e8 100644 --- a/apps/sim/app/o/[organizationId]/search/search-results-view.tsx +++ b/apps/sim/app/o/[organizationId]/search/search-results-view.tsx @@ -1,5 +1,11 @@ import { type ReactNode, useRef } from 'react' -import { cn, scrollFadeAttributes, scrollFadeClass, useScrollEdges } from '@sim/emcn' +import { + cn, + pageHeadingClassName, + scrollFadeAttributes, + scrollFadeClass, + useScrollEdges, +} from '@sim/emcn' import { HEADER_ACTION_CLUSTER, PAGE_HEADER_BAR } from '@/components/page-header-bar' import type { WorkspaceSearchFilters } from '@/lib/api/contracts/knowledge' import type { SearchResource } from '@/lib/mothership/generated/resources' @@ -70,7 +76,7 @@ export function SearchResultsView({
{/* Asymmetric padding biases the group up so heading and field sit at the optical center, as on Home */}
-

+

Search {organization.name}

{composer}
diff --git a/apps/sim/app/workspace/[workspaceId]/components/error/error.tsx b/apps/sim/app/workspace/[workspaceId]/components/error/error.tsx index 392c085baae..5019383d1a1 100644 --- a/apps/sim/app/workspace/[workspaceId]/components/error/error.tsx +++ b/apps/sim/app/workspace/[workspaceId]/components/error/error.tsx @@ -1,7 +1,7 @@ 'use client' import { type ReactNode, useEffect } from 'react' -import { Chip } from '@sim/emcn' +import { Chip, pageHeadingClassName } from '@sim/emcn' import { TriangleAlert } from '@sim/emcn/icons' import { createLogger } from '@sim/logger' @@ -43,9 +43,7 @@ export function ErrorShell({ title, description, icon, children }: ErrorShellPro
-

- {title} -

+

{title}

{description}

diff --git a/apps/sim/app/workspace/[workspaceId]/home/home.tsx b/apps/sim/app/workspace/[workspaceId]/home/home.tsx index 9fbf9461e75..f1dadf41702 100644 --- a/apps/sim/app/workspace/[workspaceId]/home/home.tsx +++ b/apps/sim/app/workspace/[workspaceId]/home/home.tsx @@ -1,7 +1,7 @@ 'use client' import { useCallback, useEffect, useRef, useState } from 'react' -import { cn, toast } from '@sim/emcn' +import { cn, pageHeadingClassName, toast } from '@sim/emcn' import { createLogger } from '@sim/logger' import { useQueryClient } from '@tanstack/react-query' import { useParams } from 'next/navigation' @@ -434,7 +434,7 @@ function HomeContent({ chatId, userName, userId }: HomeProps) {
{/* Asymmetric padding biases the group up so the full cluster (heading + input + suggestions) sits at the optical center */}
-

+

What should we get done{firstName ? `, ${firstName}` : ''}?

diff --git a/packages/emcn/src/components/index.ts b/packages/emcn/src/components/index.ts index 8a6c0391020..d7c97a2d793 100644 --- a/packages/emcn/src/components/index.ts +++ b/packages/emcn/src/components/index.ts @@ -197,6 +197,7 @@ export { overflowTextClipClass, overflowTextFadeClass, } from './overflow-text/overflow-text' +export { pageHeadingClassName } from './page-heading/page-heading' export { Popover, PopoverAnchor, diff --git a/packages/emcn/src/components/page-heading/page-heading.ts b/packages/emcn/src/components/page-heading/page-heading.ts new file mode 100644 index 00000000000..89f4c64bba5 --- /dev/null +++ b/packages/emcn/src/components/page-heading/page-heading.ts @@ -0,0 +1,3 @@ +/** Typography shared by the centered product page and error headings. */ +export const pageHeadingClassName = + 'text-balance font-season text-[26px] text-[var(--text-primary)] leading-[1.15] tracking-[-0.01em] sm:text-[28px]' From d1a43b55620371e069b80ffa5db4a36c0e638fe4 Mon Sep 17 00:00:00 2001 From: Bill Leoutsakos Date: Thu, 24 Sep 2026 12:27:16 -0700 Subject: [PATCH 2/2] test: include shared heading export in logs error mock --- apps/sim/app/workspace/[workspaceId]/logs/error.test.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/sim/app/workspace/[workspaceId]/logs/error.test.tsx b/apps/sim/app/workspace/[workspaceId]/logs/error.test.tsx index cd7f30ee2f2..9c1e4904856 100644 --- a/apps/sim/app/workspace/[workspaceId]/logs/error.test.tsx +++ b/apps/sim/app/workspace/[workspaceId]/logs/error.test.tsx @@ -6,6 +6,7 @@ import { createRoot, type Root } from 'react-dom/client' import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' vi.mock('@sim/emcn', () => ({ + pageHeadingClassName: 'test-page-heading', Chip: ({ children, ...props }: { children: ReactNode } & Record) => ( ),