Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Onboarding For Integrations #54

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
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
15 changes: 12 additions & 3 deletions gui/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,10 @@ import Onboarding from "./pages/onboarding/Onboarding";
import SettingsPage from "./pages/settings";
import Stats from "./pages/stats";
import Inventory from "./pages/inventory";
import AiderGUI from "./integrations/aider/aidergui";
import PerplexityGUI from "./integrations/perplexity/perplexitygui";

import AiderGUI from "./integrations/aider/aiderGui";
import AiderOnboarding from "./integrations/aider/aiderOnboarding";
import PerplexityGUI from "./integrations/perplexity/perplexityGui";
import PerplexityOnboarding from "./integrations/perplexity/perplexityOnboarding";

declare global {
interface Window {
Expand All @@ -49,10 +50,18 @@ const router = createMemoryRouter(
path: "/aiderMode",
element: <AiderGUI />,
},
{
path: "/aiderOnboarding",
element: <AiderOnboarding />,
},
{
path: "/perplexityMode",
element: <PerplexityGUI />,
},
{
path: "/perplexityOnboarding",
element: <PerplexityOnboarding />,
},
{
path: "/history",
element: <History />,
Expand Down
144 changes: 144 additions & 0 deletions gui/src/integrations/aider/aiderOnboarding.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
import React, { useEffect } from 'react';
import { useNavigate } from 'react-router-dom';
import styled, { keyframes } from 'styled-components';
import { Button } from '../../components';
import { getLocalStorage, setLocalStorage } from '../../util/localStorage';

const rumbleAnimation = keyframes`
0% { transform: translate(0, 0); }
25% { transform: translate(-5px, 5px); }
50% { transform: translate(5px, -5px); }
75% { transform: translate(-3px, -3px); }
100% { transform: translate(0, 0); }
`;

const fadeInUp = keyframes`
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
`;

const glowPulse = keyframes`
0% { box-shadow: 0 0 5px rgba(255, 255, 255, 0.5); }
50% { box-shadow: 0 0 20px rgba(255, 255, 255, 0.8); }
100% { box-shadow: 0 0 5px rgba(255, 255, 255, 0.5); }
`;

const OnboardingContainer = styled.div`
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
min-height: 80vh;
padding: 2rem;
text-align: center;
max-width: 800px;
margin: 0 auto;
animation: ${rumbleAnimation} 0.5s ease-in-out;
`;

const Title = styled.h1`
font-size: 2.5rem;
margin-bottom: 2rem;
color: ${props => props.theme.textColor};
animation: ${fadeInUp} 0.8s ease-out forwards;
opacity: 0;
`;

const Description = styled.p`
font-size: 1.2rem;
line-height: 1.6;
margin-bottom: 2rem;
color: ${props => props.theme.secondaryText};
animation: ${fadeInUp} 0.8s ease-out 0.3s forwards;
opacity: 0;
`;

const FeatureList = styled.ul`
list-style-type: none;
padding: 0;
margin-bottom: 2rem;
text-align: left;
animation: ${fadeInUp} 0.8s ease-out 0.6s forwards;
opacity: 0;
`;

const FeatureItem = styled.li`
font-size: 1.1rem;
margin-bottom: 1rem;
padding-left: 1.5rem;
position: relative;
transition: transform 0.3s ease;

&:before {
content: "→";
position: absolute;
left: 0;
transition: transform 0.3s ease;
}

&:hover {
transform: translateX(10px);

&:before {
transform: rotate(90deg);
}
}
`;

const StartButton = styled(Button)`
padding: 1rem 2rem;
font-size: 1.2rem;
animation: ${fadeInUp} 0.8s ease-out 0.9s forwards, ${glowPulse} 2s infinite;
opacity: 0;
transition: transform 0.3s ease;

&:hover {
transform: scale(1.05);
}
`;

const AiderOnboarding = () => {
const navigate = useNavigate();

useEffect(() => {
// Play a subtle rumble sound when the component mounts
const audio = new Audio('data:audio/wav;base64,UklGRjIAAABXQVZFZm10IBIAAAABAAEAQB8AAEAfAAABAAgAAABmYWN0BAAAAAAAAABkYXRhAAAAAA==');
audio.play().catch(() => {
// Ignore audio play errors
});
}, []);

const handleStart = () => {
setLocalStorage('hasSeenAiderOnboarding', true);
navigate('/aiderMode');
};

return (
<OnboardingContainer>
<Title>Welcome to PearAI Creator</Title>
<Description>
Your AI-powered coding companion that helps you build and modify your projects effortlessly.
Just describe what you want to create or change, and we'll handle the implementation.
</Description>

<FeatureList>
<FeatureItem>Create new features by describing them in plain English</FeatureItem>
<FeatureItem>Fix bugs and improve existing code naturally</FeatureItem>
<FeatureItem>Refactor and optimize your codebase effortlessly</FeatureItem>
<FeatureItem>Get intelligent suggestions and solutions</FeatureItem>
</FeatureList>

<StartButton onClick={handleStart}>
Okay! Let's start creating
</StartButton>
</OnboardingContainer>
);
};

export default AiderOnboarding;
20 changes: 19 additions & 1 deletion gui/src/integrations/aider/aidergui.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,16 @@ import {


function AiderGUI() {
const navigate = useNavigate();
useEffect(() => {
const hasSeenOnboarding = getLocalStorage('hasSeenAiderOnboarding');
if (!hasSeenOnboarding) {
navigate('./aiderOnboarding');
}
}, [navigate]);

const posthog = usePostHog();
const dispatch = useDispatch();
const navigate = useNavigate();
const ideMessenger = useContext(IdeMessengerContext);
const isBetaAccess = useSelector((state: RootState) => state.state.config.isBetaAccess);

Expand Down Expand Up @@ -177,8 +184,10 @@ function AiderGUI() {

return (
<>

<TopGuiDiv ref={topGuiDivRef} onScroll={handleScroll}>
<div className="mx-2">

<div className="pl-2 mt-8 border-b border-gray-700">
<div className="flex items-center gap-2">
<h1 className="text-2xl font-bold mb-2">PearAI Creator - Beta</h1>
Expand All @@ -197,6 +206,13 @@ function AiderGUI() {
<p className="text-sm text-gray-400 mt-0">
Ask for a feature, describe a bug, or ask for a change to your project. We'll take care of everything for you!
</p>
<NewSessionButton
onClick={() => {
dispatch(newSession()); // Reset the state
setLocalStorage('hasSeenAiderOnboarding', false); // Reset onboarding flag
navigate("/aiderOnboarding");
}}
>Return to Onboarding (Remove when in prod)</NewSessionButton>
</div>
<StepsDiv>
{state.history.map((item, index: number) => (
Expand Down Expand Up @@ -327,6 +343,8 @@ function AiderGUI() {
Inventory
</NewSessionButton>
}


</>
);
}
Expand Down
87 changes: 87 additions & 0 deletions gui/src/integrations/perplexity/perplexityOnboarding.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import React from 'react';
import { useNavigate } from 'react-router-dom';
import styled from 'styled-components';
import { Button } from '../../components';
import { getLocalStorage, setLocalStorage } from '../../util/localStorage';

const OnboardingContainer = styled.div`
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
min-height: 80vh;
padding: 2rem;
text-align: center;
max-width: 800px;
margin: 0 auto;
`;

const Title = styled.h1`
font-size: 2.5rem;
margin-bottom: 2rem;
color: ${props => props.theme.textColor};
`;

const Description = styled.p`
font-size: 1.2rem;
line-height: 1.6;
margin-bottom: 2rem;
color: ${props => props.theme.secondaryText};
`;

const FeatureList = styled.ul`
list-style-type: none;
padding: 0;
margin-bottom: 2rem;
text-align: left;
`;

const FeatureItem = styled.li`
font-size: 1.1rem;
margin-bottom: 1rem;
padding-left: 1.5rem;
position: relative;

&:before {
content: "→";
position: absolute;
left: 0;
}
`;

const StartButton = styled(Button)`
padding: 1rem 2rem;
font-size: 1.2rem;
`;

const PerplexityOnboarding = () => {
const navigate = useNavigate();

const handleStart = () => {
setLocalStorage('hasSeenPerplexityOnboarding', true);
navigate('/perplexityMode');
};

return (
<OnboardingContainer>
<Title>Welcome to PearAI Creator</Title>
<Description>
Your AI-powered coding companion that helps you build and modify your projects effortlessly.
Just describe what you want to create or change, and we'll handle the implementation.
</Description>

<FeatureList>
<FeatureItem>Create new features by describing them in plain English</FeatureItem>
<FeatureItem>Fix bugs and improve existing code naturally</FeatureItem>
<FeatureItem>Refactor and optimize your codebase effortlessly</FeatureItem>
<FeatureItem>Get intelligent suggestions and solutions</FeatureItem>
</FeatureList>

<StartButton onClick={handleStart}>
Okay! Let's start creating
</StartButton>
</OnboardingContainer>
);
};

export default PerplexityOnboarding;
9 changes: 8 additions & 1 deletion gui/src/integrations/perplexity/perplexitygui.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,16 @@ import {
import { TopGuiDiv, StopButton, StepsDiv, NewSessionButton, fallbackRender } from "../../pages/gui";

function PerplexityGUI() {
const navigate = useNavigate();
useEffect(() => {
const hasSeenOnboarding = getLocalStorage('hasSeenPerplexityOnboarding');
if (!hasSeenOnboarding) {
navigate('./perplexityOnboarding');
}
}, [navigate]);

const posthog = usePostHog();
const dispatch = useDispatch();
const navigate = useNavigate();
const ideMessenger = useContext(IdeMessengerContext);
const isBetaAccess = useSelector((state: RootState) => state.state.config.isBetaAccess);

Expand Down
2 changes: 2 additions & 0 deletions gui/src/util/localStorage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ type LocalStorageTypes = {
showTutorialCard: boolean;
shownProfilesIntroduction: boolean;
disableIndexing: boolean;
hasSeenAiderOnboarding: boolean;
hasSeenPerplexityOnboarding: boolean;
};

export function getLocalStorage<T extends keyof LocalStorageTypes>(
Expand Down