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
165 changes: 107 additions & 58 deletions apps/sim/app/(home)/components/navbar/navbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
import { useCallback, useEffect, useRef, useState } from 'react'
import Image from 'next/image'
import Link from 'next/link'
import { useSearchParams } from 'next/navigation'
import { GithubOutlineIcon } from '@/components/icons'
import { useSession } from '@/lib/auth/auth-client'
import { cn } from '@/lib/core/utils/cn'
import {
BlogDropdown,
Expand Down Expand Up @@ -40,6 +42,12 @@ interface NavbarProps {

export default function Navbar({ logoOnly = false, blogPosts = [] }: NavbarProps) {
const brand = getBrandConfig()
const searchParams = useSearchParams()
const { data: session, isPending: isSessionPending } = useSession()
const isAuthenticated = Boolean(session?.user?.id)
const isBrowsingHome = searchParams.has('home')
const useHomeLinks = isAuthenticated || isBrowsingHome
const logoHref = useHomeLinks ? '/?home' : '/'
const [activeDropdown, setActiveDropdown] = useState<DropdownId>(null)
const [hoveredLink, setHoveredLink] = useState<string | null>(null)
const [mobileMenuOpen, setMobileMenuOpen] = useState(false)
Expand Down Expand Up @@ -92,7 +100,7 @@ export default function Navbar({ logoOnly = false, blogPosts = [] }: NavbarProps
itemScope
itemType='https://schema.org/SiteNavigationElement'
>
<Link href='/' className={LOGO_CELL} aria-label={`${brand.name} home`} itemProp='url'>
<Link href={logoHref} className={LOGO_CELL} aria-label={`${brand.name} home`} itemProp='url'>
<span itemProp='name' className='sr-only'>
{brand.name}
</span>
Expand Down Expand Up @@ -121,7 +129,9 @@ export default function Navbar({ logoOnly = false, blogPosts = [] }: NavbarProps
{!logoOnly && (
<>
<ul className='mt-[0.75px] hidden lg:flex'>
{NAV_LINKS.map(({ label, href, external, icon, dropdown }) => {
{NAV_LINKS.map(({ label, href: rawHref, external, icon, dropdown }) => {
const href =
useHomeLinks && rawHref.startsWith('/#') ? `/?home${rawHref.slice(1)}` : rawHref
const hasDropdown = !!dropdown
const isActive = hasDropdown && activeDropdown === dropdown
const isThisHovered = hoveredLink === label
Expand Down Expand Up @@ -206,21 +216,38 @@ export default function Navbar({ logoOnly = false, blogPosts = [] }: NavbarProps

<div className='hidden flex-1 lg:block' />

<div className='hidden items-center gap-[8px] pr-[80px] pl-[20px] lg:flex'>
<Link
href='/login'
className='inline-flex h-[30px] items-center rounded-[5px] border border-[#3d3d3d] px-[9px] text-[#ECECEC] text-[13.5px] transition-colors hover:bg-[#2A2A2A]'
aria-label='Log in'
>
Log in
</Link>
<Link
href='/signup'
className='inline-flex h-[30px] items-center gap-[7px] rounded-[5px] border border-[#FFFFFF] bg-[#FFFFFF] px-[9px] text-[13.5px] text-black transition-colors hover:border-[#E0E0E0] hover:bg-[#E0E0E0]'
aria-label='Get started with Sim'
>
Get started
</Link>
<div
className={cn(
'hidden items-center gap-[8px] pr-[80px] pl-[20px] lg:flex',
isSessionPending && 'invisible'
)}
>
{isAuthenticated ? (
<Link
href='/workspace'
className='inline-flex h-[30px] items-center gap-[7px] rounded-[5px] border border-[#FFFFFF] bg-[#FFFFFF] px-[9px] text-[13.5px] text-black transition-colors hover:border-[#E0E0E0] hover:bg-[#E0E0E0]'
aria-label='Go to app'
>
Go to App
</Link>
) : (
<>
<Link
href='/login'
className='inline-flex h-[30px] items-center rounded-[5px] border border-[#3d3d3d] px-[9px] text-[#ECECEC] text-[13.5px] transition-colors hover:bg-[#2A2A2A]'
aria-label='Log in'
>
Log in
</Link>
<Link
href='/signup'
className='inline-flex h-[30px] items-center gap-[7px] rounded-[5px] border border-[#FFFFFF] bg-[#FFFFFF] px-[9px] text-[13.5px] text-black transition-colors hover:border-[#E0E0E0] hover:bg-[#E0E0E0]'
aria-label='Get started with Sim'
>
Get started
</Link>
</>
)}
</div>

<div className='flex flex-1 items-center justify-end pr-[20px] lg:hidden'>
Expand All @@ -242,30 +269,34 @@ export default function Navbar({ logoOnly = false, blogPosts = [] }: NavbarProps
)}
>
<ul className='flex flex-col'>
{NAV_LINKS.map(({ label, href, external }) => (
<li key={label} className='border-[#2A2A2A] border-b'>
{external ? (
<a
href={href}
target='_blank'
rel='noopener noreferrer'
className='flex items-center justify-between px-[20px] py-[14px] text-[#ECECEC] transition-colors active:bg-[#2A2A2A]'
onClick={() => setMobileMenuOpen(false)}
>
{label}
<ExternalArrowIcon />
</a>
) : (
<Link
href={href}
className='flex items-center px-[20px] py-[14px] text-[#ECECEC] transition-colors active:bg-[#2A2A2A]'
onClick={() => setMobileMenuOpen(false)}
>
{label}
</Link>
)}
</li>
))}
{NAV_LINKS.map(({ label, href: rawHref, external }) => {
const href =
useHomeLinks && rawHref.startsWith('/#') ? `/?home${rawHref.slice(1)}` : rawHref
return (
<li key={label} className='border-[#2A2A2A] border-b'>
{external ? (
<a
href={href}
target='_blank'
rel='noopener noreferrer'
className='flex items-center justify-between px-[20px] py-[14px] text-[#ECECEC] transition-colors active:bg-[#2A2A2A]'
onClick={() => setMobileMenuOpen(false)}
>
{label}
<ExternalArrowIcon />
</a>
) : (
<Link
href={href}
className='flex items-center px-[20px] py-[14px] text-[#ECECEC] transition-colors active:bg-[#2A2A2A]'
onClick={() => setMobileMenuOpen(false)}
>
{label}
</Link>
)}
</li>
)
})}
<li className='border-[#2A2A2A] border-b'>
<a
href='https://github.com/simstudioai/sim'
Expand All @@ -280,23 +311,41 @@ export default function Navbar({ logoOnly = false, blogPosts = [] }: NavbarProps
</li>
</ul>

<div className='mt-auto flex flex-col gap-[10px] p-[20px]'>
<Link
href='/login'
className='flex h-[32px] items-center justify-center rounded-[5px] border border-[#3d3d3d] text-[#ECECEC] text-[14px] transition-colors active:bg-[#2A2A2A]'
onClick={() => setMobileMenuOpen(false)}
aria-label='Log in'
>
Log in
</Link>
<Link
href='/signup'
className='flex h-[32px] items-center justify-center rounded-[5px] border border-[#FFFFFF] bg-[#FFFFFF] text-[14px] text-black transition-colors active:bg-[#E0E0E0]'
onClick={() => setMobileMenuOpen(false)}
aria-label='Get started with Sim'
>
Get started
</Link>
<div
className={cn(
'mt-auto flex flex-col gap-[10px] p-[20px]',
isSessionPending && 'invisible'
)}
>
{isAuthenticated ? (
<Link
href='/workspace'
className='flex h-[32px] items-center justify-center rounded-[5px] border border-[#FFFFFF] bg-[#FFFFFF] text-[14px] text-black transition-colors active:bg-[#E0E0E0]'
onClick={() => setMobileMenuOpen(false)}
aria-label='Go to app'
>
Go to App
</Link>
) : (
<>
<Link
href='/login'
className='flex h-[32px] items-center justify-center rounded-[5px] border border-[#3d3d3d] text-[#ECECEC] text-[14px] transition-colors active:bg-[#2A2A2A]'
onClick={() => setMobileMenuOpen(false)}
aria-label='Log in'
>
Log in
</Link>
<Link
href='/signup'
className='flex h-[32px] items-center justify-center rounded-[5px] border border-[#FFFFFF] bg-[#FFFFFF] text-[14px] text-black transition-colors active:bg-[#E0E0E0]'
onClick={() => setMobileMenuOpen(false)}
aria-label='Get started with Sim'
>
Get started
</Link>
</>
)}
</div>
</div>
</>
Expand Down
2 changes: 0 additions & 2 deletions apps/sim/app/(landing)/blog/[slug]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,6 @@ export default async function Page({ params }: { params: Promise<{ slug: string
sizes='(max-width: 768px) 100vw, 450px'
priority
itemProp='image'
unoptimized
/>
</div>
</div>
Expand Down Expand Up @@ -144,7 +143,6 @@ export default async function Page({ params }: { params: Promise<{ slug: string
className='h-[160px] w-full object-cover'
sizes='(max-width: 640px) 100vw, (max-width: 1024px) 50vw, 33vw'
loading='lazy'
unoptimized
/>
<div className='p-3'>
<div className='mb-1 text-[#999] text-xs'>
Expand Down
1 change: 0 additions & 1 deletion apps/sim/app/(landing)/blog/authors/[id]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,6 @@ export default async function AuthorPage({ params }: { params: Promise<{ id: str
width={600}
height={315}
className='h-[160px] w-full object-cover transition-transform group-hover:scale-[1.02]'
unoptimized
/>
<div className='p-3'>
<div className='mb-1 text-[#999] text-xs'>
Expand Down
1 change: 0 additions & 1 deletion apps/sim/app/(landing)/blog/post-grid.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ export function PostGrid({ posts }: { posts: Post[] }) {
src={p.ogImage}
alt={p.title}
sizes='(max-width: 768px) 100vw, (max-width: 1024px) 50vw, 33vw'
unoptimized
priority={index < 6}
loading={index < 6 ? undefined : 'lazy'}
fill
Expand Down
114 changes: 73 additions & 41 deletions apps/sim/app/(landing)/components/nav/nav.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@ import { createLogger } from '@sim/logger'
import { ArrowRight, ChevronRight } from 'lucide-react'
import Image from 'next/image'
import Link from 'next/link'
import { useRouter } from 'next/navigation'
import { useRouter, useSearchParams } from 'next/navigation'
import { GithubIcon } from '@/components/icons'
import { useSession } from '@/lib/auth/auth-client'
import { isHosted } from '@/lib/core/config/feature-flags'
import { getFormattedGitHubStars } from '@/app/(landing)/actions/github'
import { useBrandConfig } from '@/ee/whitelabeling'
Expand All @@ -26,6 +27,12 @@ export default function Nav({ hideAuthButtons = false, variant = 'landing' }: Na
const router = useRouter()
const brand = useBrandConfig()
const buttonClass = useBrandedButtonClass()
const searchParams = useSearchParams()
const { data: session, isPending: isSessionPending } = useSession()
const isAuthenticated = Boolean(session?.user?.id)
const isBrowsingHome = searchParams.has('home')
const useHomeLinks = isAuthenticated || isBrowsingHome
const logoHref = useHomeLinks ? '/?home' : '/'

useEffect(() => {
if (variant !== 'landing') return
Expand Down Expand Up @@ -72,7 +79,7 @@ export default function Nav({ hideAuthButtons = false, variant = 'landing' }: Na
</li>
<li>
<Link
href='/?from=nav#pricing'
href={useHomeLinks ? '/?home#pricing' : '/#pricing'}
className='text-[16px] text-muted-foreground transition-colors hover:text-foreground'
scroll={true}
>
Expand Down Expand Up @@ -124,7 +131,7 @@ export default function Nav({ hideAuthButtons = false, variant = 'landing' }: Na
itemType='https://schema.org/SiteNavigationElement'
>
<div className='flex items-center gap-[34px]'>
<Link href='/?from=nav' aria-label={`${brand.name} home`} itemProp='url'>
<Link href={logoHref} aria-label={`${brand.name} home`} itemProp='url'>
<span itemProp='name' className='sr-only'>
{brand.name} Home
</span>
Expand Down Expand Up @@ -162,45 +169,70 @@ export default function Nav({ hideAuthButtons = false, variant = 'landing' }: Na

{/* Auth Buttons - show only when hosted, regardless of variant */}
{!hideAuthButtons && isHosted && (
<div className='flex items-center justify-center gap-[16px] pt-[1.5px]'>
<button
onClick={handleLoginClick}
onMouseEnter={() => setIsLoginHovered(true)}
onMouseLeave={() => setIsLoginHovered(false)}
className='group hidden text-[#2E2E2E] text-[16px] transition-colors hover:text-foreground md:block'
type='button'
aria-label='Log in to your account'
>
<span className='flex items-center gap-1'>
Log in
<span className='inline-flex transition-transform duration-200 group-hover:translate-x-0.5'>
{isLoginHovered ? (
<ArrowRight className='h-4 w-4' aria-hidden='true' />
) : (
<ChevronRight className='h-4 w-4' aria-hidden='true' />
)}
</span>
</span>
</button>
<Link
href='/signup'
onMouseEnter={() => setIsHovered(true)}
onMouseLeave={() => setIsHovered(false)}
className={`${buttonClass} group inline-flex items-center justify-center gap-2 rounded-[10px] py-[6px] pr-[10px] pl-[12px] text-[15px] text-white transition-all`}
aria-label='Get started with Sim - Sign up for free'
prefetch={true}
>
<span className='flex items-center gap-1'>
Get started
<span className='inline-flex transition-transform duration-200 group-hover:translate-x-0.5'>
{isHovered ? (
<ArrowRight className='h-4 w-4' aria-hidden='true' />
) : (
<ChevronRight className='h-4 w-4' aria-hidden='true' />
)}
<div
className={`flex items-center justify-center gap-[16px] pt-[1.5px]${isSessionPending ? ' invisible' : ''}`}
>
{isAuthenticated ? (
<Link
href='/workspace'
onMouseEnter={() => setIsHovered(true)}
onMouseLeave={() => setIsHovered(false)}
className={`${buttonClass} group inline-flex items-center justify-center gap-2 rounded-[10px] py-[6px] pr-[10px] pl-[12px] text-[15px] text-white transition-all`}
aria-label='Go to app'
>
<span className='flex items-center gap-1'>
Go to App
<span className='inline-flex transition-transform duration-200 group-hover:translate-x-0.5'>
{isHovered ? (
<ArrowRight className='h-4 w-4' aria-hidden='true' />
) : (
<ChevronRight className='h-4 w-4' aria-hidden='true' />
)}
</span>
</span>
</span>
</Link>
</Link>
) : (
<>
<button
onClick={handleLoginClick}
onMouseEnter={() => setIsLoginHovered(true)}
onMouseLeave={() => setIsLoginHovered(false)}
className='group hidden text-[#2E2E2E] text-[16px] transition-colors hover:text-foreground md:block'
type='button'
aria-label='Log in to your account'
>
<span className='flex items-center gap-1'>
Log in
<span className='inline-flex transition-transform duration-200 group-hover:translate-x-0.5'>
{isLoginHovered ? (
<ArrowRight className='h-4 w-4' aria-hidden='true' />
) : (
<ChevronRight className='h-4 w-4' aria-hidden='true' />
)}
</span>
</span>
</button>
<Link
href='/signup'
onMouseEnter={() => setIsHovered(true)}
onMouseLeave={() => setIsHovered(false)}
className={`${buttonClass} group inline-flex items-center justify-center gap-2 rounded-[10px] py-[6px] pr-[10px] pl-[12px] text-[15px] text-white transition-all`}
aria-label='Get started with Sim - Sign up for free'
prefetch={true}
>
<span className='flex items-center gap-1'>
Get started
<span className='inline-flex transition-transform duration-200 group-hover:translate-x-0.5'>
{isHovered ? (
<ArrowRight className='h-4 w-4' aria-hidden='true' />
) : (
<ChevronRight className='h-4 w-4' aria-hidden='true' />
)}
</span>
</span>
</Link>
</>
)}
</div>
)}
</nav>
Expand Down
Loading
Loading