Skip to content

Commit 734b988

Browse files
committed
fix(landing): preserve accessible controls and readable terminal previews
1 parent c17c5f3 commit 734b988

8 files changed

Lines changed: 68 additions & 14 deletions

File tree

‎apps/sim/app/(landing)/components/features/components/features-rail/features-rail.test.tsx‎

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,39 @@ describe('FeaturesRail', () => {
145145
expect(mount(true).scrollLeft).toBe(SET)
146146
})
147147

148+
it('keeps interactive controls keyboard-accessible only in the home copy', () => {
149+
let activations = 0
150+
act(() =>
151+
root?.render(
152+
<FeaturesRail label='Interactive features'>
153+
<div>
154+
<button type='button' onClick={() => activations++}>
155+
Open folder
156+
</button>
157+
<input aria-label='Search files' />
158+
</div>
159+
</FeaturesRail>
160+
)
161+
)
162+
163+
const homeControls = host?.querySelectorAll<HTMLElement>(
164+
'[data-copy="home"] :is(button, input)'
165+
)
166+
expect(homeControls).toHaveLength(2)
167+
for (const control of homeControls ?? []) expect(control.tabIndex).toBe(0)
168+
169+
const cloneControls = host?.querySelectorAll<HTMLElement>(
170+
':is([data-copy="lead"], [data-copy="tail"]) :is(button, input)'
171+
)
172+
expect(cloneControls).toHaveLength(4)
173+
for (const control of cloneControls ?? []) expect(control.tabIndex).toBe(-1)
174+
175+
const cloneButton = host?.querySelector<HTMLButtonElement>('[data-copy="tail"] button')
176+
expect(cloneButton?.disabled).toBe(false)
177+
act(() => cloneButton?.click())
178+
expect(activations).toBe(1)
179+
})
180+
148181
it('drags with the mouse, scrolling by the pointer delta and swallowing the click', () => {
149182
const rail = mount()
150183
const link = rail.querySelector<HTMLAnchorElement>('[data-copy="home"] a')

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -142,10 +142,10 @@ export function FeaturesRail({ label, children }: FeaturesRailProps) {
142142
if (Math.abs(next - rail.scrollLeft) > FOLD_TOLERANCE) rail.scrollLeft = next
143143
}
144144

145-
for (const link of rail.querySelectorAll<HTMLElement>(
146-
'[data-copy="lead"] a, [data-copy="tail"] a'
145+
for (const control of rail.querySelectorAll<HTMLElement>(
146+
':is([data-copy="lead"], [data-copy="tail"]) :is(a, button, input, select, textarea, [tabindex])'
147147
)) {
148-
link.tabIndex = -1
148+
control.tabIndex = -1
149149
}
150150
measure()
151151
rail.scrollLeft = foldScrollLeft(rail.scrollLeft + setWidthRef.current, setWidthRef.current)

‎apps/sim/app/(landing)/components/hero/components/hero-platform-loop/stage-block-card.tsx‎

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -320,8 +320,8 @@ export function StageBlockCard({
320320
type='button'
321321
variant='ghost'
322322
size={null}
323-
aria-label={label}
324-
onClick={(event) => event.stopPropagation()}
323+
disabled={!decorative}
324+
aria-label={decorative ? label : `${label} unavailable in preview`}
325325
className={getActionButtonClassName(
326326
label === 'Delete' ? 'last' : 'middle',
327327
selected
@@ -331,7 +331,9 @@ export function StageBlockCard({
331331
</Button>
332332
</span>
333333
</Tooltip.Trigger>
334-
<Tooltip.Content side='top'>{label}</Tooltip.Content>
334+
<Tooltip.Content side='top'>
335+
{decorative ? label : `${label} unavailable in preview`}
336+
</Tooltip.Content>
335337
</Tooltip.Root>
336338
))}
337339
</div>

‎apps/sim/app/(landing)/components/shared/cli-graphic/cli-graphic.module.css‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,14 +51,14 @@
5151
max-width: 100%;
5252
white-space: nowrap;
5353
}
54-
.response .started {
54+
.started {
5555
margin: 0;
5656
animation: response-first 12s steps(34, end) infinite;
5757
}
58-
.response .running {
58+
.running {
5959
animation: response-second 12s steps(33, end) infinite;
6060
}
61-
.response .completed {
61+
.completed {
6262
animation: response-third 12s steps(37, end) infinite;
6363
}
6464
@keyframes response-first {

‎apps/sim/app/(landing)/components/shared/code-window-graphic/code-window-graphic.module.css‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,11 +166,18 @@
166166
padding: 18px 14px;
167167
}
168168
.lines {
169+
width: 100%;
169170
font-size: 11px;
170171
line-height: 23px;
171172
}
172173
.row {
173174
gap: 8px;
175+
width: 100%;
176+
}
177+
.typed {
178+
min-width: 0;
179+
white-space: pre-wrap;
180+
overflow-wrap: anywhere;
174181
}
175182
}
176183

‎apps/sim/app/(landing)/components/shared/code-window-graphic/code-window-graphic.tsx‎

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,18 @@ import { cn } from '@sim/emcn'
22
import { TerminalWindow } from '@sim/emcn/icons'
33
import styles from '@/app/(landing)/components/shared/code-window-graphic/code-window-graphic.module.css'
44

5+
/** The compact preview sequences up to six visual command rows. */
6+
export type CodeWindowCommands =
7+
| readonly [string]
8+
| readonly [string, string]
9+
| readonly [string, string, string]
10+
| readonly [string, string, string, string]
11+
| readonly [string, string, string, string, string]
12+
| readonly [string, string, string, string, string, string]
13+
514
interface CodeWindowGraphicProps {
615
filename: string
7-
commands: readonly string[]
16+
commands: CodeWindowCommands
817
}
918

1019
/** A complete terminal window with sequentially typed, documentation-backed CLI examples. */

‎apps/sim/app/(landing)/components/solutions-page/components/solutions-product-page/components/product-code-example.tsx‎

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,13 @@ export function ProductCodeExample({ example }: ProductCodeExampleProps) {
3636
</LandingCtaLink>
3737
</div>
3838
</div>
39-
<div className='relative h-[340px] min-w-0 overflow-hidden rounded-2xl bg-[var(--surface-3)] pt-8 pl-8 max-sm:h-[300px] max-sm:pt-5 max-sm:pl-5'>
40-
<div className='w-[calc(100%+96px)]'>
39+
<div className='relative h-[340px] min-w-0 overflow-hidden rounded-2xl bg-[var(--surface-3)] pt-8 pl-8 max-sm:h-auto max-sm:p-3'>
40+
<div className='w-[calc(100%+96px)] max-sm:w-full'>
4141
<CodeWindowGraphic filename={example.filename} commands={example.commands} />
4242
</div>
43-
<EdgeFade ground='surface' edges={['right', 'bottom']} depth='preview' />
43+
<div className='pointer-events-none absolute inset-0 max-sm:hidden'>
44+
<EdgeFade ground='surface' edges={['right', 'bottom']} depth='preview' />
45+
</div>
4446
</div>
4547
</div>
4648
</section>

‎apps/sim/app/(landing)/components/solutions-page/types.ts‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import type { ReactNode } from 'react'
2+
import type { CodeWindowCommands } from '@/app/(landing)/components/shared/code-window-graphic/code-window-graphic'
23

34
/**
45
* Solutions-page configuration - the entire content contract a route passes to
@@ -157,5 +158,5 @@ export interface SolutionsProductCodeExampleConfig {
157158
title: string
158159
description: string
159160
filename: string
160-
commands: readonly string[]
161+
commands: CodeWindowCommands
161162
}

0 commit comments

Comments
 (0)