mirror of
https://github.com/khoaliber/khoj.git
synced 2026-03-09 21:29:11 +00:00
Update the home page suggestion cards
- Rather than chunky generic cards, make the suggested actions more action oriented, around the problem a user might want to solve. Give them follow-up options. Design still in progress.
This commit is contained in:
@@ -168,6 +168,9 @@ const iconMap: IconMap = {
|
|||||||
Broadcast: (color: string, width: string, height: string) => (
|
Broadcast: (color: string, width: string, height: string) => (
|
||||||
<Broadcast className={`${width} ${height} ${color} mr-2`} />
|
<Broadcast className={`${width} ${height} ${color} mr-2`} />
|
||||||
),
|
),
|
||||||
|
Image: (color: string, width: string, height: string) => (
|
||||||
|
<Image className={`${width} ${height} ${color} mr-2`} />
|
||||||
|
),
|
||||||
};
|
};
|
||||||
|
|
||||||
export function getIconForSlashCommand(command: string, customClassName: string | null = null) {
|
export function getIconForSlashCommand(command: string, customClassName: string | null = null) {
|
||||||
|
|||||||
@@ -65,6 +65,12 @@ export interface AttachedFileText {
|
|||||||
size: number;
|
size: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export enum ChatInputFocus {
|
||||||
|
MESSAGE = "message",
|
||||||
|
FILE = "file",
|
||||||
|
RESEARCH = "research",
|
||||||
|
}
|
||||||
|
|
||||||
interface ChatInputProps {
|
interface ChatInputProps {
|
||||||
sendMessage: (message: string) => void;
|
sendMessage: (message: string) => void;
|
||||||
sendImage: (image: string) => void;
|
sendImage: (image: string) => void;
|
||||||
@@ -77,11 +83,15 @@ interface ChatInputProps {
|
|||||||
agentColor?: string;
|
agentColor?: string;
|
||||||
isResearchModeEnabled?: boolean;
|
isResearchModeEnabled?: boolean;
|
||||||
setTriggeredAbort: (value: boolean) => void;
|
setTriggeredAbort: (value: boolean) => void;
|
||||||
|
prefillMessage?: string;
|
||||||
|
focus?: ChatInputFocus;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ChatInputArea = forwardRef<HTMLTextAreaElement, ChatInputProps>((props, ref) => {
|
export const ChatInputArea = forwardRef<HTMLTextAreaElement, ChatInputProps>((props, ref) => {
|
||||||
const [message, setMessage] = useState("");
|
const [message, setMessage] = useState("");
|
||||||
const fileInputRef = useRef<HTMLInputElement>(null);
|
const fileInputRef = useRef<HTMLInputElement>(null);
|
||||||
|
const fileInputButtonRef = useRef<HTMLButtonElement>(null);
|
||||||
|
const researchModeRef = useRef<HTMLButtonElement>(null);
|
||||||
|
|
||||||
const [warning, setWarning] = useState<string | null>(null);
|
const [warning, setWarning] = useState<string | null>(null);
|
||||||
const [error, setError] = useState<string | null>(null);
|
const [error, setError] = useState<string | null>(null);
|
||||||
@@ -125,6 +135,22 @@ export const ChatInputArea = forwardRef<HTMLTextAreaElement, ChatInputProps>((pr
|
|||||||
}
|
}
|
||||||
}, [uploading]);
|
}, [uploading]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (props.prefillMessage) {
|
||||||
|
setMessage(props.prefillMessage);
|
||||||
|
}
|
||||||
|
}, [props.prefillMessage]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (props.focus === ChatInputFocus.MESSAGE) {
|
||||||
|
chatInputRef?.current?.focus();
|
||||||
|
} else if (props.focus === ChatInputFocus.FILE) {
|
||||||
|
fileInputButtonRef.current?.focus();
|
||||||
|
} else if (props.focus === ChatInputFocus.RESEARCH) {
|
||||||
|
researchModeRef.current?.focus();
|
||||||
|
}
|
||||||
|
}, [props.focus]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
async function fetchImageData() {
|
async function fetchImageData() {
|
||||||
if (imagePaths.length > 0) {
|
if (imagePaths.length > 0) {
|
||||||
@@ -630,6 +656,7 @@ export const ChatInputArea = forwardRef<HTMLTextAreaElement, ChatInputProps>((pr
|
|||||||
className="!bg-none p-0 m-2 h-auto text-3xl rounded-full text-gray-300 hover:text-gray-500"
|
className="!bg-none p-0 m-2 h-auto text-3xl rounded-full text-gray-300 hover:text-gray-500"
|
||||||
disabled={props.sendDisabled || !props.isLoggedIn}
|
disabled={props.sendDisabled || !props.isLoggedIn}
|
||||||
onClick={handleFileButtonClick}
|
onClick={handleFileButtonClick}
|
||||||
|
ref={fileInputButtonRef}
|
||||||
>
|
>
|
||||||
<Paperclip className="w-8 h-8" />
|
<Paperclip className="w-8 h-8" />
|
||||||
</Button>
|
</Button>
|
||||||
@@ -732,6 +759,7 @@ export const ChatInputArea = forwardRef<HTMLTextAreaElement, ChatInputProps>((pr
|
|||||||
variant="ghost"
|
variant="ghost"
|
||||||
className="float-right justify-center gap-1 flex items-center p-1.5 mr-2 h-fit"
|
className="float-right justify-center gap-1 flex items-center p-1.5 mr-2 h-fit"
|
||||||
disabled={props.sendDisabled || !props.isLoggedIn}
|
disabled={props.sendDisabled || !props.isLoggedIn}
|
||||||
|
ref={researchModeRef}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setUseResearchMode(!useResearchMode);
|
setUseResearchMode(!useResearchMode);
|
||||||
chatInputRef?.current?.focus();
|
chatInputRef?.current?.focus();
|
||||||
|
|||||||
@@ -1,25 +1,32 @@
|
|||||||
"use client";
|
"use client";
|
||||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
|
import { Card, CardContent, CardDescription } from "@/components/ui/card";
|
||||||
|
|
||||||
import styles from "./suggestions.module.css";
|
import styles from "./suggestions.module.css";
|
||||||
import { converColorToBgGradient } from "@/app/common/colorUtils";
|
|
||||||
import { convertSuggestionTitleToIconClass } from "./suggestionsData";
|
import { convertSuggestionTitleToIconClass } from "./suggestionsData";
|
||||||
|
import { ArrowLeft, ArrowRight } from "@phosphor-icons/react";
|
||||||
|
|
||||||
interface SuggestionCardProps {
|
interface StepOneSuggestionCardProps {
|
||||||
title: string;
|
title: string;
|
||||||
body: string;
|
body: string;
|
||||||
link: string;
|
|
||||||
color: string;
|
color: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function SuggestionCard(data: SuggestionCardProps) {
|
interface StepOneSuggestionRevertCardProps extends StepOneSuggestionCardProps {
|
||||||
const cardClassName = `${styles.card} md:w-full md:h-fit sm:w-full h-fit md:w-[200px] md:h-[180px] cursor-pointer md:p-2`;
|
onClick: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface StepTwoSuggestionCardProps {
|
||||||
|
prompt: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function StepOneSuggestionCard(data: StepOneSuggestionCardProps) {
|
||||||
|
const cardClassName = `${styles.card} md:w-full md:h-fit sm:w-full h-fit md:w-[200px] cursor-pointer md:p-2`;
|
||||||
const descriptionClassName = `${styles.text} dark:text-white`;
|
const descriptionClassName = `${styles.text} dark:text-white`;
|
||||||
|
|
||||||
const cardContent = (
|
const cardContent = (
|
||||||
<Card className={cardClassName}>
|
<Card className={cardClassName}>
|
||||||
<div className="flex w-full">
|
<div className="flex w-full">
|
||||||
<CardContent className="m-0 p-2 w-full">
|
<CardContent className="m-0 p-2 w-full flex flex-row">
|
||||||
{convertSuggestionTitleToIconClass(data.title, data.color.toLowerCase())}
|
{convertSuggestionTitleToIconClass(data.title, data.color.toLowerCase())}
|
||||||
<CardDescription
|
<CardDescription
|
||||||
className={`${descriptionClassName} sm:line-clamp-2 md:line-clamp-4 pt-1 break-words whitespace-pre-wrap max-w-full`}
|
className={`${descriptionClassName} sm:line-clamp-2 md:line-clamp-4 pt-1 break-words whitespace-pre-wrap max-w-full`}
|
||||||
@@ -31,11 +38,45 @@ export default function SuggestionCard(data: SuggestionCardProps) {
|
|||||||
</Card>
|
</Card>
|
||||||
);
|
);
|
||||||
|
|
||||||
return data.link ? (
|
return cardContent;
|
||||||
<a href={data.link} className="no-underline">
|
}
|
||||||
{cardContent}
|
|
||||||
</a>
|
export function StepTwoSuggestionCard(data: StepTwoSuggestionCardProps) {
|
||||||
) : (
|
const cardClassName = `${styles.card} md:h-fit sm:w-full h-fit cursor-pointer md:p-2`;
|
||||||
cardContent
|
|
||||||
|
return (
|
||||||
|
<Card className={cardClassName}>
|
||||||
|
<div className="flex w-full items-center">
|
||||||
|
<CardContent className="m-0 p-2 w-full flex flex-row items-center">
|
||||||
|
<ArrowRight className="w-6 h-6 text-muted-foreground inline-flex mr-1" />
|
||||||
|
<CardDescription
|
||||||
|
className={`sm:line-clamp-2 md:line-clamp-4 break-words whitespace-pre-wrap max-w-full text-sm text-wrap text-black dark:text-white`}
|
||||||
|
>
|
||||||
|
{data.prompt}
|
||||||
|
</CardDescription>
|
||||||
|
</CardContent>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function StepOneSuggestionRevertCard(data: StepOneSuggestionRevertCardProps) {
|
||||||
|
const cardClassName = `${styles.card} md:w-full md:h-fit sm:w-full h-fit md:w-[200px] cursor-pointer md:p-2 animate-fade-in-up`;
|
||||||
|
const descriptionClassName = `${styles.text} dark:text-white`;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Card className={cardClassName} onClick={data.onClick}>
|
||||||
|
<div className="flex w-full">
|
||||||
|
<CardContent className="m-0 p-2 w-full flex flex-row">
|
||||||
|
<ArrowLeft className="w-4 h-4 text-muted-foreground inline-flex mr-1" />
|
||||||
|
{convertSuggestionTitleToIconClass(data.title, data.color.toLowerCase())}
|
||||||
|
<CardDescription
|
||||||
|
className={`${descriptionClassName} sm:line-clamp-2 md:line-clamp-4 pt-1 break-words whitespace-pre-wrap max-w-full`}
|
||||||
|
>
|
||||||
|
{data.body}
|
||||||
|
</CardDescription>
|
||||||
|
</CardContent>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -8,14 +8,25 @@ import useSWR from "swr";
|
|||||||
import { ArrowCounterClockwise } from "@phosphor-icons/react";
|
import { ArrowCounterClockwise } from "@phosphor-icons/react";
|
||||||
|
|
||||||
import { Card, CardTitle } from "@/components/ui/card";
|
import { Card, CardTitle } from "@/components/ui/card";
|
||||||
import SuggestionCard from "@/app/components/suggestions/suggestionCard";
|
import {
|
||||||
|
StepOneSuggestionCard,
|
||||||
|
StepOneSuggestionRevertCard,
|
||||||
|
StepTwoSuggestionCard,
|
||||||
|
} from "@/app/components/suggestions/suggestionCard";
|
||||||
import Loading from "@/app/components/loading/loading";
|
import Loading from "@/app/components/loading/loading";
|
||||||
import {
|
import {
|
||||||
AttachedFileText,
|
AttachedFileText,
|
||||||
ChatInputArea,
|
ChatInputArea,
|
||||||
|
ChatInputFocus,
|
||||||
ChatOptions,
|
ChatOptions,
|
||||||
} from "@/app/components/chatInputArea/chatInputArea";
|
} from "@/app/components/chatInputArea/chatInputArea";
|
||||||
import { Suggestion, suggestionsData } from "@/app/components/suggestions/suggestionsData";
|
import {
|
||||||
|
StepOneSuggestion,
|
||||||
|
stepOneSuggestions,
|
||||||
|
StepTwoSuggestion,
|
||||||
|
getStepTwoSuggestions,
|
||||||
|
SuggestionType,
|
||||||
|
} from "@/app/components/suggestions/suggestionsData";
|
||||||
import LoginPrompt from "@/app/components/loginPrompt/loginPrompt";
|
import LoginPrompt from "@/app/components/loginPrompt/loginPrompt";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@@ -38,6 +49,7 @@ import { SidebarInset, SidebarProvider, SidebarTrigger } from "@/components/ui/s
|
|||||||
import { AppSidebar } from "./components/appSidebar/appSidebar";
|
import { AppSidebar } from "./components/appSidebar/appSidebar";
|
||||||
import { Separator } from "@/components/ui/separator";
|
import { Separator } from "@/components/ui/separator";
|
||||||
import { KhojLogoType } from "./components/logo/khojLogo";
|
import { KhojLogoType } from "./components/logo/khojLogo";
|
||||||
|
import { Button } from "@/components/ui/button";
|
||||||
|
|
||||||
interface ChatBodyDataProps {
|
interface ChatBodyDataProps {
|
||||||
chatOptionsData: ChatOptions | null;
|
chatOptionsData: ChatOptions | null;
|
||||||
@@ -59,10 +71,19 @@ function FisherYatesShuffle(array: any[]) {
|
|||||||
|
|
||||||
function ChatBodyData(props: ChatBodyDataProps) {
|
function ChatBodyData(props: ChatBodyDataProps) {
|
||||||
const [message, setMessage] = useState("");
|
const [message, setMessage] = useState("");
|
||||||
|
const [prefilledMessage, setPrefilledMessage] = useState("");
|
||||||
|
const [chatInputFocus, setChatInputFocus] = useState<ChatInputFocus>(ChatInputFocus.MESSAGE);
|
||||||
const [images, setImages] = useState<string[]>([]);
|
const [images, setImages] = useState<string[]>([]);
|
||||||
const [processingMessage, setProcessingMessage] = useState(false);
|
const [processingMessage, setProcessingMessage] = useState(false);
|
||||||
const [greeting, setGreeting] = useState("");
|
const [greeting, setGreeting] = useState("");
|
||||||
const [shuffledOptions, setShuffledOptions] = useState<Suggestion[]>([]);
|
const [stepOneSuggestionOptions, setStepOneSuggestionOptions] = useState<StepOneSuggestion[]>(
|
||||||
|
[],
|
||||||
|
);
|
||||||
|
const [stepTwoSuggestionOptions, setStepTwoSuggestionOptions] = useState<StepTwoSuggestion[]>(
|
||||||
|
[],
|
||||||
|
);
|
||||||
|
const [selectedStepOneSuggestion, setSelectedStepOneSuggestion] =
|
||||||
|
useState<StepOneSuggestion | null>(null);
|
||||||
const [hoveredAgent, setHoveredAgent] = useState<string | null>(null);
|
const [hoveredAgent, setHoveredAgent] = useState<string | null>(null);
|
||||||
const debouncedHoveredAgent = useDebounce(hoveredAgent, 500);
|
const debouncedHoveredAgent = useDebounce(hoveredAgent, 500);
|
||||||
const [isPopoverOpen, setIsPopoverOpen] = useState(false);
|
const [isPopoverOpen, setIsPopoverOpen] = useState(false);
|
||||||
@@ -103,8 +124,8 @@ function ChatBodyData(props: ChatBodyDataProps) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
function shuffleAndSetOptions() {
|
function shuffleAndSetOptions() {
|
||||||
const shuffled = FisherYatesShuffle(suggestionsData);
|
const shuffled = FisherYatesShuffle(stepOneSuggestions);
|
||||||
setShuffledOptions(shuffled.slice(0, 3));
|
setStepOneSuggestionOptions(shuffled.slice(0, 3));
|
||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -148,8 +169,8 @@ function ChatBodyData(props: ChatBodyDataProps) {
|
|||||||
setAgentIcons(agentIcons);
|
setAgentIcons(agentIcons);
|
||||||
}, [agentsData, props.isMobileWidth]);
|
}, [agentsData, props.isMobileWidth]);
|
||||||
|
|
||||||
function shuffleSuggestionsCards() {
|
function showAllSuggestionsCards() {
|
||||||
shuffleAndSetOptions();
|
setStepOneSuggestionOptions(stepOneSuggestions);
|
||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -193,27 +214,22 @@ function ChatBodyData(props: ChatBodyDataProps) {
|
|||||||
return () => scrollAreaEl?.removeEventListener("scroll", handleScroll);
|
return () => scrollAreaEl?.removeEventListener("scroll", handleScroll);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
function fillArea(link: string, type: string, prompt: string) {
|
function clickStepOneSuggestion(suggestion: StepOneSuggestion) {
|
||||||
if (!link) {
|
let message_str = "";
|
||||||
let message_str = "";
|
let prompt =
|
||||||
prompt = prompt.charAt(0).toLowerCase() + prompt.slice(1);
|
suggestion.description.charAt(0).toLowerCase() + suggestion.description.slice(1);
|
||||||
|
|
||||||
if (type === "Online Search") {
|
if (suggestion.type === "Paint") {
|
||||||
message_str = "/online " + prompt;
|
message_str = "/image " + prompt;
|
||||||
} else if (type === "Paint") {
|
} else {
|
||||||
message_str = "/image " + prompt;
|
message_str = prompt;
|
||||||
} else {
|
|
||||||
message_str = prompt;
|
|
||||||
}
|
|
||||||
// Get the textarea element
|
|
||||||
const message_area = document.getElementById("message") as HTMLTextAreaElement;
|
|
||||||
|
|
||||||
if (message_area) {
|
|
||||||
// Update the value directly
|
|
||||||
message_area.value = message_str;
|
|
||||||
setMessage(message_str);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setPrefilledMessage(message_str);
|
||||||
|
const stepTwoSuggestions = getStepTwoSuggestions(suggestion.type);
|
||||||
|
setSelectedStepOneSuggestion(suggestion);
|
||||||
|
setStepTwoSuggestionOptions(stepTwoSuggestions);
|
||||||
|
setChatInputFocus(ChatInputFocus.FILE);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -306,13 +322,15 @@ function ChatBodyData(props: ChatBodyDataProps) {
|
|||||||
</ScrollArea>
|
</ScrollArea>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className={`mx-auto ${props.isMobileWidth ? "w-full" : "w-fit max-w-screen-md"}`}>
|
<div className={`mx-auto ${props.isMobileWidth ? "w-full" : "w-full max-w-screen-md"}`}>
|
||||||
{!props.isMobileWidth && (
|
{!props.isMobileWidth && (
|
||||||
<div
|
<div
|
||||||
className={`w-full ${styles.inputBox} shadow-lg bg-background align-middle items-center justify-center px-3 py-1 dark:bg-neutral-700 border-stone-100 dark:border-none dark:shadow-none rounded-2xl`}
|
className={`w-full ${styles.inputBox} shadow-lg bg-background align-middle items-center justify-center px-3 py-1 dark:bg-neutral-700 border-stone-100 dark:border-none dark:shadow-none rounded-2xl`}
|
||||||
>
|
>
|
||||||
<ChatInputArea
|
<ChatInputArea
|
||||||
isLoggedIn={props.isLoggedIn}
|
isLoggedIn={props.isLoggedIn}
|
||||||
|
prefillMessage={prefilledMessage}
|
||||||
|
focus={chatInputFocus}
|
||||||
sendMessage={(message) => setMessage(message)}
|
sendMessage={(message) => setMessage(message)}
|
||||||
sendImage={(image) => setImages((prevImages) => [...prevImages, image])}
|
sendImage={(image) => setImages((prevImages) => [...prevImages, image])}
|
||||||
sendDisabled={processingMessage}
|
sendDisabled={processingMessage}
|
||||||
@@ -327,43 +345,74 @@ function ChatBodyData(props: ChatBodyDataProps) {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<div
|
<div
|
||||||
className={`${styles.suggestions} w-full ${props.isMobileWidth ? "grid" : "flex flex-row"} justify-center items-center`}
|
className={`${styles.suggestions} w-full ${props.isMobileWidth ? "grid" : "grid grid-cols-3"} justify-center items-center`}
|
||||||
>
|
>
|
||||||
{shuffledOptions.map((suggestion, index) => (
|
{stepTwoSuggestionOptions.length == 0 &&
|
||||||
<div
|
stepOneSuggestionOptions.map((suggestion, index) => (
|
||||||
key={`${suggestion.type} ${suggestion.description}`}
|
<div
|
||||||
onClick={(event) => {
|
key={`${suggestion.type} ${suggestion.description}`}
|
||||||
if (props.isLoggedIn) {
|
onClick={(event) => {
|
||||||
fillArea(
|
if (props.isLoggedIn) {
|
||||||
suggestion.link,
|
clickStepOneSuggestion(suggestion);
|
||||||
suggestion.type,
|
} else {
|
||||||
suggestion.description,
|
event.preventDefault();
|
||||||
);
|
event.stopPropagation();
|
||||||
} else {
|
setShowLoginPrompt(true);
|
||||||
event.preventDefault();
|
}
|
||||||
event.stopPropagation();
|
}}
|
||||||
setShowLoginPrompt(true);
|
>
|
||||||
}
|
<StepOneSuggestionCard
|
||||||
}}
|
key={suggestion.type + Math.random()}
|
||||||
>
|
title={suggestion.type}
|
||||||
<SuggestionCard
|
body={suggestion.description}
|
||||||
key={suggestion.type + Math.random()}
|
color={suggestion.color}
|
||||||
title={suggestion.type}
|
/>
|
||||||
body={suggestion.description}
|
</div>
|
||||||
link={suggestion.link}
|
))}
|
||||||
color={suggestion.color}
|
</div>
|
||||||
/>
|
{stepTwoSuggestionOptions.length == 0 &&
|
||||||
|
stepOneSuggestionOptions.length < stepOneSuggestions.length && (
|
||||||
|
<div className="flex items-center justify-center margin-auto">
|
||||||
|
<button
|
||||||
|
onClick={showAllSuggestionsCards}
|
||||||
|
className="m-2 p-1.5 rounded-lg dark:hover:bg-[var(--background-color)] hover:bg-stone-100 border border-stone-100 text-sm text-stone-500 dark:text-stone-300 dark:border-neutral-700"
|
||||||
|
>
|
||||||
|
More Actions <ArrowCounterClockwise className="h-4 w-4 inline" />
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
))}
|
)}
|
||||||
</div>
|
{selectedStepOneSuggestion && (
|
||||||
<div className="flex items-center justify-center margin-auto">
|
<StepOneSuggestionRevertCard
|
||||||
<button
|
title={selectedStepOneSuggestion.type}
|
||||||
onClick={shuffleSuggestionsCards}
|
body={selectedStepOneSuggestion.description}
|
||||||
className="m-2 p-1.5 rounded-lg dark:hover:bg-[var(--background-color)] hover:bg-stone-100 border border-stone-100 text-sm text-stone-500 dark:text-stone-300 dark:border-neutral-700"
|
color={selectedStepOneSuggestion.color}
|
||||||
|
onClick={() => {
|
||||||
|
setSelectedStepOneSuggestion(null);
|
||||||
|
setStepTwoSuggestionOptions([]);
|
||||||
|
setChatInputFocus(ChatInputFocus.MESSAGE);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{stepTwoSuggestionOptions.length > 0 && (
|
||||||
|
<div
|
||||||
|
className={`w-full ${props.isMobileWidth ? "grid" : "grid grid-cols-1"} justify-center items-center gap-2 pt-2`}
|
||||||
>
|
>
|
||||||
More Ideas <ArrowCounterClockwise className="h-4 w-4 inline" />
|
{stepTwoSuggestionOptions.map((suggestion, index) => (
|
||||||
</button>
|
<div
|
||||||
</div>
|
key={`${suggestion.prompt} ${index}`}
|
||||||
|
className={`w-full cursor-pointer animate-fade-in-up`}
|
||||||
|
onClick={(event) => {
|
||||||
|
setMessage(suggestion.prompt);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<StepTwoSuggestionCard
|
||||||
|
key={suggestion.prompt}
|
||||||
|
prompt={suggestion.prompt}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
{props.isMobileWidth && (
|
{props.isMobileWidth && (
|
||||||
<>
|
<>
|
||||||
|
|||||||
@@ -133,11 +133,16 @@ const config = {
|
|||||||
opacity: "0",
|
opacity: "0",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
fadeInUp: {
|
||||||
|
"0%": { opacity: "0", transform: "translateY(20px)" },
|
||||||
|
"100%": { opacity: "1", transform: "translateY(0)" },
|
||||||
|
},
|
||||||
},
|
},
|
||||||
animation: {
|
animation: {
|
||||||
"accordion-down": "accordion-down 0.2s ease-out",
|
"accordion-down": "accordion-down 0.2s ease-out",
|
||||||
"accordion-up": "accordion-up 0.2s ease-out",
|
"accordion-up": "accordion-up 0.2s ease-out",
|
||||||
"caret-blink": "caret-blink 1.25s ease-out infinite",
|
"caret-blink": "caret-blink 1.25s ease-out infinite",
|
||||||
|
"fade-in-up": "fadeInUp 0.3s ease-out",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user