From 312ec968efae60c736bcace8c414ffdca5e12aaf Mon Sep 17 00:00:00 2001 From: DIYgod Date: Tue, 17 Mar 2026 16:44:49 +0800 Subject: [PATCH] feat(landing): add audience tabs to hero --- .../components/ui/segment-tab/SegmentTab.tsx | 23 +-- .../src/components/widgets/landing/Hero.tsx | 132 ++++++++++++------ apps/landing/src/messages/en.json | 6 +- apps/landing/src/messages/jp.json | 6 +- apps/landing/src/messages/zh.json | 6 +- 5 files changed, 121 insertions(+), 52 deletions(-) diff --git a/apps/landing/src/components/ui/segment-tab/SegmentTab.tsx b/apps/landing/src/components/ui/segment-tab/SegmentTab.tsx index b3339a3bb..597ce74c7 100644 --- a/apps/landing/src/components/ui/segment-tab/SegmentTab.tsx +++ b/apps/landing/src/components/ui/segment-tab/SegmentTab.tsx @@ -23,6 +23,7 @@ export interface SegmentTabProps { inactiveClassName?: string size?: 'sm' | 'md' | 'lg' variant?: 'default' | 'compact' + distribution?: 'fill' | 'fit' disabled?: boolean responsiveWrap?: boolean ref?: Ref @@ -69,6 +70,7 @@ export function SegmentTab({ inactiveClassName, size = 'md', variant = 'default', + distribution = 'fill', disabled = false, responsiveWrap = false, ref, @@ -82,7 +84,8 @@ export function SegmentTab({ role="tablist" aria-disabled={disabled || undefined} className={cn( - 'container-type-[inline-size] relative flex w-full items-center', + 'container-type-[inline-size] relative flex items-center', + distribution === 'fill' ? 'w-full' : 'w-fit max-w-full', styles.container, disabled && 'pointer-events-none opacity-60', containerClassName, @@ -90,7 +93,8 @@ export function SegmentTab({ >
@@ -110,12 +114,14 @@ export function SegmentTab({ 'focus-visible:ring-accent/30 focus:outline-none focus-visible:ring-2', sizeClass, styles.button, - responsiveWrap - ? clsx( - '@[0px]:flex-none @[0px]:basis-[calc(50%-0.125rem)] @[0px]:px-2', - '@[420px]:flex-1 @[420px]:basis-auto @[420px]:px-3', - ) - : clsx('flex-1', '@[0px]:px-2 @[420px]:px-3'), + distribution === 'fit' + ? 'flex-none' + : responsiveWrap + ? clsx( + '@[0px]:flex-none @[0px]:basis-[calc(50%-0.125rem)] @[0px]:px-2', + '@[420px]:flex-1 @[420px]:basis-auto @[420px]:px-3', + ) + : clsx('flex-1', '@[0px]:px-2 @[420px]:px-3'), isActive ? cn('text-text', activeClassName) : cn( @@ -150,7 +156,6 @@ export function SegmentTab({ // Floating pill indicator with subtle border & shadow 'pointer-events-none absolute inset-x-0 inset-y-0.5 z-[-1]', styles.indicator, - responsiveWrap && 'hidden @[420px]:block', className, )} /> diff --git a/apps/landing/src/components/widgets/landing/Hero.tsx b/apps/landing/src/components/widgets/landing/Hero.tsx index c763f6f7c..c7fbe682a 100644 --- a/apps/landing/src/components/widgets/landing/Hero.tsx +++ b/apps/landing/src/components/widgets/landing/Hero.tsx @@ -15,6 +15,7 @@ import { ParticlesAura } from '~/components/ui/effects/ParticlesAura' import { TiltCard } from '~/components/ui/effects/TiltCard' import { Highlighter } from '~/components/ui/highlighter' import { PanelSplitter } from '~/components/ui/panel/PanelSplitter' +import { SegmentTab } from '~/components/ui/segment-tab' import { Link as LocalizedLink } from '~/i18n/routing' import type { HeroTimelineItem } from '~/lib/landing-data' @@ -26,6 +27,8 @@ type LandingHeroProps = { items: HeroTimelineItem[] } +type AudienceKey = 'human' | 'agent' + export const LandingHero: Component = ({ items }) => { const ref = React.useRef(null) const { scrollYProgress } = useScroll({ @@ -35,6 +38,28 @@ export const LandingHero: Component = ({ items }) => { const bgY = useTransform(scrollYProgress, [0, 1], [0, -150]) const heroT = useTranslations('landing.hero') const actionsT = useTranslations('common.actions') + const [audience, setAudience] = React.useState('human') + + const audienceItems: { + value: AudienceKey + label: string + icon: React.ReactNode + }[] = [ + { + value: 'human', + label: heroT('humanTab'), + icon: ( + + ), + }, + { + value: 'agent', + label: heroT('agentTab'), + icon: ( + + ), + }, + ] return (
@@ -75,48 +100,75 @@ export const LandingHero: Component = ({ items }) => {

{heroT('bodyLine2')}

-
- - - + + - - - - - - - - - - {/* - - New - - Product Intelligence - - */} + + + + +
+ ) : ( +
+

+ {heroT('agentTitle')} +

+

+ {heroT.rich('agentBody', { + skill: (chunks) => ( + + {chunks} + + ), + })} +

+
+ )} diff --git a/apps/landing/src/messages/en.json b/apps/landing/src/messages/en.json index c38e18e57..4bec2f4ca 100644 --- a/apps/landing/src/messages/en.json +++ b/apps/landing/src/messages/en.json @@ -22,7 +22,11 @@ "eyebrow": "AI RSS Reader · Clean Timeline", "title": "Folo is the AI RSS Reader", "bodyLine1": "The AI that reads the internet for you,", - "bodyLine2": "cutting through noise to surface the knowledge you actually care about." + "bodyLine2": "cutting through noise to surface the knowledge you actually care about.", + "humanTab": "I'm a Human", + "agentTab": "I'm an Agent", + "agentTitle": "Use Folo", + "agentBody": "Read https://api.folo.is/skill.md and follow the instructions to use Folo." }, "features": { "headline": "Reading reimagined in the AI era", diff --git a/apps/landing/src/messages/jp.json b/apps/landing/src/messages/jp.json index eba2eb17e..eb9a303ec 100644 --- a/apps/landing/src/messages/jp.json +++ b/apps/landing/src/messages/jp.json @@ -22,7 +22,11 @@ "eyebrow": "AI RSS Reader · クリーンタイムライン", "title": "Folo はあなたの AI RSS Reader", "bodyLine1": "インターネットの情報を AI が代わりに読み、", - "bodyLine2": "雑音を取り除いて、本当に必要な知識だけを届けます。" + "bodyLine2": "雑音を取り除いて、本当に必要な知識だけを届けます。", + "humanTab": "I'm a Human", + "agentTab": "I'm an Agent", + "agentTitle": "Use Folo", + "agentBody": "Read https://api.folo.is/skill.md and follow the instructions to use Folo." }, "features": { "headline": "AI 時代のための新しい読書体験", diff --git a/apps/landing/src/messages/zh.json b/apps/landing/src/messages/zh.json index a95132b14..25ec1cb66 100644 --- a/apps/landing/src/messages/zh.json +++ b/apps/landing/src/messages/zh.json @@ -22,7 +22,11 @@ "eyebrow": "AI RSS Reader · 洁净时间线", "title": "Folo 是你的 AI RSS Reader", "bodyLine1": "这款 AI 为你读遍全网,", - "bodyLine2": "穿透噪音,只呈现你真正关心的洞见。" + "bodyLine2": "穿透噪音,只呈现你真正关心的洞见。", + "humanTab": "I'm a Human", + "agentTab": "I'm an Agent", + "agentTitle": "Use Folo", + "agentBody": "Read https://api.folo.is/skill.md and follow the instructions to use Folo." }, "features": { "headline": "在 AI 时代重新定义阅读",