-
Notifications
You must be signed in to change notification settings - Fork 23
Expand file tree
/
Copy pathWelcomeScreen.tsx
More file actions
154 lines (142 loc) · 4.59 KB
/
WelcomeScreen.tsx
File metadata and controls
154 lines (142 loc) · 4.59 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
import {
ArrowRight,
ChartLine,
Cloud,
GitPullRequest,
Robot,
Tray,
} from "@phosphor-icons/react";
import { Button, Flex, Text } from "@radix-ui/themes";
import explorerHog from "@renderer/assets/images/hedgehogs/explorer-hog.png";
import Logo from "@renderer/assets/logo";
import { useCallback, useEffect, useRef, useState } from "react";
import { FeatureBentoCard } from "./FeatureBentoCard";
import { OnboardingHogTip } from "./OnboardingHogTip";
import { StepActions } from "./StepActions";
const FEATURES = [
{
icon: <ChartLine size={28} />,
title: "Product data as context",
description:
"Built-in context on analytics, session replays, experiments, feature flags, and more.",
className: "col-span-4",
},
{
icon: <Tray size={26} />,
title: "Your signals inbox",
description:
"Automatically surfaces the highest-impact work from your product data so you always know what to do next.",
className: "col-span-2",
},
{
icon: <Robot size={22} />,
title: "Your pick of Claude Code or Codex",
description:
"PostHog is harness-agnostic – both Anthropic and OpenAI supported.",
className: "col-span-2",
},
{
icon: <Cloud size={22} />,
title: "Build non-stop",
description:
"Run tasks in parallel across local and cloud environments - even while you're away.",
className: "col-span-2",
},
{
icon: <GitPullRequest size={22} />,
title: "Review and ship with confidence",
description:
"Inline diffs, AI-assisted code review and PR creation in a single flow.",
className: "col-span-2",
},
];
interface WelcomeScreenProps {
onNext: () => void;
}
const CYCLE_INTERVAL_MS = 2500;
const CYCLE_START_DELAY_MS = FEATURES.length * 100 + 400;
export function WelcomeScreen({ onNext }: WelcomeScreenProps) {
const [activeIndex, setActiveIndex] = useState(-1);
const timerRef = useRef<ReturnType<typeof setInterval>>(null);
const startCycling = useCallback(() => {
if (timerRef.current) clearInterval(timerRef.current);
timerRef.current = setInterval(() => {
setActiveIndex((prev) => (prev + 1) % FEATURES.length);
}, CYCLE_INTERVAL_MS);
}, []);
useEffect(() => {
const timeout = setTimeout(() => {
setActiveIndex(0);
startCycling();
}, CYCLE_START_DELAY_MS);
return () => {
clearTimeout(timeout);
if (timerRef.current) clearInterval(timerRef.current);
};
}, [startCycling]);
const handleMouseEnter = (index: number) => {
setActiveIndex(index);
if (timerRef.current) clearInterval(timerRef.current);
};
const handleMouseLeave = () => {
startCycling();
};
return (
<Flex align="center" height="100%" px="8">
<Flex
direction="column"
align="center"
className="h-full w-full pt-[24px] pb-[40px]"
>
<Flex
direction="column"
align="center"
className="min-h-0 w-full flex-1"
>
<Flex
direction="column"
align="start"
className="mx-0 my-auto w-full max-w-[760px] gap-6 overflow-hidden"
>
<Flex direction="row" align="center" gap="3">
<Text
/** Very specifically 25px text to be the same size as the Logo's font size */
className="font-bold text-(--gray-12) text-[25px] tracking-[-0.05em]"
>
Welcome to
</Text>
<Logo />
</Flex>
<div className="grid w-full grid-cols-6 grid-rows-[18rem_14rem] gap-3 overflow-hidden rounded-lg">
{FEATURES.map((feature, index) => (
<FeatureBentoCard
key={feature.title}
icon={feature.icon}
title={feature.title}
description={feature.description}
active={activeIndex === index}
index={index}
className={feature.className}
onMouseEnter={() => handleMouseEnter(index)}
onMouseLeave={handleMouseLeave}
/>
))}
</div>
</Flex>
</Flex>
<Flex direction="column" align="center" className="shrink-0 pt-[16px]">
<OnboardingHogTip
hogSrc={explorerHog}
message="Let's get you set up! It only takes a minute."
/>
<StepActions delay={0.25}>
<Button size="3" onClick={onNext}>
Start shipping
<ArrowRight size={16} weight="bold" />
</Button>
</StepActions>
</Flex>
</Flex>
</Flex>
);
}