pull/5267/head
Kamran Ahmed 11 months ago
parent 797b1e6dca
commit 08a315c341
  1. BIN
      public/images/icons8-wand.gif
  2. 91
      src/components/GenerateRoadmap/GenerateRoadmap.tsx
  3. 51
      src/components/GenerateRoadmap/RoadmapSearch.tsx
  4. 2
      src/layouts/BaseLayout.astro

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

@ -7,18 +7,24 @@ import { renderFlowJSON } from '../../../editor/renderer/renderer';
import { replaceChildren } from '../../lib/dom'; import { replaceChildren } from '../../lib/dom';
import { readAIRoadmapStream } from '../../helper/read-stream'; import { readAIRoadmapStream } from '../../helper/read-stream';
import { removeAuthToken } from '../../lib/jwt'; import { removeAuthToken } from '../../lib/jwt';
import { RoadmapSearch } from './RoadmapSearch.tsx';
import { Spinner } from '../ReactIcons/Spinner.tsx';
import { Download, PenSquare, Wand } from 'lucide-react';
import { ShareRoadmapButton } from '../ShareRoadmapButton.tsx';
export function GenerateRoadmap() { export function GenerateRoadmap() {
const roadmapContainerRef = useRef<HTMLDivElement>(null); const roadmapContainerRef = useRef<HTMLDivElement>(null);
const toast = useToast(); const toast = useToast();
const [hasSubmitted, setHasSubmitted] = useState<boolean>(false);
const [isLoading, setIsLoading] = useState(false); const [isLoading, setIsLoading] = useState(false);
const [roadmapName, setRoadmapName] = useState(''); const [roadmapTopic, setRoadmapTopic] = useState('');
const handleSubmit = async (e: FormEvent<HTMLFormElement>) => { const handleSubmit = async (e: FormEvent<HTMLFormElement>) => {
e.preventDefault(); e.preventDefault();
setIsLoading(true); setIsLoading(true);
setHasSubmitted(true);
const response = await fetch( const response = await fetch(
`${import.meta.env.PUBLIC_API_URL}/v1-generate-ai-roadmap`, `${import.meta.env.PUBLIC_API_URL}/v1-generate-ai-roadmap`,
@ -28,7 +34,7 @@ export function GenerateRoadmap() {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
}, },
credentials: 'include', credentials: 'include',
body: JSON.stringify({ title: roadmapName }), body: JSON.stringify({ title: roadmapTopic }),
}, },
); );
@ -64,42 +70,77 @@ export function GenerateRoadmap() {
setIsLoading(false); setIsLoading(false);
}; };
if (!hasSubmitted) {
return ( return (
<section className="container grid grid-cols-[280px,1fr]"> <RoadmapSearch
roadmapTopic={roadmapTopic}
setRoadmapTopic={setRoadmapTopic}
handleSubmit={handleSubmit}
/>
);
}
return (
<section className="flex flex-grow flex-col bg-gray-100">
<div className="flex items-center justify-center border-b bg-white py-6">
{isLoading && (
<span className="flex items-center gap-2 rounded-full bg-black px-3 py-1 text-white">
<Spinner isDualRing={false} innerFill={'white'} />
Generating roadmap ..
</span>
)}
{!isLoading && (
<div className="flex max-w-[600px] flex-grow flex-col items-center">
<div className="mt-2 flex w-full items-center justify-between text-sm">
<span className="text-gray-800">
0 of 5 roadmaps generated <button className='underline underline-offset-2 font-medium text-black'>Login to increase your limit</button>
</span>
</div>
<form <form
className="h-full space-y-4 border-r px-4 py-10"
onSubmit={handleSubmit} onSubmit={handleSubmit}
className="my-3 flex w-full flex-row items-center justify-center gap-2"
> >
<div className="flex w-full flex-col">
<label
htmlFor="roadmap-name"
className='text-sm leading-none text-slate-500 after:text-red-400 after:content-["*"]'
>
Roadmap Title
</label>
<input <input
type="text" type="text"
name="roadmap-name" autoFocus
id="roadmap-name" placeholder="e.g. Ansible"
className="mt-2 block w-full appearance-none rounded-lg border border-gray-300 px-3 py-2 shadow-sm outline-none placeholder:text-gray-400 focus:ring-2 focus:ring-black focus:ring-offset-1" className="flex-grow rounded-md border border-gray-400 px-3 py-2 transition-colors focus:border-black focus:outline-none"
required value={roadmapTopic}
placeholder="Frontend"
value={roadmapName}
onInput={(e) => onInput={(e) =>
setRoadmapName((e.target as HTMLInputElement).value) setRoadmapTopic((e.target as HTMLInputElement).value)
} }
/> />
</div>
<button <button
type="submit" type={'submit'}
disabled={isLoading} className="flex flex-shrink-0 items-center gap-2 rounded-md border border-black bg-black px-4 py-2 text-white"
className="inline-flex w-full items-center justify-center rounded-lg bg-black p-2 py-3 text-sm font-medium text-white outline-none focus:ring-2 focus:ring-black focus:ring-offset-1 disabled:bg-gray-400"
> >
{isLoading ? 'Please wait...' : 'Generate'} <Wand size={20} />
Generate
</button> </button>
</form> </form>
<div className="flex w-full items-center justify-between gap-2">
<div ref={roadmapContainerRef} className="px-4 py-10" /> <div className="flex items-center justify-between gap-2">
<button className="inline-flex items-center justify-center gap-2 rounded-md bg-yellow-400 py-1.5 pl-2.5 pr-3 text-xs font-medium transition-opacity duration-300 hover:bg-yellow-500 sm:text-sm">
<Download size={15} />
Download
</button>
<ShareRoadmapButton
description={'c'}
pageUrl={'https://roadmap.sh'}
/>
</div>
<button className="inline-flex items-center justify-center gap-2 rounded-md bg-gray-200 py-1.5 pl-2.5 pr-3 text-xs font-medium text-black transition-colors transition-opacity duration-300 hover:bg-gray-300 sm:text-sm">
<PenSquare size={15} />
Edit in Editor
</button>
</div>
</div>
)}
</div>
<div
ref={roadmapContainerRef}
className="px-4 py-5 [&>svg]:mx-auto [&>svg]:max-w-[1300px] "
/>
</section> </section>
); );
} }

