Skip to content

Commit a54822e

Browse files
committed
fix(landing): refine graphics, navigation, and accessibility
1 parent 38f4664 commit a54822e

39 files changed

Lines changed: 160 additions & 76 deletions

File tree

‎apps/sim/app/(landing)/careers/careers.tsx‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ export default async function Careers({ searchParams }: CareersProps) {
5050
<p className='sr-only'>
5151
Careers at Sim, the open-source AI workspace where teams build, deploy, and manage AI
5252
agents. Sim is hiring engineers, designers, and go-to-market builders to help teams
53-
automate real work across 1,000+ integrations and every major LLM — visually,
53+
automate real work across hundreds of integrations and every major LLM — visually,
5454
conversationally, or with code.
5555
</p>
5656

‎apps/sim/app/(landing)/careers/components/job-board/job-board.tsx‎

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,17 +54,23 @@ export function JobBoard({ postings }: JobBoardProps) {
5454
return (
5555
<div className='flex flex-col gap-10'>
5656
<div className='flex flex-wrap items-center gap-3'>
57+
<span id='career-team-filter-description' className='sr-only'>
58+
Filter roles by team
59+
</span>
5760
<ChipSelect
5861
options={teamOptions}
5962
value={team}
6063
onChange={(value) => setFilters({ team: value })}
61-
aria-label='Filter roles by team'
64+
aria-describedby='career-team-filter-description'
6265
/>
66+
<span id='career-location-filter-description' className='sr-only'>
67+
Filter roles by location
68+
</span>
6369
<ChipSelect
6470
options={locationOptions}
6571
value={location}
6672
onChange={(value) => setFilters({ location: value })}
67-
aria-label='Filter roles by location'
73+
aria-describedby='career-location-filter-description'
6874
/>
6975
</div>
7076

‎apps/sim/app/(landing)/changelog/components/changelog-timeline/changelog-timeline.tsx‎

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -91,22 +91,22 @@ export function ChangelogTimeline({ initialEntries }: ChangelogTimelineProps) {
9191
const headingId = `release-${entry.tag}-heading`
9292
return (
9393
<section key={entry.tag} aria-labelledby={headingId} className='flex flex-col'>
94-
<div className='flex items-center justify-between gap-4'>
94+
<div className='flex flex-wrap items-center justify-between gap-4'>
9595
<div className='flex items-center gap-2'>
9696
<h2 id={headingId} className='text-[18px] text-[var(--text-primary)] leading-[1.3]'>
9797
{entry.tag}
9898
</h2>
9999
{entry.contributors.length > 0 ? (
100-
<div className='flex'>
101-
{entry.contributors.slice(0, 5).map((contributor, index) => (
100+
<div className='flex gap-1'>
101+
{entry.contributors.slice(0, 5).map((contributor) => (
102102
<a
103103
key={contributor}
104104
href={`https://github.com/${contributor}`}
105105
target='_blank'
106106
rel='noopener noreferrer'
107107
aria-label={`View @${contributor} on GitHub`}
108108
title={`@${contributor}`}
109-
className={index === 0 ? 'block' : '-ms-2 block'}
109+
className='block size-6 shrink-0'
110110
>
111111
<Avatar className='size-6 ring-2 ring-[var(--bg)]'>
112112
<AvatarImage
@@ -119,7 +119,7 @@ export function ChangelogTimeline({ initialEntries }: ChangelogTimelineProps) {
119119
</a>
120120
))}
121121
{entry.contributors.length > 5 ? (
122-
<div className='-ms-2 relative flex size-6 items-center justify-center rounded-full bg-[var(--surface-2)] text-[10px] text-[var(--text-body)] ring-2 ring-[var(--bg)] hover:z-10'>
122+
<div className='relative flex size-6 items-center justify-center rounded-full bg-[var(--surface-2)] text-[10px] text-[var(--text-body)] ring-2 ring-[var(--bg)]'>
123123
+{entry.contributors.length - 5}
124124
</div>
125125
) : null}

‎apps/sim/app/(landing)/comparisons/components/source-info/source-info.tsx‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,10 @@ export function SourceLink({ source, children, className }: SourceLinkProps) {
2828
href={source.url}
2929
target='_blank'
3030
rel='noopener noreferrer'
31-
aria-label={`${source.label} (opens source)`}
3231
className={cn('block min-w-0', className)}
3332
>
3433
{children}
34+
<span className='sr-only'> (source: {source.label}, opens in a new tab)</span>
3535
</a>
3636
</Tooltip.Trigger>
3737
<Tooltip.Content>Source: {source.label}</Tooltip.Content>

‎apps/sim/app/(landing)/components/content-index-page/content-index-page.tsx‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -88,9 +88,9 @@ export function ContentIndexPage({
8888
timeZone: 'UTC',
8989
})}
9090
</span>
91-
<h3 className='text-[var(--text-primary)] text-lg leading-tight tracking-[-0.01em]'>
91+
<h2 className='text-[var(--text-primary)] text-lg leading-tight tracking-[-0.01em]'>
9292
{p.title}
93-
</h3>
93+
</h2>
9494
<p className='line-clamp-2 text-[var(--text-secondary)] text-sm leading-[150%]'>
9595
{p.description}
9696
</p>
@@ -127,9 +127,9 @@ export function ContentIndexPage({
127127
timeZone: 'UTC',
128128
})}
129129
</span>
130-
<h3 className='text-[var(--text-primary)] text-base leading-tight tracking-[-0.01em] lg:text-lg lg:leading-7'>
130+
<h2 className='text-[var(--text-primary)] text-base leading-tight tracking-[-0.01em] lg:text-lg lg:leading-7'>
131131
{p.title}
132-
</h3>
132+
</h2>
133133
<p className='line-clamp-2 text-[var(--text-secondary)] text-sm leading-[150%]'>
134134
{p.description}
135135
</p>

‎apps/sim/app/(landing)/components/hero/hero.tsx‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,9 @@ export function Hero() {
3131
>
3232
<p className='sr-only'>
3333
Sim is the open-source AI workspace where teams build, deploy, and manage AI agents for
34-
their organization. Connect 1,000+ integrations and every major LLM, then govern access,
35-
spend, data, and deployment from one place. Build visually, conversationally, or with code,
36-
and run Sim in your own cloud.
34+
their organization. Connect hundreds of integrations and every major LLM, then govern
35+
access, spend, data, and deployment from one place. Build visually, conversationally, or
36+
with code, and run Sim in your own cloud.
3737
</p>
3838

3939
<div className={HOME_INSET}>

‎apps/sim/app/(landing)/components/home-structured-data/home-structured-data.tsx‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ import { JsonLd } from '@/app/(landing)/components/json-ld'
2222
* `WebPage.description` below, so the three surfaces never drift.
2323
*/
2424
export const HOME_PAGE_DESCRIPTION =
25-
'Sim is the open-source AI workspace where companies build, distribute, and govern AI agents. 1,000+ integrations, every major LLM, permission groups, spend limits, and self-hosting.'
25+
'Sim is the open-source AI workspace where companies build, distribute, and govern AI agents. Hundreds of integrations, every major LLM, permission groups, spend limits, and self-hosting.'
2626

2727
/**
2828
* The home page's canonical title - the single string shared by the
@@ -62,7 +62,7 @@ const HOME_JSON_LD = {
6262
url: SITE_URL,
6363
name: 'Sim, The AI Workspace',
6464
description:
65-
'Sim is the open-source AI workspace where companies build, distribute, and govern AI agents in one place. Teams build agents visually, conversationally, or with code across 1,000+ integrations and every major LLM, while administrators control model access, integration access, spend limits, and deployment. Trusted by over 100,000 builders. SOC2 compliant and self-hostable.',
65+
'Sim is the open-source AI workspace where companies build, distribute, and govern AI agents in one place. Teams build agents visually, conversationally, or with code across hundreds of integrations and every major LLM, while administrators control model access, integration access, spend limits, and deployment. Trusted by over 100,000 builders. SOC2 compliant and self-hostable.',
6666
applicationCategory: 'BusinessApplication',
6767
applicationSubCategory: 'AI Workspace',
6868
operatingSystem: 'Web',
@@ -110,7 +110,7 @@ const HOME_JSON_LD = {
110110
'Chat: build and manage agents in natural language',
111111
'Visual workflow builder',
112112
'CLI access for coding agents and terminal workflows',
113-
'1,000+ integrations',
113+
'Hundreds of integrations',
114114
'LLM orchestration (OpenAI, Anthropic, Google, xAI, Mistral, Perplexity)',
115115
'Knowledge base creation',
116116
'Table creation',

‎apps/sim/app/(landing)/components/landing-shell/landing-shell.tsx‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ export async function LandingShell({ children }: LandingShellProps) {
2424
const stars = await getGitHubStars()
2525

2626
return (
27-
<div className='relative h-screen overflow-y-auto overscroll-y-none bg-[var(--bg)] text-[var(--text-primary)]'>
27+
<div className='relative h-screen overflow-y-auto overscroll-y-none bg-[var(--bg)] text-[var(--text-primary)] [--text-muted:var(--text-secondary)]'>
2828
<SiteStructuredData />
2929
<a
3030
href='#main-content'

‎apps/sim/app/(landing)/components/navbar/components/mobile-nav/mobile-nav.test.tsx‎

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,12 @@ vi.mock('@sim/emcn', () => ({
1717
vi.mock('@sim/emcn/icons', () => ({ Menu: () => null, X: () => null }))
1818
vi.mock('@/components/icons', () => ({ GithubOutlineIcon: () => null }))
1919
vi.mock('next/link', () => ({
20-
default: (props: AnchorHTMLAttributes<HTMLAnchorElement>) => <a {...props} />,
20+
default: ({
21+
prefetch,
22+
...props
23+
}: AnchorHTMLAttributes<HTMLAnchorElement> & { prefetch?: boolean | null }) => (
24+
<a {...props} data-prefetch={prefetch === false ? 'disabled' : 'auto'} />
25+
),
2126
}))
2227
vi.mock('@/app/(landing)/components/landing-cta-link', () => ({
2328
LandingCtaLink: ({ children, href, onClick }: AnchorHTMLAttributes<HTMLAnchorElement>) => (
@@ -77,6 +82,20 @@ function trigger(): HTMLButtonElement {
7782
}
7883

7984
describe('MobileNav dismissal', () => {
85+
it('enables prefetch only while the sheet is open and closes on navigation', () => {
86+
const link = host.querySelector<HTMLAnchorElement>('#mobile-nav-sheet a[href="/workflows"]')
87+
if (!link) throw new Error('Missing workflow link')
88+
expect(link.dataset.prefetch).toBe('disabled')
89+
90+
act(() => trigger().click())
91+
expect(link.dataset.prefetch).toBe('auto')
92+
link.addEventListener('click', (event) => event.preventDefault(), { once: true })
93+
act(() => link.dispatchEvent(new MouseEvent('click', { bubbles: true, cancelable: true })))
94+
expect(trigger().getAttribute('aria-expanded')).toBe('false')
95+
expect(link.dataset.prefetch).toBe('disabled')
96+
expect(setMenuOpen).toHaveBeenLastCalledWith('mobile', false)
97+
})
98+
8099
it('releases its scroll lock when resizing to desktop and stays closed when returning', () => {
81100
act(() => trigger().click())
82101
expect(trigger().getAttribute('aria-expanded')).toBe('true')

‎apps/sim/app/(landing)/components/navbar/components/mobile-nav/mobile-nav.tsx‎

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,12 @@ export function MobileNav({ stars }: MobileNavProps) {
130130
<div className='mx-auto flex w-full max-w-[1728px] flex-col gap-1 px-7 pt-2 pb-5'>
131131
<div className='flex flex-col gap-2 pb-4 sm:hidden'>
132132
<NavbarAuthPill size='default' onNavigate={() => updateOpen(false)} />
133-
<LandingCtaLink href={DEMO_HREF} withArrow onClick={() => updateOpen(false)}>
133+
<LandingCtaLink
134+
href={DEMO_HREF}
135+
prefetch={open ? null : false}
136+
withArrow
137+
onClick={() => updateOpen(false)}
138+
>
134139
Request a demo
135140
</LandingCtaLink>
136141
</div>
@@ -143,6 +148,7 @@ export function MobileNav({ stars }: MobileNavProps) {
143148
{menu.index && (
144149
<Link
145150
href={menu.index.href}
151+
prefetch={open ? null : false}
146152
onClick={() => updateOpen(false)}
147153
className={SHEET_ROW}
148154
>
@@ -169,6 +175,7 @@ export function MobileNav({ stars }: MobileNavProps) {
169175
<Link
170176
key={item.title}
171177
href={item.href}
178+
prefetch={open ? null : false}
172179
onClick={() => updateOpen(false)}
173180
className={SHEET_ROW}
174181
>
@@ -182,7 +189,13 @@ export function MobileNav({ stars }: MobileNavProps) {
182189
))}
183190

184191
{STANDALONE_LINKS.map(({ label, href }) => (
185-
<Link key={label} href={href} onClick={() => updateOpen(false)} className={SHEET_ROW}>
192+
<Link
193+
key={label}
194+
href={href}
195+
prefetch={open ? null : false}
196+
onClick={() => updateOpen(false)}
197+
className={SHEET_ROW}
198+
>
186199
{label}
187200
</Link>
188201
))}

0 commit comments

Comments
 (0)