Skip to content

Commit 3534b48

Browse files
authored
feat: new onboarding tutorial step (#1185)
### TL;DR Added an interactive tutorial step to the onboarding flow with guided tour highlighting, animated hedgehog assistant, and updated app icons. ### What changed? - **New Tutorial Components**: Added `TutorialStep`, `TutorialHedgehog`, and `TourHighlight` components to create an interactive guided experience - **Tutorial Tour Logic**: Implemented `useTutorialTour` hook to manage step progression through repo selection, workspace mode, model selection, execution mode cycling, prompt auto-fill, and task submission - **Enhanced Onboarding Flow**: Integrated tutorial as the final onboarding step with seamless hedgehog animation transitions using Framer Motion's `LayoutGroup` - **Tour Highlighting System**: Added spotlight effects to UI components during tutorial with dimming for inactive elements - **App Icon Updates**: Refreshed app icons across formats (ICNS, ICO, PNG) and reorganized icon assets with new JSON configuration - **Build Script Updates**: Modified icon generation to use `app-icon.png` instead of `icon@3x.png` as source - **Component Enhancements**: Added tour highlighting support to `TaskInputEditor`, model change callbacks to `UnifiedModelSelector`, and workspace mode overrides to `WorkspaceModeSelect` - **Prompt Generation**: Created utility to generate PostHog instrumentation prompts based on selected signal sources
1 parent 57b60e0 commit 3534b48

21 files changed

Lines changed: 1041 additions & 182 deletions

File tree

apps/code/build/app-icon.icns

535 KB
Binary file not shown.

apps/code/build/app-icon.ico

160 KB
Binary file not shown.

apps/code/build/app-icon.png

284 KB
Loading
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
{
2+
"fill": {
3+
"automatic-gradient": "display-p3:0.00000,0.00000,0.00000,1.00000"
4+
},
5+
"groups": [
6+
{
7+
"layers": [
8+
{
9+
"fill": "none",
10+
"image-name": "icon.png",
11+
"name": "icon",
12+
"position": {
13+
"scale": 0.4,
14+
"translation-in-points": [3, 3]
15+
}
16+
}
17+
],
18+
"shadow": {
19+
"kind": "neutral",
20+
"opacity": 0.5
21+
},
22+
"translucency": {
23+
"enabled": true,
24+
"value": 0.5
25+
}
26+
}
27+
],
28+
"supported-platforms": {
29+
"circles": ["watchOS"],
30+
"squares": "shared"
31+
}
32+
}

apps/code/build/icon@3x.png

-104 KB
Binary file not shown.

apps/code/build/logo.png

-25 KB
Binary file not shown.

apps/code/forge.config.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ const config: ForgeConfig = {
187187
generateAssets: async () => {
188188
// Generate ICNS from source PNG (skip if already exists)
189189
if (
190-
existsSync("build/icon@3x.png") &&
190+
existsSync("build/app-icon.png") &&
191191
!existsSync("build/app-icon.icns")
192192
) {
193193
execSync("bash scripts/generate-icns.sh", { stdio: "inherit" });

apps/code/scripts/generate-icns.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
set -e
88

9-
SOURCE_PNG="${1:-build/icon@3x.png}"
9+
SOURCE_PNG="${1:-build/app-icon.png}"
1010
OUTPUT_ICNS="${2:-build/app-icon.icns}"
1111
ICONSET_DIR=$(mktemp -d)/icon.iconset
1212

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
import { motion } from "framer-motion";
2+
3+
interface TourHighlightProps {
4+
active: boolean;
5+
children: React.ReactNode;
6+
borderRadius?: string;
7+
/** Set true for elements that should stretch to fill their container (e.g. editor) */
8+
fullWidth?: boolean;
9+
/** When true and not active, dim to show it's not the focus of attention */
10+
dimWhenInactive?: boolean;
11+
/**
12+
* Keep opacity at 1 without triggering the glow — use when a child component
13+
* is highlighted so this wrapper doesn't dim it via CSS opacity inheritance.
14+
*/
15+
opaque?: boolean;
16+
}
17+
18+
export function TourHighlight({
19+
active,
20+
children,
21+
borderRadius = "var(--radius-2)",
22+
fullWidth,
23+
dimWhenInactive,
24+
opaque,
25+
}: TourHighlightProps) {
26+
const targetOpacity = active || opaque ? 1 : dimWhenInactive ? 0.35 : 1;
27+
28+
return (
29+
<motion.div
30+
style={{
31+
borderRadius,
32+
display: fullWidth ? "flex" : "inline-flex",
33+
width: fullWidth ? "100%" : undefined,
34+
position: "relative",
35+
overflow: "visible",
36+
}}
37+
animate={
38+
active
39+
? {
40+
boxShadow: [
41+
"0 0 0 1.5px var(--accent-a8), 0 0 8px 2px var(--accent-a5)",
42+
"0 0 0 1.5px var(--accent-a9), 0 0 12px 4px var(--accent-a6)",
43+
"0 0 0 1.5px var(--accent-a8), 0 0 8px 2px var(--accent-a5)",
44+
],
45+
opacity: 1,
46+
}
47+
: {
48+
boxShadow: "0 0 0 0px transparent",
49+
opacity: targetOpacity,
50+
}
51+
}
52+
transition={
53+
active
54+
? {
55+
boxShadow: {
56+
duration: 3,
57+
repeat: Number.POSITIVE_INFINITY,
58+
ease: "easeInOut",
59+
},
60+
opacity: { duration: 0.3 },
61+
}
62+
: { duration: 0.3 }
63+
}
64+
>
65+
{children}
66+
</motion.div>
67+
);
68+
}

0 commit comments

Comments
 (0)