Skip to content

Commit 1728c37

Browse files
authored
improvement(landing): lighthouse performance and accessibility fixes (#3837)
* improvement(landing): lighthouse performance and accessibility fixes * improvement(landing): extract FeatureToggleItem to deduplicate accessibility logic * lint * fix(landing): ensure explicit delay prop takes precedence over transition spread
1 parent 82e58a5 commit 1728c37

File tree

8 files changed

+89
-65
lines changed

8 files changed

+89
-65
lines changed

apps/sim/app/(home)/components/collaboration/collaboration.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -288,7 +288,6 @@ export default function Collaboration() {
288288
width={876}
289289
height={480}
290290
className='h-full w-auto object-left md:min-w-[100vw]'
291-
priority
292291
/>
293292
</div>
294293
<div className='hidden lg:block'>

apps/sim/app/(home)/components/enterprise/components/access-control-panel.tsx

Lines changed: 77 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,56 @@ function ProviderPreviewIcon({ providerId }: { providerId?: string }) {
8181
)
8282
}
8383

84+
interface FeatureToggleItemProps {
85+
feature: PermissionFeature
86+
enabled: boolean
87+
color: string
88+
isInView: boolean
89+
delay: number
90+
textClassName: string
91+
transition: Record<string, unknown>
92+
onToggle: () => void
93+
}
94+
95+
function FeatureToggleItem({
96+
feature,
97+
enabled,
98+
color,
99+
isInView,
100+
delay,
101+
textClassName,
102+
transition,
103+
onToggle,
104+
}: FeatureToggleItemProps) {
105+
return (
106+
<motion.div
107+
key={feature.key}
108+
role='button'
109+
tabIndex={0}
110+
aria-label={`Toggle ${feature.name}`}
111+
aria-pressed={enabled}
112+
className='flex cursor-pointer items-center gap-2 rounded-[4px] py-0.5'
113+
initial={{ opacity: 0, x: -6 }}
114+
animate={isInView ? { opacity: 1, x: 0 } : {}}
115+
transition={{ ...transition, delay }}
116+
onClick={onToggle}
117+
onKeyDown={(e) => {
118+
if (e.key === 'Enter' || e.key === ' ') {
119+
e.preventDefault()
120+
onToggle()
121+
}
122+
}}
123+
whileTap={{ scale: 0.98 }}
124+
>
125+
<CheckboxIcon checked={enabled} color={color} />
126+
<ProviderPreviewIcon providerId={feature.providerId} />
127+
<span className={textClassName} style={{ color: enabled ? '#F6F6F6AA' : '#F6F6F640' }}>
128+
{feature.name}
129+
</span>
130+
</motion.div>
131+
)
132+
}
133+
84134
export function AccessControlPanel() {
85135
const ref = useRef(null)
86136
const isInView = useInView(ref, { once: true, margin: '-40px' })
@@ -97,39 +147,25 @@ export function AccessControlPanel() {
97147

98148
return (
99149
<div key={category.label} className={catIdx > 0 ? 'mt-4' : ''}>
100-
<span className='font-[430] font-season text-[#F6F6F6]/30 text-[10px] uppercase leading-none tracking-[0.08em]'>
150+
<span className='font-[430] font-season text-[#F6F6F6]/55 text-[10px] uppercase leading-none tracking-[0.08em]'>
101151
{category.label}
102152
</span>
103153
<div className='mt-2 grid grid-cols-2 gap-x-4 gap-y-2'>
104-
{category.features.map((feature, featIdx) => {
105-
const enabled = accessState[feature.key]
106-
107-
return (
108-
<motion.div
109-
key={feature.key}
110-
className='flex cursor-pointer items-center gap-2 rounded-[4px] py-0.5'
111-
initial={{ opacity: 0, x: -6 }}
112-
animate={isInView ? { opacity: 1, x: 0 } : {}}
113-
transition={{
114-
delay: 0.05 + (offsetBefore + featIdx) * 0.04,
115-
duration: 0.3,
116-
}}
117-
onClick={() =>
118-
setAccessState((prev) => ({ ...prev, [feature.key]: !prev[feature.key] }))
119-
}
120-
whileTap={{ scale: 0.98 }}
121-
>
122-
<CheckboxIcon checked={enabled} color={category.color} />
123-
<ProviderPreviewIcon providerId={feature.providerId} />
124-
<span
125-
className='truncate font-[430] font-season text-[13px] leading-none tracking-[0.02em]'
126-
style={{ color: enabled ? '#F6F6F6AA' : '#F6F6F640' }}
127-
>
128-
{feature.name}
129-
</span>
130-
</motion.div>
131-
)
132-
})}
154+
{category.features.map((feature, featIdx) => (
155+
<FeatureToggleItem
156+
key={feature.key}
157+
feature={feature}
158+
enabled={accessState[feature.key]}
159+
color={category.color}
160+
isInView={isInView}
161+
delay={0.05 + (offsetBefore + featIdx) * 0.04}
162+
textClassName='truncate font-[430] font-season text-[13px] leading-none tracking-[0.02em]'
163+
transition={{ duration: 0.3 }}
164+
onToggle={() =>
165+
setAccessState((prev) => ({ ...prev, [feature.key]: !prev[feature.key] }))
166+
}
167+
/>
168+
))}
133169
</div>
134170
</div>
135171
)
@@ -140,43 +176,31 @@ export function AccessControlPanel() {
140176
<div className='hidden lg:block'>
141177
{PERMISSION_CATEGORIES.map((category, catIdx) => (
142178
<div key={category.label} className={catIdx > 0 ? 'mt-4' : ''}>
143-
<span className='font-[430] font-season text-[#F6F6F6]/30 text-[10px] uppercase leading-none tracking-[0.08em]'>
179+
<span className='font-[430] font-season text-[#F6F6F6]/55 text-[10px] uppercase leading-none tracking-[0.08em]'>
144180
{category.label}
145181
</span>
146182
<div className='mt-2 grid grid-cols-2 gap-x-4 gap-y-2'>
147183
{category.features.map((feature, featIdx) => {
148-
const enabled = accessState[feature.key]
149184
const currentIndex =
150185
PERMISSION_CATEGORIES.slice(0, catIdx).reduce(
151186
(sum, c) => sum + c.features.length,
152187
0
153188
) + featIdx
154189

155190
return (
156-
<motion.div
191+
<FeatureToggleItem
157192
key={feature.key}
158-
className='flex cursor-pointer items-center gap-2 rounded-[4px] py-0.5'
159-
initial={{ opacity: 0, x: -6 }}
160-
animate={isInView ? { opacity: 1, x: 0 } : {}}
161-
transition={{
162-
delay: 0.1 + currentIndex * 0.04,
163-
duration: 0.3,
164-
ease: [0.25, 0.46, 0.45, 0.94],
165-
}}
166-
onClick={() =>
193+
feature={feature}
194+
enabled={accessState[feature.key]}
195+
color={category.color}
196+
isInView={isInView}
197+
delay={0.1 + currentIndex * 0.04}
198+
textClassName='truncate font-[430] font-season text-[11px] leading-none tracking-[0.02em] transition-opacity duration-200'
199+
transition={{ duration: 0.3, ease: [0.25, 0.46, 0.45, 0.94] }}
200+
onToggle={() =>
167201
setAccessState((prev) => ({ ...prev, [feature.key]: !prev[feature.key] }))
168202
}
169-
whileTap={{ scale: 0.98 }}
170-
>
171-
<CheckboxIcon checked={enabled} color={category.color} />
172-
<ProviderPreviewIcon providerId={feature.providerId} />
173-
<span
174-
className='truncate font-[430] font-season text-[11px] leading-none tracking-[0.02em] transition-opacity duration-200'
175-
style={{ color: enabled ? '#F6F6F6AA' : '#F6F6F640' }}
176-
>
177-
{feature.name}
178-
</span>
179-
</motion.div>
203+
/>
180204
)
181205
})}
182206
</div>

apps/sim/app/(home)/components/enterprise/components/audit-log-preview.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -146,14 +146,14 @@ function AuditRow({ entry, index }: AuditRowProps) {
146146
</div>
147147

148148
{/* Time */}
149-
<span className='w-[56px] shrink-0 font-[430] font-season text-[#F6F6F6]/30 text-[11px] leading-none tracking-[0.02em]'>
149+
<span className='w-[56px] shrink-0 font-[430] font-season text-[#F6F6F6]/55 text-[11px] leading-none tracking-[0.02em]'>
150150
{timeAgo}
151151
</span>
152152

153153
<span className='min-w-0 truncate font-[430] font-season text-[12px] leading-none tracking-[0.02em]'>
154154
<span className='text-[#F6F6F6]/80'>{entry.actor}</span>
155155
<span className='hidden sm:inline'>
156-
<span className='text-[#F6F6F6]/40'> · </span>
156+
<span className='text-[#F6F6F6]/60'> · </span>
157157
<span className='text-[#F6F6F6]/55'>{entry.description}</span>
158158
</span>
159159
</span>

apps/sim/app/(home)/components/enterprise/enterprise.tsx

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ function TrustStrip() {
8585
<strong className='font-[430] font-season text-small text-white leading-none'>
8686
SOC 2 & HIPAA
8787
</strong>
88-
<span className='font-[430] font-season text-[color-mix(in_srgb,var(--landing-text-subtle)_30%,transparent)] text-xs leading-none tracking-[0.02em] transition-colors group-hover:text-[color-mix(in_srgb,var(--landing-text-subtle)_55%,transparent)]'>
88+
<span className='font-[430] font-season text-[color-mix(in_srgb,var(--landing-text-subtle)_55%,transparent)] text-xs leading-none tracking-[0.02em] transition-colors group-hover:text-[color-mix(in_srgb,var(--landing-text-subtle)_75%,transparent)]'>
8989
Type II · PHI protected →
9090
</span>
9191
</div>
@@ -105,7 +105,7 @@ function TrustStrip() {
105105
<strong className='font-[430] font-season text-small text-white leading-none'>
106106
Open Source
107107
</strong>
108-
<span className='font-[430] font-season text-[color-mix(in_srgb,var(--landing-text-subtle)_30%,transparent)] text-xs leading-none tracking-[0.02em] transition-colors group-hover:text-[color-mix(in_srgb,var(--landing-text-subtle)_55%,transparent)]'>
108+
<span className='font-[430] font-season text-[color-mix(in_srgb,var(--landing-text-subtle)_55%,transparent)] text-xs leading-none tracking-[0.02em] transition-colors group-hover:text-[color-mix(in_srgb,var(--landing-text-subtle)_75%,transparent)]'>
109109
View on GitHub →
110110
</span>
111111
</div>
@@ -120,7 +120,7 @@ function TrustStrip() {
120120
<strong className='font-[430] font-season text-small text-white leading-none'>
121121
SSO & SCIM
122122
</strong>
123-
<span className='font-[430] font-season text-[color-mix(in_srgb,var(--landing-text-subtle)_30%,transparent)] text-xs leading-none tracking-[0.02em]'>
123+
<span className='font-[430] font-season text-[color-mix(in_srgb,var(--landing-text-subtle)_55%,transparent)] text-xs leading-none tracking-[0.02em]'>
124124
Okta, Azure AD, Google
125125
</span>
126126
</div>
@@ -165,7 +165,7 @@ export default function Enterprise() {
165165
<h3 className='font-[430] font-season text-[16px] text-white leading-[120%] tracking-[-0.01em]'>
166166
Audit Trail
167167
</h3>
168-
<p className='mt-2 max-w-[480px] font-[430] font-season text-[#F6F6F6]/50 text-[14px] leading-[150%] tracking-[0.02em]'>
168+
<p className='mt-2 max-w-[480px] font-[430] font-season text-[#F6F6F6]/70 text-[14px] leading-[150%] tracking-[0.02em]'>
169169
Every action is captured with full actor attribution.
170170
</p>
171171
</div>
@@ -179,7 +179,7 @@ export default function Enterprise() {
179179
<h3 className='font-[430] font-season text-[16px] text-white leading-[120%] tracking-[-0.01em]'>
180180
Access Control
181181
</h3>
182-
<p className='mt-1.5 font-[430] font-season text-[#F6F6F6]/50 text-[14px] leading-[150%] tracking-[0.02em]'>
182+
<p className='mt-1.5 font-[430] font-season text-[#F6F6F6]/70 text-[14px] leading-[150%] tracking-[0.02em]'>
183183
Restrict providers, surfaces, and tools per group.
184184
</p>
185185
</div>
@@ -211,7 +211,7 @@ export default function Enterprise() {
211211
(tag, i) => (
212212
<span
213213
key={i}
214-
className='enterprise-feature-marquee-tag whitespace-nowrap border-[var(--landing-bg-elevated)] border-r px-5 py-4 font-[430] font-season text-[color-mix(in_srgb,var(--landing-text-subtle)_40%,transparent)] text-small leading-none tracking-[0.02em] hover:bg-white/[0.04] hover:text-[color-mix(in_srgb,var(--landing-text-subtle)_55%,transparent)]'
214+
className='enterprise-feature-marquee-tag whitespace-nowrap border-[var(--landing-bg-elevated)] border-r px-5 py-4 font-[430] font-season text-[color-mix(in_srgb,var(--landing-text-subtle)_60%,transparent)] text-small leading-none tracking-[0.02em] hover:bg-white/[0.04] hover:text-[color-mix(in_srgb,var(--landing-text-subtle)_80%,transparent)]'
215215
>
216216
{tag}
217217
</span>
@@ -221,7 +221,7 @@ export default function Enterprise() {
221221
</div>
222222

223223
<div className='flex items-center justify-between border-[var(--landing-bg-elevated)] border-t px-6 py-5 md:px-8 md:py-6'>
224-
<p className='font-[430] font-season text-[color-mix(in_srgb,var(--landing-text-subtle)_40%,transparent)] text-base leading-[150%] tracking-[0.02em]'>
224+
<p className='font-[430] font-season text-[color-mix(in_srgb,var(--landing-text-subtle)_60%,transparent)] text-base leading-[150%] tracking-[0.02em]'>
225225
Ready for growth?
226226
</p>
227227
<DemoRequestModal>

apps/sim/app/(home)/components/features/features.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,6 @@ export default function Features() {
190190
width={1440}
191191
height={366}
192192
className='h-auto w-full'
193-
priority
194193
/>
195194
</div>
196195

apps/sim/app/(home)/components/footer/footer-cta.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ export function FooterCTA() {
6767
type='button'
6868
onClick={handleSubmit}
6969
disabled={isEmpty}
70+
aria-label='Submit message'
7071
className='flex h-[28px] w-[28px] items-center justify-center rounded-full border-0 p-0 transition-colors'
7172
style={{
7273
background: isEmpty ? '#C0C0C0' : '#1C1C1C',

apps/sim/app/layout.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,7 @@ export default function RootLayout({ children }: { children: React.ReactNode })
218218
<meta httpEquiv='x-ua-compatible' content='ie=edge' />
219219

220220
{/* OneDollarStats Analytics */}
221+
<link rel='dns-prefetch' href='https://assets.onedollarstats.com' />
221222
<script defer src='https://assets.onedollarstats.com/stonks.js' />
222223

223224
<PublicEnvScript />

apps/sim/app/page.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import type { Metadata } from 'next'
22
import { getBaseUrl } from '@/lib/core/utils/urls'
33
import Landing from '@/app/(home)/landing'
44

5-
export const dynamic = 'force-dynamic'
5+
export const revalidate = 3600
66

77
const baseUrl = getBaseUrl()
88

0 commit comments

Comments
 (0)