11'use client'
22
33import { useCallback , useEffect , useRef , useState } from 'react'
4- import { createLogger } from '@sim/logger'
5- import { AnimatePresence , type MotionValue , motion , useScroll , useTransform } from 'framer-motion'
4+ import { type MotionValue , motion , useScroll , useTransform } from 'framer-motion'
65import dynamic from 'next/dynamic'
7- import { useRouter } from 'next/navigation '
6+ import Link from 'next/link '
87import { Badge , ChevronDown } from '@/components/emcn'
98import { LandingWorkflowSeedStorage } from '@/lib/core/utils/browser-storage'
9+
1010import { cn } from '@/lib/core/utils/cn'
1111import { TEMPLATE_WORKFLOWS } from '@/app/(home)/components/templates/template-workflows'
12-
12+ import { createLogger } from '@sim/logger'
13+ import { useRouter } from 'next/navigation'
1314const logger = createLogger ( 'LandingTemplates' )
1415
1516const LandingPreviewWorkflow = dynamic (
@@ -337,7 +338,7 @@ function DotGrid({ className, cols, rows, gap = 0 }: DotGridProps) {
337338 } }
338339 >
339340 { Array . from ( { length : cols * rows } , ( _ , i ) => (
340- < div key = { i } className = 'h-[1.5px ] w-[1.5px ] rounded-full bg-[#2A2A2A]' />
341+ < div key = { i } className = 'h-[2px ] w-[2px ] rounded-full bg-[#2A2A2A]' />
341342 ) ) }
342343 </ div >
343344 )
@@ -424,8 +425,8 @@ export default function Templates() {
424425
425426 < div className = 'bg-[#1C1C1C]' >
426427 < DotGrid
427- className = 'overflow-hidden border-[#2A2A2A] border-y bg-[#1C1C1C] p-[6px]'
428- cols = { 160 }
428+ className = 'border-[#2A2A2A] border-y bg-[#1C1C1C] p-[6px]'
429+ cols = { 120 }
429430 rows = { 1 }
430431 gap = { 6 }
431432 />
@@ -449,7 +450,7 @@ export default function Templates() {
449450 </ svg >
450451 </ div >
451452
452- < div className = 'px-[20px] pt-[60px] lg:px-[ 80px] lg: pt-[100px]' >
453+ < div className = 'px-[80px] pt-[100px]' >
453454 < div className = 'flex flex-col items-start gap-[20px]' >
454455 < Badge
455456 variant = 'blue'
@@ -466,132 +467,107 @@ export default function Templates() {
466467
467468 < h2
468469 id = 'templates-heading'
469- className = 'font-[430] font-season text-[28px ] text-white leading-[100%] tracking-[-0.02em] lg:text-[40px ]'
470+ className = 'font-[430] font-season text-[40px ] text-white leading-[100%] tracking-[-0.02em]'
470471 >
471472 Ship your agent in minutes
472473 </ h2 >
473474
474- < p className = 'font-[430] font-season text-[#F6F6F0]/50 text-[15px ] leading-[150 %] tracking-[0.02em] lg:text-[18px ]' >
475+ < p className = 'font-[430] font-season text-[#F6F6F0]/50 text-[16px ] leading-[125 %] tracking-[0.02em]' >
475476 Pre-built templates for every use case—pick one, swap{ ' ' }
476477 < br className = 'hidden lg:inline' />
477478 models and tools to fit your stack, and deploy.
478479 </ p >
479480 </ div >
480481 </ div >
481482
482- < div className = 'mt-[40px] flex border-[#2A2A2A] border-y lg:mt-[73px]' >
483- < div className = 'shrink-0' >
484- < div className = 'h-full lg:hidden' >
485- < DotGrid
486- className = 'h-full w-[24px] overflow-hidden border-[#2A2A2A] border-r p-[4px]'
487- cols = { 2 }
488- rows = { 55 }
489- gap = { 4 }
490- />
491- </ div >
492- < div className = 'hidden h-full lg:block' >
493- < DotGrid
494- className = 'h-full w-[80px] overflow-hidden border-[#2A2A2A] border-r p-[6px]'
495- cols = { 8 }
496- rows = { 55 }
497- gap = { 6 }
498- />
499- </ div >
500- </ div >
483+ < div className = 'mt-[73px] flex border-[#2A2A2A] border-y' >
484+ < DotGrid
485+ className = 'w-[80px] shrink-0 overflow-hidden border-[#2A2A2A] border-r p-[6px]'
486+ cols = { 6 }
487+ rows = { 55 }
488+ gap = { 6 }
489+ />
501490
502- < div className = 'flex min-w-0 flex-1 flex-col lg:flex-row ' >
491+ < div className = 'flex min-w-0 flex-1' >
503492 < div
504493 role = 'tablist'
505494 aria-label = 'Workflow templates'
506- className = 'flex w-full shrink-0 flex-col border-[#2A2A2A] lg:w-[300px] lg: border-r'
495+ className = 'flex w-[300px] shrink-0 flex-col border-[#2A2A2A] border-r'
507496 >
508497 { TEMPLATE_WORKFLOWS . map ( ( workflow , index ) => {
509498 const isActive = index === activeIndex
499+ const depth = DEPTH_CONFIGS [ workflow . id ]
510500 return (
511- < div key = { workflow . id } >
512- < button
513- id = { `template-tab-${ index } ` }
514- type = 'button'
515- role = 'tab'
516- aria-selected = { isActive }
517- aria-controls = { TEMPLATES_PANEL_ID }
518- onClick = { ( ) => setActiveIndex ( index ) }
519- className = { cn (
520- 'relative w-full text-left' ,
521- isActive
522- ? 'z-10'
523- : cn (
524- 'flex items-center px-[12px] py-[10px] hover:bg-[#232323]/50' ,
525- index < TEMPLATE_WORKFLOWS . length - 1 &&
526- 'shadow-[inset_0_-1px_0_0_#2A2A2A]'
527- )
528- ) }
501+ < button
502+ key = { workflow . id }
503+ id = { `template-tab-${ index } ` }
504+ type = 'button'
505+ role = 'tab'
506+ aria-selected = { isActive }
507+ aria-controls = { TEMPLATES_PANEL_ID }
508+ onClick = { ( ) => setActiveIndex ( index ) }
509+ className = { cn (
510+ 'relative text-left' ,
511+ isActive
512+ ? 'z-10'
513+ : 'shadow-[inset_0_-1px_0_0_#2A2A2A] last:shadow-none hover:bg-[#232323]/50'
514+ ) }
515+ >
516+ < div
517+ className = 'pointer-events-none absolute top-[-8px] bottom-0 left-0 w-2'
518+ style = { {
519+ clipPath : LEFT_WALL_CLIP ,
520+ backgroundColor : hexToRgba ( depth . color , 0.63 ) ,
521+ opacity : isActive ? 1 : 0 ,
522+ transition : isActive
523+ ? 'opacity 250ms cubic-bezier(0.2, 0, 0, 1) 50ms'
524+ : 'opacity 200ms cubic-bezier(0.4, 0, 1, 1)' ,
525+ } }
526+ />
527+ < div
528+ className = 'pointer-events-none absolute right-[-8px] bottom-0 left-2 h-2'
529+ style = { {
530+ ...buildBottomWallStyle ( depth ) ,
531+ opacity : isActive ? 1 : 0 ,
532+ transition : isActive
533+ ? 'opacity 250ms cubic-bezier(0.2, 0, 0, 1) 50ms'
534+ : 'opacity 200ms cubic-bezier(0.4, 0, 1, 1)' ,
535+ } }
536+ />
537+ < div
538+ className = 'relative flex items-center px-[12px] py-[10px]'
539+ style = { {
540+ transform : isActive ? 'translate(8px, -8px)' : 'translate(0px, 0px)' ,
541+ backgroundColor : isActive ? '#242424' : 'transparent' ,
542+ boxShadow : isActive
543+ ? 'inset 0 0 0 1.5px #3E3E3E'
544+ : 'inset 0 0 0 1.5px transparent' ,
545+ transition : isActive
546+ ? 'transform 350ms cubic-bezier(0.34, 1.4, 0.64, 1), background-color 250ms ease 30ms, box-shadow 250ms ease 30ms'
547+ : 'transform 300ms cubic-bezier(0.4, 0, 0.2, 1), background-color 200ms ease, box-shadow 200ms ease' ,
548+ } }
529549 >
530- { isActive ? (
531- ( ( ) => {
532- const depth = DEPTH_CONFIGS [ workflow . id ]
533- return (
534- < >
535- < div
536- className = 'absolute top-[-8px] bottom-0 left-0 w-2'
537- style = { {
538- clipPath : LEFT_WALL_CLIP ,
539- backgroundColor : hexToRgba ( depth . color , 0.63 ) ,
540- } }
541- />
542- < div
543- className = 'absolute right-[-8px] bottom-0 left-2 h-2'
544- style = { buildBottomWallStyle ( depth ) }
545- />
546- < div className = '-translate-y-2 relative flex translate-x-2 items-center bg-[#242424] px-[12px] py-[10px] shadow-[inset_0_0_0_1.5px_#3E3E3E]' >
547- < span className = 'flex-1 font-[430] font-season text-[16px] text-white' >
548- { workflow . name }
549- </ span >
550- < ChevronDown
551- className = '-rotate-90 h-[11px] w-[11px] shrink-0'
552- style = { { color : depth . color } }
553- />
554- </ div >
555- </ >
556- )
557- } ) ( )
558- ) : (
559- < span className = 'font-[430] font-season text-[#F6F6F0]/50 text-[16px]' >
560- { workflow . name }
561- </ span >
562- ) }
563- </ button >
564-
565- < AnimatePresence >
566- { isActive && isMobile && (
567- < motion . div
568- initial = { { height : 0 , opacity : 0 } }
569- animate = { { height : 'auto' , opacity : 1 } }
570- exit = { { height : 0 , opacity : 0 } }
571- transition = { { duration : 0.25 , ease : [ 0.4 , 0 , 0.2 , 1 ] } }
572- className = 'overflow-hidden'
573- >
574- < div className = 'aspect-[16/10] w-full border-[#2A2A2A] border-y bg-[#1b1b1b]' >
575- < LandingPreviewWorkflow
576- workflow = { workflow }
577- animate
578- fitViewOptions = { { padding : 0.15 , maxZoom : 1.3 } }
579- />
580- </ div >
581- < div className = 'p-[12px]' >
582- < button
583- type = 'button'
584- onClick = { handleUseTemplate }
585- disabled = { isPreparingTemplate }
586- className = 'inline-flex h-[32px] w-full cursor-pointer items-center justify-center gap-[6px] rounded-[5px] border border-[#FFFFFF] bg-[#FFFFFF] font-[430] font-season text-[14px] text-black transition-colors active:bg-[#E0E0E0]'
587- >
588- { isPreparingTemplate ? 'Preparing...' : 'Use template' }
589- </ button >
590- </ div >
591- </ motion . div >
592- ) }
593- </ AnimatePresence >
594- </ div >
550+ < span
551+ className = 'flex-1 font-[430] font-season text-[16px]'
552+ style = { {
553+ color : isActive ? '#FFFFFF' : 'rgba(246, 246, 240, 0.5)' ,
554+ transition : 'color 250ms ease' ,
555+ } }
556+ >
557+ { workflow . name }
558+ </ span >
559+ < ChevronDown
560+ className = '-rotate-90 h-[11px] w-[11px] shrink-0'
561+ style = { {
562+ color : depth . color ,
563+ opacity : isActive ? 1 : 0 ,
564+ transition : isActive
565+ ? 'opacity 200ms ease 150ms'
566+ : 'opacity 150ms ease' ,
567+ } }
568+ />
569+ </ div >
570+ </ button >
595571 )
596572 } ) }
597573 </ div >
@@ -610,13 +586,11 @@ export default function Templates() {
610586 fitViewOptions = { { padding : 0.15 , maxZoom : 1.3 } }
611587 />
612588 </ div >
613- < button
614- type = 'button'
615- onClick = { handleUseTemplate }
616- disabled = { isPreparingTemplate }
617- className = 'group/cta absolute top-[16px] right-[16px] z-10 inline-flex h-[32px] cursor-pointer items-center gap-[6px] rounded-[5px] border border-[#FFFFFF] bg-[#FFFFFF] px-[10px] font-[430] font-season text-[14px] text-black transition-colors hover:border-[#E0E0E0] hover:bg-[#E0E0E0]'
589+ < Link
590+ href = '/signup'
591+ className = 'group/cta absolute top-[16px] right-[16px] z-10 inline-flex h-[32px] items-center gap-[6px] rounded-[5px] border border-[#33C482] bg-[#33C482] px-[10px] font-[430] font-season text-[14px] text-black transition-[filter] hover:brightness-110'
618592 >
619- { isPreparingTemplate ? 'Preparing...' : ' Use template' }
593+ Use template
620594 < span className = 'relative h-[10px] w-[10px] shrink-0' >
621595 < ChevronDown className = '-rotate-90 absolute inset-0 h-[10px] w-[10px] transition-opacity duration-150 group-hover/cta:opacity-0' />
622596 < svg
@@ -635,31 +609,19 @@ export default function Templates() {
635609 />
636610 </ svg >
637611 </ span >
638- </ button >
612+ </ Link >
639613 </ div >
640614 </ div >
641615
642- < div className = 'shrink-0' >
643- < div className = 'h-full lg:hidden' >
644- < DotGrid
645- className = 'h-full w-[24px] overflow-hidden border-[#2A2A2A] border-l p-[4px]'
646- cols = { 2 }
647- rows = { 55 }
648- gap = { 4 }
649- />
650- </ div >
651- < div className = 'hidden h-full lg:block' >
652- < DotGrid
653- className = 'h-full w-[80px] overflow-hidden border-[#2A2A2A] border-l p-[6px]'
654- cols = { 8 }
655- rows = { 55 }
656- gap = { 6 }
657- />
658- </ div >
659- </ div >
616+ < DotGrid
617+ className = 'w-[80px] shrink-0 overflow-hidden border-[#2A2A2A] border-l p-[6px]'
618+ cols = { 6 }
619+ rows = { 55 }
620+ gap = { 6 }
621+ />
660622 </ div >
661623 </ div >
662624 </ div >
663625 </ section >
664626 )
665- }
627+ }
0 commit comments