Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions apps/sim/app/(home)/components/footer/footer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ const RESOURCES_LINKS: FooterItem[] = [
{ label: 'Blog', href: '/blog' },
// { label: 'Templates', href: '/templates' },
{ label: 'Docs', href: 'https://docs.sim.ai', external: true },
{ label: 'Models', href: '/models' },
// { label: 'Academy', href: '/academy' },
{ label: 'Partners', href: '/partners' },
{ label: 'Careers', href: 'https://jobs.ashbyhq.com/sim', external: true },
Expand Down
63 changes: 63 additions & 0 deletions apps/sim/app/(landing)/components/landing-faq.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
'use client'

import { useState } from 'react'
import { ChevronDown } from '@/components/emcn'
import { cn } from '@/lib/core/utils/cn'

export interface LandingFAQItem {
question: string
answer: string
}

interface LandingFAQProps {
faqs: LandingFAQItem[]
}

export function LandingFAQ({ faqs }: LandingFAQProps) {
const [openIndex, setOpenIndex] = useState<number | null>(0)

return (
<div className='divide-y divide-[var(--landing-border)]'>
{faqs.map(({ question, answer }, index) => {
const isOpen = openIndex === index

return (
<div key={question}>
<button
type='button'
onClick={() => setOpenIndex(isOpen ? null : index)}
className='flex w-full items-start justify-between gap-4 py-5 text-left'
aria-expanded={isOpen}
>
<span
className={cn(
'font-[500] text-[15px] leading-snug transition-colors',
isOpen
? 'text-[var(--landing-text)]'
: 'text-[var(--landing-text-muted)] hover:text-[var(--landing-text)]'
)}
>
{question}
</span>
<ChevronDown
className={cn(
'mt-0.5 h-4 w-4 shrink-0 text-[#555] transition-transform duration-200',
isOpen ? 'rotate-180' : 'rotate-0'
)}
aria-hidden='true'
/>
</button>

{isOpen && (
<div className='pb-5'>
<p className='text-[14px] text-[var(--landing-text-muted)] leading-[1.75]'>
{answer}
</p>
</div>
)}
</div>
)
})}
</div>
)
}
Original file line number Diff line number Diff line change
@@ -1,58 +1,10 @@
'use client'

import { useState } from 'react'
import { ChevronDown } from '@/components/emcn'
import { cn } from '@/lib/core/utils/cn'
import { LandingFAQ } from '@/app/(landing)/components/landing-faq'
import type { FAQItem } from '@/app/(landing)/integrations/data/types'

interface IntegrationFAQProps {
faqs: FAQItem[]
}

export function IntegrationFAQ({ faqs }: IntegrationFAQProps) {
const [openIndex, setOpenIndex] = useState<number | null>(0)

return (
<div className='divide-y divide-[var(--landing-border)]'>
{faqs.map(({ question, answer }, index) => {
const isOpen = openIndex === index
return (
<div key={question}>
<button
type='button'
onClick={() => setOpenIndex(isOpen ? null : index)}
className='flex w-full items-start justify-between gap-4 py-5 text-left'
aria-expanded={isOpen}
>
<span
className={cn(
'font-[500] text-[15px] leading-snug transition-colors',
isOpen
? 'text-[var(--landing-text)]'
: 'text-[var(--landing-text-muted)] hover:text-[var(--landing-text)]'
)}
>
{question}
</span>
<ChevronDown
className={cn(
'mt-0.5 h-4 w-4 shrink-0 text-[#555] transition-transform duration-200',
isOpen ? 'rotate-180' : 'rotate-0'
)}
aria-hidden='true'
/>
</button>

{isOpen && (
<div className='pb-5'>
<p className='text-[14px] text-[var(--landing-text-muted)] leading-[1.75]'>
{answer}
</p>
</div>
)}
</div>
)
})}
</div>
)
return <LandingFAQ faqs={faqs} />
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { notFound } from 'next/navigation'
import { createModelsOgImage } from '@/app/(landing)/models/og-utils'
import {
formatPrice,
formatTokenCount,
getModelBySlug,
getProviderBySlug,
} from '@/app/(landing)/models/utils'

export const runtime = 'edge'
export const contentType = 'image/png'
export const size = {
width: 1200,
height: 630,
}

export default async function Image({
params,
}: {
params: Promise<{ provider: string; model: string }>
}) {
const { provider: providerSlug, model: modelSlug } = await params
const provider = getProviderBySlug(providerSlug)
const model = getModelBySlug(providerSlug, modelSlug)

if (!provider || !model) {
notFound()
}

return createModelsOgImage({
eyebrow: `${provider.name} model`,
title: model.displayName,
subtitle: `${provider.name} pricing, context window, and feature support generated from Sim's model registry.`,
pills: [
`Input ${formatPrice(model.pricing.input)}/1M`,
`Output ${formatPrice(model.pricing.output)}/1M`,
model.contextWindow ? `${formatTokenCount(model.contextWindow)} context` : 'Unknown context',
model.capabilityTags[0] ?? 'Capabilities tracked',
],
domainLabel: `sim.ai${model.href}`,
})
}
Loading
Loading