chatbot-template/components/chat/suggested-actions.tsx
dmitry.galkin 3e21c2334c Initial commit: EGBE chatbot template
Stripped from vercel/chatbot (Apache 2.0):
- Dropped @vercel/* packages and AI Gateway
- Removed artifacts feature (code/text/sheet/image side panel)
- Switched AI provider to @ai-sdk/openai-compatible -> EGBE LiteLLM
- Replaced Vercel Blob upload with data URLs
- Dropped Redis resumable streams and rate limiter (in-memory now)
- Added Dockerfile (Next.js standalone) + entrypoint that runs migrations
- Wired DATABASE_URL, EGBE_AI_API_URL/KEY, NEXT_PUBLIC_BASE_URL for app-deploy.sh
2026-05-25 14:54:04 +04:00

78 lines
2.5 KiB
TypeScript

"use client";
import type { UseChatHelpers } from "@ai-sdk/react";
import { motion } from "framer-motion";
import { memo } from "react";
import { suggestions } from "@/lib/constants";
import type { ChatMessage } from "@/lib/types";
import { Suggestion } from "../ai-elements/suggestion";
import type { VisibilityType } from "./visibility-selector";
type SuggestedActionsProps = {
chatId: string;
sendMessage: UseChatHelpers<ChatMessage>["sendMessage"];
selectedVisibilityType: VisibilityType;
};
function PureSuggestedActions({ chatId, sendMessage }: SuggestedActionsProps) {
const suggestedActions = suggestions;
return (
<div
className="flex w-full gap-2.5 overflow-x-auto pb-1 sm:grid sm:grid-cols-2 sm:overflow-visible"
data-testid="suggested-actions"
style={{
scrollbarWidth: "none",
WebkitOverflowScrolling: "touch",
msOverflowStyle: "none",
}}
>
{suggestedActions.map((suggestedAction, index) => (
<motion.div
animate={{ opacity: 1, y: 0 }}
className="min-w-[200px] shrink-0 sm:min-w-0 sm:shrink"
exit={{ opacity: 0, y: 16 }}
initial={{ opacity: 0, y: 16 }}
key={suggestedAction}
transition={{
delay: 0.06 * index,
duration: 0.4,
ease: [0.22, 1, 0.36, 1],
}}
>
<Suggestion
className="h-auto w-full whitespace-nowrap rounded-xl border border-border/50 bg-card/30 px-4 py-3 text-left text-[12px] leading-relaxed text-muted-foreground transition-all duration-200 sm:whitespace-normal sm:p-4 sm:text-[13px] hover:-translate-y-0.5 hover:bg-card/60 hover:text-foreground hover:shadow-[var(--shadow-card)]"
onClick={(suggestion) => {
window.history.pushState(
{},
"",
`${process.env.NEXT_PUBLIC_BASE_PATH ?? ""}/chat/${chatId}`
);
sendMessage({
role: "user",
parts: [{ type: "text", text: suggestion }],
});
}}
suggestion={suggestedAction}
>
{suggestedAction}
</Suggestion>
</motion.div>
))}
</div>
);
}
export const SuggestedActions = memo(
PureSuggestedActions,
(prevProps, nextProps) => {
if (prevProps.chatId !== nextProps.chatId) {
return false;
}
if (prevProps.selectedVisibilityType !== nextProps.selectedVisibilityType) {
return false;
}
return true;
}
);