mirror of
https://github.com/kamranahmedse/developer-roadmap.git
synced 2025-09-09 00:30:40 +02:00
Add question answers
This commit is contained in:
1
.astro/types.d.ts
vendored
1
.astro/types.d.ts
vendored
@@ -1 +1,2 @@
|
|||||||
/// <reference types="astro/client" />
|
/// <reference types="astro/client" />
|
||||||
|
/// <reference path="content.d.ts" />
|
@@ -19,6 +19,7 @@ import {
|
|||||||
type QuestionAnswerChatMessage,
|
type QuestionAnswerChatMessage,
|
||||||
} from './QuestionAnswerChat';
|
} from './QuestionAnswerChat';
|
||||||
import { useToast } from '../../hooks/use-toast';
|
import { useToast } from '../../hooks/use-toast';
|
||||||
|
import { cn } from '../../lib/classname';
|
||||||
|
|
||||||
const allowedFormats = ['course', 'guide', 'roadmap'] as const;
|
const allowedFormats = ['course', 'guide', 'roadmap'] as const;
|
||||||
export type AllowedFormat = (typeof allowedFormats)[number];
|
export type AllowedFormat = (typeof allowedFormats)[number];
|
||||||
@@ -159,7 +160,12 @@ export function ContentGenerator() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<label
|
<label
|
||||||
className="flex items-center gap-2 rounded-xl border border-gray-200 bg-white p-4"
|
className={cn(
|
||||||
|
'flex cursor-pointer items-center gap-2 rounded-xl border border-gray-200 bg-white p-4 transition-all',
|
||||||
|
{
|
||||||
|
'rounded-b-none bg-gray-200 text-black': showFineTuneOptions,
|
||||||
|
},
|
||||||
|
)}
|
||||||
htmlFor={fineTuneOptionsId}
|
htmlFor={fineTuneOptionsId}
|
||||||
>
|
>
|
||||||
<input
|
<input
|
||||||
@@ -185,6 +191,7 @@ export function ContentGenerator() {
|
|||||||
|
|
||||||
{showFineTuneOptions && (
|
{showFineTuneOptions && (
|
||||||
<QuestionAnswerChat
|
<QuestionAnswerChat
|
||||||
|
className="-mt-4 rounded-t-none border-t-0"
|
||||||
term={title}
|
term={title}
|
||||||
format={selectedFormat}
|
format={selectedFormat}
|
||||||
questionAnswerChatMessages={questionAnswerChatMessages}
|
questionAnswerChatMessages={questionAnswerChatMessages}
|
||||||
|
@@ -34,6 +34,7 @@ type QuestionAnswerChatProps = {
|
|||||||
onGenerateNow: () => void;
|
onGenerateNow: () => void;
|
||||||
defaultQuestions?: AIQuestionSuggestionsResponse['questions'];
|
defaultQuestions?: AIQuestionSuggestionsResponse['questions'];
|
||||||
type?: 'create' | 'update';
|
type?: 'create' | 'update';
|
||||||
|
className?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export function QuestionAnswerChat(props: QuestionAnswerChatProps) {
|
export function QuestionAnswerChat(props: QuestionAnswerChatProps) {
|
||||||
@@ -45,6 +46,7 @@ export function QuestionAnswerChat(props: QuestionAnswerChatProps) {
|
|||||||
setQuestionAnswerChatMessages,
|
setQuestionAnswerChatMessages,
|
||||||
onGenerateNow,
|
onGenerateNow,
|
||||||
type = 'create',
|
type = 'create',
|
||||||
|
className = '',
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
const [activeMessageIndex, setActiveMessageIndex] = useState(
|
const [activeMessageIndex, setActiveMessageIndex] = useState(
|
||||||
@@ -128,7 +130,12 @@ export function QuestionAnswerChat(props: QuestionAnswerChatProps) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="relative h-[420px] w-full overflow-hidden rounded-xl border border-gray-200 bg-white">
|
<div
|
||||||
|
className={cn(
|
||||||
|
'relative h-[420px] w-full overflow-hidden rounded-xl border border-gray-200 bg-white',
|
||||||
|
className,
|
||||||
|
)}
|
||||||
|
>
|
||||||
{isLoadingAiQuestionSuggestions && (
|
{isLoadingAiQuestionSuggestions && (
|
||||||
<div className="absolute inset-0 flex items-center justify-center bg-white">
|
<div className="absolute inset-0 flex items-center justify-center bg-white">
|
||||||
<div className="flex animate-pulse items-center gap-2 rounded-full border border-gray-200 bg-gray-50 p-2 px-4 text-sm">
|
<div className="flex animate-pulse items-center gap-2 rounded-full border border-gray-200 bg-gray-50 p-2 px-4 text-sm">
|
||||||
@@ -190,6 +197,8 @@ export function QuestionAnswerChat(props: QuestionAnswerChatProps) {
|
|||||||
<QuestionAnswerChatMessage
|
<QuestionAnswerChatMessage
|
||||||
role="assistant"
|
role="assistant"
|
||||||
question={activeMessage?.question ?? ''}
|
question={activeMessage?.question ?? ''}
|
||||||
|
possibleAnswers={activeMessage.possibleAnswers}
|
||||||
|
onAnswerSelect={handleAnswerSelect}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
@@ -215,32 +224,12 @@ export function QuestionAnswerChat(props: QuestionAnswerChatProps) {
|
|||||||
{activeMessage && (
|
{activeMessage && (
|
||||||
<div className="p-2">
|
<div className="p-2">
|
||||||
<div className="rounded-lg border border-gray-200 bg-white">
|
<div className="rounded-lg border border-gray-200 bg-white">
|
||||||
<div className="border-b border-gray-200 p-2">
|
|
||||||
<p className="text-sm text-gray-500">
|
|
||||||
Pick an answer from these or write it below
|
|
||||||
</p>
|
|
||||||
<div className="mt-2 flex flex-wrap gap-2 text-sm text-gray-500">
|
|
||||||
{activeMessage.possibleAnswers.map((answer) => (
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
key={answer}
|
|
||||||
className="cursor-pointer rounded-lg bg-gray-100 p-1 px-2 hover:bg-gray-200 focus:outline-none"
|
|
||||||
onClick={() => {
|
|
||||||
handleAnswerSelect(answer);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{answer}
|
|
||||||
</button>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="flex w-full items-center justify-between gap-2 p-2">
|
<div className="flex w-full items-center justify-between gap-2 p-2">
|
||||||
<input
|
<input
|
||||||
value={message}
|
value={message}
|
||||||
onChange={(e) => setMessage(e.target.value)}
|
onChange={(e) => setMessage(e.target.value)}
|
||||||
className="w-full bg-transparent text-sm focus:outline-none"
|
className="w-full bg-transparent text-sm focus:outline-none"
|
||||||
placeholder="Write your answer here..."
|
placeholder="Or type your own answer..."
|
||||||
autoFocus
|
autoFocus
|
||||||
onKeyDown={(e) => {
|
onKeyDown={(e) => {
|
||||||
if (e.key === 'Enter' && !e.shiftKey) {
|
if (e.key === 'Enter' && !e.shiftKey) {
|
||||||
@@ -287,10 +276,14 @@ type QuestionAnswerChatMessageProps = {
|
|||||||
role: 'user' | 'assistant';
|
role: 'user' | 'assistant';
|
||||||
question?: string;
|
question?: string;
|
||||||
answer?: string;
|
answer?: string;
|
||||||
|
possibleAnswers?: string[];
|
||||||
|
onAnswerSelect?: (answer: string) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
function QuestionAnswerChatMessage(props: QuestionAnswerChatMessageProps) {
|
function QuestionAnswerChatMessage(props: QuestionAnswerChatMessageProps) {
|
||||||
const { role, question, answer } = props;
|
const { role, question, answer, possibleAnswers, onAnswerSelect } = props;
|
||||||
|
|
||||||
|
const hasAnswers = possibleAnswers && possibleAnswers.length > 0;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
@@ -300,7 +293,29 @@ function QuestionAnswerChatMessage(props: QuestionAnswerChatMessageProps) {
|
|||||||
role === 'assistant' && 'border-yellow-200 bg-yellow-300/30',
|
role === 'assistant' && 'border-yellow-200 bg-yellow-300/30',
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{role === 'assistant' && <div className="text-sm">{question}</div>}
|
{role === 'assistant' && (
|
||||||
|
<div className="text-sm">
|
||||||
|
<div className={cn(hasAnswers && 'mb-2')}>{question}</div>
|
||||||
|
{hasAnswers && onAnswerSelect && (
|
||||||
|
<div className="mt-2">
|
||||||
|
<div className="flex flex-wrap gap-1.5">
|
||||||
|
{possibleAnswers.map((answer) => (
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
key={answer}
|
||||||
|
className="cursor-pointer rounded-md bg-white/70 px-2 py-1 text-xs text-gray-700 hover:bg-white hover:shadow-sm focus:outline-none border border-yellow-300/50"
|
||||||
|
onClick={() => {
|
||||||
|
onAnswerSelect(answer);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{answer}
|
||||||
|
</button>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
{role === 'user' && <div className="text-sm">{answer}</div>}
|
{role === 'user' && <div className="text-sm">{answer}</div>}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
Reference in New Issue
Block a user