@ -0,0 +1,51 @@
import { Wand } from 'lucide-react';
import type { FormEvent } from 'react';
type RoadmapSearchProps = {
roadmapTopic: string;
setRoadmapTopic: (topic: string) => void;
handleSubmit: (e: FormEvent<HTMLFormElement>) => void;
};
export function RoadmapSearch(props: RoadmapSearchProps) {
const { roadmapTopic, setRoadmapTopic, handleSubmit } = props;
return (
<div className="flex flex-grow flex-col items-center justify-center py-6">
<div className="flex flex-col gap-2 text-center">
<h1 className="relative text-3xl font-medium">
Generate roadmaps with AI
</h1>
<p className="text-lg text-gray-500">
Enter a topic and let the AI generate a roadmap for you
</p>
</div>
<form
onSubmit={handleSubmit}
className="my-6 flex w-full max-w-[600px] flex-row"
>
<input
autoFocus
type="text"
placeholder="e.g. Ansible"
className="w-full rounded-md border border-gray-400 px-3 py-2.5 transition-colors focus:border-black focus:outline-none"
value={roadmapTopic}
onInput={(e) => setRoadmapTopic((e.target as HTMLInputElement).value)}
/>
<button className="ml-2 flex flex-shrink-0 items-center gap-2 rounded-md bg-black px-4 py-2 text-white">
<Wand size={20} />
Generate
</button>
</form>
<div className="mb-36">
<p className="text-gray-500">
You have generated <span className="text-gray-800">0 of 5</span>{' '}
roadmaps today.{' '}
<button className="font-semibold text-black underline underline-offset-2">
Log in to increase your limit
</button>
</p>
</div>
</div>
);
}

@ -149,7 +149,7 @@ const gaPageIdentifier = Astro.url.pathname
) )
} }
</head> </head>
<body> <body class='flex min-h-screen flex-col'>
<slot name='page-header'> <slot name='page-header'>
<Navigation /> <Navigation />
</slot> </slot>

Loading…
Cancel
Save