Improve chat scroll behavior and UI; add prompt patterns and content for Sample MCPs
This commit is contained in:
parent
85ef56f301
commit
89873a990f
@ -23,6 +23,11 @@
|
|||||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&display=swap" rel="stylesheet">
|
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&display=swap" rel="stylesheet">
|
||||||
<link href="https://fonts.googleapis.com/css2?family=Fredoka:wght@300..700&family=Nunito:ital,wght@0,200..1000;1,200..1000&family=Poppins:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&family=Quicksand:wght@300..700&display=swap" rel="stylesheet">
|
<link href="https://fonts.googleapis.com/css2?family=Fredoka:wght@300..700&family=Nunito:ital,wght@0,200..1000;1,200..1000&family=Poppins:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&family=Quicksand:wght@300..700&display=swap" rel="stylesheet">
|
||||||
|
|
||||||
|
<style>
|
||||||
|
html {
|
||||||
|
scroll-behavior: smooth;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body style="font-family: 'Inter', sans-serif;">
|
<body style="font-family: 'Inter', sans-serif;">
|
||||||
|
@ -22,6 +22,10 @@ html, body, #root {
|
|||||||
font-family: 'Quicksand', sans-serif;
|
font-family: 'Quicksand', sans-serif;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
html{
|
||||||
|
scroll-behavior: smooth;
|
||||||
|
}
|
||||||
|
|
||||||
@keyframes logo-spin {
|
@keyframes logo-spin {
|
||||||
from {
|
from {
|
||||||
transform: rotate(0deg);
|
transform: rotate(0deg);
|
||||||
|
@ -16,7 +16,9 @@ const prompts = [
|
|||||||
"What can you help me with?",
|
"What can you help me with?",
|
||||||
"What is MCP?",
|
"What is MCP?",
|
||||||
"Who is this for?",
|
"Who is this for?",
|
||||||
"Show me how I can earn"
|
"Show me how I can earn",
|
||||||
|
"Developers",
|
||||||
|
"Sample MCPs"
|
||||||
];
|
];
|
||||||
|
|
||||||
const ChatInterface: React.FC<ChatInterfaceProps> = ({ onPromptSelect, isExpanded }) => {
|
const ChatInterface: React.FC<ChatInterfaceProps> = ({ onPromptSelect, isExpanded }) => {
|
||||||
@ -24,29 +26,110 @@ const ChatInterface: React.FC<ChatInterfaceProps> = ({ onPromptSelect, isExpande
|
|||||||
const [inputValue, setInputValue] = useState('');
|
const [inputValue, setInputValue] = useState('');
|
||||||
const [isThinking, setIsThinking] = useState(false);
|
const [isThinking, setIsThinking] = useState(false);
|
||||||
const [chatKey, setChatKey] = useState(0);
|
const [chatKey, setChatKey] = useState(0);
|
||||||
|
const [thinkingStage, setThinkingStage] = useState<"thinking" | "memory" | null>(null);
|
||||||
const scrollAnchorRef = useRef<HTMLDivElement | null>(null);
|
const scrollAnchorRef = useRef<HTMLDivElement | null>(null);
|
||||||
|
|
||||||
const handlePromptClick = (prompt: string) => {
|
const promptPatterns = [
|
||||||
setMessages(prev => [...prev, { text: prompt, isUser: true }]);
|
{
|
||||||
|
pattern: /(how|what).*?(help|useful|do|job|use\s+you\s+for|offer|can\s+you\s+do)/i,
|
||||||
|
prompt: "What can you help me with?",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
pattern: /(what('| i)?s|define|explain|tell\s+me\s+about).*\b(mcp)\b/i,
|
||||||
|
prompt: "What is MCP?",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
pattern: /(who|whom).*?(for|use\s+this|is\s+this\s+platform\s+for|can\s+use)/i,
|
||||||
|
prompt: "Who is this for?",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
pattern: /(how|what|can\s+i|is\s+there).*?(earn|moneti[sz]e|money|income|revenue|make\s+money)/i,
|
||||||
|
prompt: "Show me how I can earn",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
pattern: /(dev|developers|developed|people)/i,
|
||||||
|
prompt: "Developers",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
pattern: /\b(sample|example|show|some)\b.*\b(mcp|mcp server|mcp servers|mcps)\b|\b(mcp|mcp server|mcp servers|mcps)\b.*\b(sample|example|show|some)\b/i,
|
||||||
|
prompt: "Sample MCPs",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
|
const promptResponses: Record<string, string> = {
|
||||||
|
"What can you help me with?": "I can assist you with understanding MCP, exploring features, and showing you how to earn with MCP. Let me show you in a detailed view.",
|
||||||
|
"What is MCP?": "MCP stands for Monetizable Code Package. It's a wrapper on an API that works with LLMs, making AI behaviors easy to deploy and monetize. Would you like to see it in a detailed view on the right?",
|
||||||
|
"Who is this for?": "MCP is for developers, creators, and businesses who want to build, deploy, and monetize AI-powered code packages easily. Here's a detailed view.",
|
||||||
|
"Show me how I can earn": "You can earn by creating MCPs, deploying them, and setting your pricing. Track usage and get paid automatically as others use your MCPs. I have generated a detailed view on the right.",
|
||||||
|
"Developers": "A lot of people have put there thoughts and ideas to bring this amazing idea to life. Here on the right I have displayed all the developers who are behind Fastcode.",
|
||||||
|
"Sample MCPs": "People all over the world are building MCP servers and earning passively. It's time you start you own as well. Here are some samples for your inspiration."
|
||||||
|
};
|
||||||
|
|
||||||
|
const handlePromptClick = (prompt: string, userInput?: string) => {
|
||||||
|
setMessages(prev => [...prev, { text: userInput || prompt, isUser: true }]);
|
||||||
|
setThinkingStage("thinking");
|
||||||
setIsThinking(true);
|
setIsThinking(true);
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
setThinkingStage("memory");
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
setIsThinking(false);
|
setIsThinking(false);
|
||||||
setMessages(prev => [...prev, { text: `Let me show you detailed information about "${prompt}"`, isUser: false, isTyping: true }]);
|
setThinkingStage(null);
|
||||||
|
setMessages(prev => [
|
||||||
|
...prev,
|
||||||
|
{
|
||||||
|
text: promptResponses[prompt] || `Let me show you detailed information about "${prompt}"`,
|
||||||
|
isUser: false,
|
||||||
|
isTyping: true,
|
||||||
|
},
|
||||||
|
]);
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
const content = getPromptContent(prompt);
|
const content = getPromptContent(prompt);
|
||||||
onPromptSelect(prompt, content);
|
onPromptSelect(prompt, content);
|
||||||
}, 1500);
|
}, 9000);
|
||||||
}, 1000);
|
}, 1000); // "Activating memory..." duration
|
||||||
|
}, 1000); // "Thinking..." duration
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleSendMessage = () => {
|
const handleSendMessage = () => {
|
||||||
if (!inputValue.trim()) return;
|
if (!inputValue.trim()) return;
|
||||||
const prompt = inputValue;
|
|
||||||
setInputValue('');
|
const userMessage = {
|
||||||
handlePromptClick(prompt);
|
text: inputValue,
|
||||||
|
isUser: true,
|
||||||
};
|
};
|
||||||
|
setMessages(prev => [...prev, userMessage]);
|
||||||
|
|
||||||
|
const matched = promptPatterns.find(({ pattern }) => pattern.test(inputValue));
|
||||||
|
const promptToUse = matched ? matched.prompt : inputValue;
|
||||||
|
|
||||||
|
setInputValue('');
|
||||||
|
setThinkingStage("thinking");
|
||||||
|
setIsThinking(true);
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
setThinkingStage("memory");
|
||||||
|
setTimeout(() => {
|
||||||
|
setIsThinking(false);
|
||||||
|
setThinkingStage(null);
|
||||||
|
setMessages(prev => [
|
||||||
|
...prev,
|
||||||
|
{
|
||||||
|
text: promptResponses[promptToUse] || `Let me show you detailed information about "${promptToUse}"`,
|
||||||
|
isUser: false,
|
||||||
|
isTyping: true,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
setTimeout(() => {
|
||||||
|
const content = getPromptContent(promptToUse);
|
||||||
|
onPromptSelect(promptToUse, content);
|
||||||
|
}, 9000);
|
||||||
|
}, 1000);
|
||||||
|
}, 1000);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const handleKeyPress = (e: React.KeyboardEvent) => {
|
const handleKeyPress = (e: React.KeyboardEvent) => {
|
||||||
if (e.key === 'Enter') handleSendMessage();
|
if (e.key === 'Enter') handleSendMessage();
|
||||||
@ -64,13 +147,11 @@ const ChatInterface: React.FC<ChatInterfaceProps> = ({ onPromptSelect, isExpande
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (scrollAnchorRef.current) {
|
scrollAnchorRef.current?.scrollIntoView({ behavior: 'smooth', block:'end' });
|
||||||
scrollAnchorRef.current.scrollIntoView({ behavior: 'smooth', block: 'end' });
|
}, [messages]);
|
||||||
}
|
|
||||||
}, [messages, isThinking]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col h-screen max-h-screen overflow-hidden p-6">
|
<div id='chat' className="flex flex-col h-screen max-h-screen overflow-hidden p-6">
|
||||||
{/* Hero Section */}
|
{/* Hero Section */}
|
||||||
{messages.length === 0 && (
|
{messages.length === 0 && (
|
||||||
<div className={`flex-1 flex flex-col justify-center items-center text-center transition-all duration-500 ${
|
<div className={`flex-1 flex flex-col justify-center items-center text-center transition-all duration-500 ${
|
||||||
@ -89,7 +170,7 @@ const ChatInterface: React.FC<ChatInterfaceProps> = ({ onPromptSelect, isExpande
|
|||||||
How can I help you today?
|
How can I help you today?
|
||||||
</h3>
|
</h3>
|
||||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-3">
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-3">
|
||||||
{prompts.map((prompt, index) => (
|
{prompts.slice(0, 4).map((prompt, index) => (
|
||||||
<Button
|
<Button
|
||||||
key={index}
|
key={index}
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
@ -108,7 +189,7 @@ const ChatInterface: React.FC<ChatInterfaceProps> = ({ onPromptSelect, isExpande
|
|||||||
{messages.length > 0 && (
|
{messages.length > 0 && (
|
||||||
<div className="flex-1 w-full md:w-1/2 mx-auto mb-6 overflow-hidden">
|
<div className="flex-1 w-full md:w-1/2 mx-auto mb-6 overflow-hidden">
|
||||||
<div
|
<div
|
||||||
className="h-full overflow-y-auto space-y-4 scrollbar-hide pr-2"
|
className="h-fit overflow-y-auto space-y-4 scrollbar-hide pr-2"
|
||||||
ref={scrollAnchorRef}
|
ref={scrollAnchorRef}
|
||||||
>
|
>
|
||||||
{messages.map((message, index) => (
|
{messages.map((message, index) => (
|
||||||
@ -131,6 +212,14 @@ const ChatInterface: React.FC<ChatInterfaceProps> = ({ onPromptSelect, isExpande
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
|
{/* Status Label */}
|
||||||
|
{thinkingStage && (
|
||||||
|
<div className="w-full md:w-1/2 mr-auto flex justify-start mb-2 z-30">
|
||||||
|
<div className="px-4 py-1 rounded-full bg-gray-900/80 dark:bg-gray-100/80 text-white dark:text-gray-900 text-xs font-semibold shadow transition-all duration-300">
|
||||||
|
{thinkingStage === "thinking" ? "Thinking..." : "Activating memory..."}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
{isThinking && (
|
{isThinking && (
|
||||||
<div className="flex justify-start">
|
<div className="flex justify-start">
|
||||||
<div className="max-w-xs lg:max-w-md px-4 py-3 rounded-2xl border border-gray-200/20 dark:border-gray-700/20 backdrop-blur-xl bg-white/10 dark:bg-black/10 text-gray-900 dark:text-white">
|
<div className="max-w-xs lg:max-w-md px-4 py-3 rounded-2xl border border-gray-200/20 dark:border-gray-700/20 backdrop-blur-xl bg-white/10 dark:bg-black/10 text-gray-900 dark:text-white">
|
||||||
@ -157,13 +246,18 @@ const ChatInterface: React.FC<ChatInterfaceProps> = ({ onPromptSelect, isExpande
|
|||||||
<Input
|
<Input
|
||||||
value={inputValue}
|
value={inputValue}
|
||||||
onChange={(e) => setInputValue(e.target.value)}
|
onChange={(e) => setInputValue(e.target.value)}
|
||||||
onKeyDown={handleKeyPress}
|
onKeyUp={(e) => {
|
||||||
|
if (e.key === 'Enter' && inputValue.trim()) {
|
||||||
|
e.preventDefault();
|
||||||
|
handleSendMessage();
|
||||||
|
}
|
||||||
|
}}
|
||||||
placeholder="Ask me anything about MCP..."
|
placeholder="Ask me anything about MCP..."
|
||||||
className="border-0 bg-transparent focus:outline-none focus:ring-0 text-gray-900 dark:text-white placeholder-gray-500 dark:placeholder-gray-400"
|
className="border-0 bg-transparent focus:outline-none focus:ring-0 text-gray-900 dark:text-white placeholder-gray-500 dark:placeholder-gray-400"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{/* Second Line: Dropdown + Upload + Send */}
|
{/* Second Line: Dropdown + Upload + Send */}
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between pointer-events-auto">
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
{/* Dropdown */}
|
{/* Dropdown */}
|
||||||
<Select>
|
<Select>
|
||||||
@ -200,6 +294,7 @@ const ChatInterface: React.FC<ChatInterfaceProps> = ({ onPromptSelect, isExpande
|
|||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
// ...existing code...
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -4,7 +4,7 @@ import { ArrowRight, Play, MessageSquare, Zap, Sparkles } from "lucide-react"
|
|||||||
|
|
||||||
const HeroSection = () => {
|
const HeroSection = () => {
|
||||||
return (
|
return (
|
||||||
<section id="hero" className="relative h-screen flex items-center justify-center overflow-hidden hero-gradient grain">
|
<section id="home" className="relative h-screen flex items-center justify-center overflow-hidden hero-gradient grain">
|
||||||
{/* Background grid */}
|
{/* Background grid */}
|
||||||
<div className="absolute inset-0 grid-glow opacity-30"></div>
|
<div className="absolute inset-0 grid-glow opacity-30"></div>
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@ import React, { useRef, useEffect } from 'react';
|
|||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
import { useTheme } from '../contexts/ThemeContext';
|
import { useTheme } from '../contexts/ThemeContext';
|
||||||
import { FiMenu, FiX, FiHelpCircle, FiUsers, FiDollarSign, FiZap, FiExternalLink, FiMoon, FiSun } from 'react-icons/fi';
|
import { FiMenu, FiX, FiHelpCircle, FiUsers, FiDollarSign, FiZap, FiExternalLink, FiMoon, FiSun } from 'react-icons/fi';
|
||||||
|
import { TbMessageChatbot } from "react-icons/tb";
|
||||||
import { LucideCodeXml } from 'lucide-react';
|
import { LucideCodeXml } from 'lucide-react';
|
||||||
import { useNavigate } from "react-router-dom";
|
import { useNavigate } from "react-router-dom";
|
||||||
|
|
||||||
@ -18,6 +19,7 @@ const suggestedQuestions = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
const navLinks = [
|
const navLinks = [
|
||||||
|
{ text: "Chat", icon: TbMessageChatbot , to: "#" },
|
||||||
{ text: "Home", icon: FiHelpCircle, to: "#home" },
|
{ text: "Home", icon: FiHelpCircle, to: "#home" },
|
||||||
{ text: "MCPs", icon: FiUsers, to: "#mcps" },
|
{ text: "MCPs", icon: FiUsers, to: "#mcps" },
|
||||||
{ text: "Monetize", icon: FiDollarSign, to: "#monetize" },
|
{ text: "Monetize", icon: FiDollarSign, to: "#monetize" },
|
||||||
@ -96,28 +98,8 @@ const LeftSidebar: React.FC<LeftSidebarProps> = ({ onPromptSelect, onStartNewCha
|
|||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Nav menu */}
|
{/* Questions */}
|
||||||
{/* <div className="px-6">
|
<div className="px-6 mb-6">
|
||||||
<h3 className="text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider mb-4 mt-4">
|
|
||||||
Navigation
|
|
||||||
</h3>
|
|
||||||
{navLinks.map((nav, index) => (
|
|
||||||
<button
|
|
||||||
key={index}
|
|
||||||
onClick={() => navigate(nav.to)}
|
|
||||||
className="w-full flex justify-start p-4 h-auto text-left border-0 bg-transparent text-gray-500 hover:text-black transition-colors duration-200 group"
|
|
||||||
>
|
|
||||||
<nav.icon className="w-4 h-4 mr-3 text-gray-400 group-hover:text-black dark:group-hover:text-white transition-colors" />
|
|
||||||
<span className="text-sm text-gray-500 dark:text-gray-400 group-hover:text-black dark:group-hover:text-white transition-colors">
|
|
||||||
{nav.text}
|
|
||||||
</span>
|
|
||||||
</button>
|
|
||||||
))}
|
|
||||||
</div> */}
|
|
||||||
|
|
||||||
{/* Main Section: Suggested Questions & Start New Chat */}
|
|
||||||
<div className="flex-1 flex flex-col justify-between">
|
|
||||||
<div className="px-6">
|
|
||||||
<h3 className="text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider mb-4 mt-4">
|
<h3 className="text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider mb-4 mt-4">
|
||||||
Quick Start
|
Quick Start
|
||||||
</h3>
|
</h3>
|
||||||
@ -138,13 +120,35 @@ const LeftSidebar: React.FC<LeftSidebarProps> = ({ onPromptSelect, onStartNewCha
|
|||||||
{/* Start New Chat Button */}
|
{/* Start New Chat Button */}
|
||||||
<Button
|
<Button
|
||||||
variant="outline"
|
variant="outline"
|
||||||
className="w-full mt-6"
|
className="w-full"
|
||||||
onClick={onStartNewChat}
|
onClick={onStartNewChat}
|
||||||
>
|
>
|
||||||
Start New Chat
|
Start New Chat
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
{/* Bottom Section: Visit Website */}
|
|
||||||
|
{/* Nav Section */}
|
||||||
|
<div className="flex-1 flex flex-col justify-between">
|
||||||
|
{/* Nav menu */}
|
||||||
|
<div className="px-6">
|
||||||
|
<h3 className="text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider mb-4 mt-4">
|
||||||
|
Navigation
|
||||||
|
</h3>
|
||||||
|
{navLinks.map((nav, index) => (
|
||||||
|
<a
|
||||||
|
href={nav.to}
|
||||||
|
key={index}
|
||||||
|
className="w-full flex justify-start p-4 h-auto text-left border-0 bg-transparent text-gray-500 hover:text-black transition-colors duration-200 group"
|
||||||
|
>
|
||||||
|
<nav.icon className="w-4 h-4 mr-3 text-gray-400 group-hover:text-black dark:group-hover:text-white transition-colors" />
|
||||||
|
<span className="text-sm text-gray-500 dark:text-gray-400 group-hover:text-black dark:group-hover:text-white transition-colors">
|
||||||
|
{nav.text}
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Visit Website */}
|
||||||
<div className="p-6 mt-auto">
|
<div className="p-6 mt-auto">
|
||||||
<h3 className="text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider mb-4">
|
<h3 className="text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider mb-4">
|
||||||
Resources
|
Resources
|
||||||
|
@ -3,7 +3,7 @@ import { Code, Cpu, DollarSign, Zap, ArrowRight, Box } from "lucide-react"
|
|||||||
|
|
||||||
const MCPSection = () => {
|
const MCPSection = () => {
|
||||||
return (
|
return (
|
||||||
<section id="mcps" className="relative flex mt-10 items-center justify-center overflow-hidden hero-gradient bg-transparent grain">
|
<section id="mcps" className="relative h-full pt-20 flex mt-10 items-center justify-center overflow-hidden hero-gradient bg-transparent grain">
|
||||||
|
|
||||||
<div className="relative z-10 max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
<div className="relative z-10 max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||||
<div className="text-center mb-16">
|
<div className="text-center mb-16">
|
||||||
|
84
src/components/content/Developers.tsx
Normal file
84
src/components/content/Developers.tsx
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { FiGithub, FiLinkedin, FiMail } from 'react-icons/fi';
|
||||||
|
|
||||||
|
const developers = [
|
||||||
|
{
|
||||||
|
name: "Ben Johnson",
|
||||||
|
role: "Founder & Lead Engineer",
|
||||||
|
github: "https://github.com/bjohnson-dev",
|
||||||
|
linkedin: "https://linkedin.com/in/benjohnson-dev",
|
||||||
|
email: "mailto:benn@fastcode.ai",
|
||||||
|
avatar: "https://randomuser.me/api/portraits/men/32.jpg"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Cayla Hawkins",
|
||||||
|
role: "Full Stack Developer",
|
||||||
|
github: "https://github.com/caylacodes",
|
||||||
|
linkedin: "https://linkedin.com/in/caylahawkins",
|
||||||
|
email: "mailto:cayla@fastcode.ai",
|
||||||
|
avatar: "https://randomuser.me/api/portraits/women/66.jpg"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Toby Schmidt",
|
||||||
|
role: "AI/ML Engineer",
|
||||||
|
github: "https://github.com/tobeyy",
|
||||||
|
linkedin: "https://linkedin.com/in/schmidttoby",
|
||||||
|
email: "mailto:toby@fastcode.ai",
|
||||||
|
avatar: "https://randomuser.me/api/portraits/men/78.jpg"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Sara Lee",
|
||||||
|
role: "Frontend Developer",
|
||||||
|
github: "https://github.com/saralee",
|
||||||
|
linkedin: "https://linkedin.com/in/saralee",
|
||||||
|
email: "mailto:sara@fastcode.ai",
|
||||||
|
avatar: "https://randomuser.me/api/portraits/women/60.jpg"
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
const Developers = () => {
|
||||||
|
return (
|
||||||
|
<div className="space-y-8">
|
||||||
|
<div className="space-y-4">
|
||||||
|
<h3 className="text-xl font-semibold text-gray-900 dark:text-white">
|
||||||
|
Meet the Developers Behind Fastcode
|
||||||
|
</h3>
|
||||||
|
<p className="text-gray-600 dark:text-gray-300 leading-relaxed">
|
||||||
|
The Fastcode platform is built and maintained by a passionate team of engineers and creators.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="grid gap-6 md:grid-cols-2">
|
||||||
|
{developers.map((dev) => (
|
||||||
|
<div
|
||||||
|
key={dev.email}
|
||||||
|
className="flex items-center gap-5 p-6 rounded-2xl border border-gray-200/20 dark:border-gray-700/20 backdrop-blur-sm bg-white/5 dark:bg-black/5 hover:scale-105 transition-all duration-300"
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
src={dev.avatar}
|
||||||
|
alt={dev.name}
|
||||||
|
className="w-16 h-16 rounded-full object-cover border-2 border-gray-300 dark:border-gray-700"
|
||||||
|
/>
|
||||||
|
<div className="flex-1">
|
||||||
|
<h4 className="font-medium text-gray-900 dark:text-white">{dev.name}</h4>
|
||||||
|
<div className="text-sm text-gray-600 dark:text-gray-300 mb-2">{dev.role}</div>
|
||||||
|
<div className="flex gap-3">
|
||||||
|
<a href={dev.github} target="_blank" rel="noopener noreferrer" aria-label="GitHub">
|
||||||
|
<FiGithub className="w-5 h-5 text-gray-700 dark:text-gray-300 hover:text-black dark:hover:text-white" />
|
||||||
|
</a>
|
||||||
|
<a href={dev.linkedin} target="_blank" rel="noopener noreferrer" aria-label="LinkedIn">
|
||||||
|
<FiLinkedin className="w-5 h-5 text-blue-700 dark:text-blue-400 hover:text-blue-900" />
|
||||||
|
</a>
|
||||||
|
<a href={dev.email} aria-label="Email">
|
||||||
|
<FiMail className="w-5 h-5 text-gray-700 dark:text-gray-300 hover:text-black dark:hover:text-white" />
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Developers;
|
71
src/components/content/SampleMCPs.tsx
Normal file
71
src/components/content/SampleMCPs.tsx
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { FiServer, FiZap, FiDollarSign, FiUsers } from 'react-icons/fi';
|
||||||
|
|
||||||
|
const mcps = [
|
||||||
|
{
|
||||||
|
name: "Image Captioning MCP",
|
||||||
|
description: "Generate accurate captions for images using state-of-the-art AI models.",
|
||||||
|
features: ["Accepts image uploads", "Returns natural language captions", "Supports multiple languages"],
|
||||||
|
icon: <FiServer className="w-6 h-6 text-blue-500" />,
|
||||||
|
author: "Ben Johnson"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Sentiment Analysis MCP",
|
||||||
|
description: "Analyze the sentiment of any text and get instant feedback.",
|
||||||
|
features: ["Real-time analysis", "Positive/Negative/Neutral output", "API & UI integration"],
|
||||||
|
icon: <FiZap className="w-6 h-6 text-yellow-500" />,
|
||||||
|
author: "Cayla Hawkins"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Text-to-Speech MCP",
|
||||||
|
description: "Convert written text into realistic speech audio.",
|
||||||
|
features: ["Multiple voices", "Fast response", "Downloadable MP3"],
|
||||||
|
icon: <FiUsers className="w-6 h-6 text-purple-500" />,
|
||||||
|
author: "Toby Shmidt"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Paywall API MCP",
|
||||||
|
description: "Easily monetize your APIs with built-in paywall and analytics.",
|
||||||
|
features: ["Stripe integration", "Usage analytics", "Custom pricing"],
|
||||||
|
icon: <FiDollarSign className="w-6 h-6 text-green-500" />,
|
||||||
|
author: "Sara Lee"
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
const SampleMCPs = () => {
|
||||||
|
return (
|
||||||
|
<div className="space-y-8">
|
||||||
|
<div className="space-y-4">
|
||||||
|
<h3 className="text-xl font-semibold text-gray-900 dark:text-white">
|
||||||
|
Sample MCP Servers
|
||||||
|
</h3>
|
||||||
|
<p className="text-gray-600 dark:text-gray-300 leading-relaxed">
|
||||||
|
Explore a few example MCPs you can build, deploy, and monetize on the Fastcode platform.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="grid gap-6 md:grid-cols-2">
|
||||||
|
{mcps.map((mcp) => (
|
||||||
|
<div
|
||||||
|
key={mcp.name}
|
||||||
|
className="flex flex-col gap-3 p-6 rounded-2xl border border-gray-200/20 dark:border-gray-700/20 backdrop-blur-sm bg-white/5 dark:bg-black/5 hover:scale-105 transition-all duration-300"
|
||||||
|
>
|
||||||
|
<div className="flex items-center gap-3">
|
||||||
|
{mcp.icon}
|
||||||
|
<h4 className="font-medium text-gray-900 dark:text-white">{mcp.name}</h4>
|
||||||
|
</div>
|
||||||
|
<div className="text-sm text-gray-600 dark:text-gray-300">{mcp.description}</div>
|
||||||
|
<ul className="list-disc list-inside text-xs text-gray-500 dark:text-gray-400 pl-2">
|
||||||
|
{mcp.features.map((feature, i) => (
|
||||||
|
<li key={i}>{feature}</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
<div className="text-xs text-gray-400 dark:text-gray-500 mt-2">By {mcp.author}</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default SampleMCPs;
|
@ -5,7 +5,7 @@ import SidebarPanel from '../components/SidebarPanel';
|
|||||||
import LeftSidebar from '../components/LeftSidebar';
|
import LeftSidebar from '../components/LeftSidebar';
|
||||||
import { ThemeProvider } from '../contexts/ThemeContext';
|
import { ThemeProvider } from '../contexts/ThemeContext';
|
||||||
import { getPromptContent } from '../utils/promptContent';
|
import { getPromptContent } from '../utils/promptContent';
|
||||||
import { FiInfo } from 'react-icons/fi'; // Add this import
|
import { FiInfo } from 'react-icons/fi';
|
||||||
import HeroSection from '@/components/HeroSection';
|
import HeroSection from '@/components/HeroSection';
|
||||||
import MCPSection from '@/components/MCPSection';
|
import MCPSection from '@/components/MCPSection';
|
||||||
import MonetizeSection from '@/components/MonetizeSection';
|
import MonetizeSection from '@/components/MonetizeSection';
|
||||||
@ -16,14 +16,13 @@ const Index = () => {
|
|||||||
const [chatKey, setChatKey] = useState(0);
|
const [chatKey, setChatKey] = useState(0);
|
||||||
|
|
||||||
const handleStartNewChat = () => {
|
const handleStartNewChat = () => {
|
||||||
setChatKey(prev => prev + 1); // This will remount ChatInterface and reset its state
|
setChatKey(prev => prev + 1);
|
||||||
setSelectedPrompt(null);
|
setSelectedPrompt(null);
|
||||||
setSidebarContent(null);
|
setSidebarContent(null);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handlePromptSelect = (prompt: string, content?: any) => {
|
const handlePromptSelect = (prompt: string, content?: any) => {
|
||||||
setSelectedPrompt(prompt);
|
setSelectedPrompt(prompt);
|
||||||
// Get content if not provided (for left sidebar clicks)
|
|
||||||
const promptContent = content || getPromptContent(prompt);
|
const promptContent = content || getPromptContent(prompt);
|
||||||
setSidebarContent(promptContent);
|
setSidebarContent(promptContent);
|
||||||
};
|
};
|
||||||
@ -33,7 +32,6 @@ const Index = () => {
|
|||||||
setSidebarContent(null);
|
setSidebarContent(null);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Add a default info content if needed
|
|
||||||
const defaultInfoContent = {
|
const defaultInfoContent = {
|
||||||
title: "Chatbot Side Panel",
|
title: "Chatbot Side Panel",
|
||||||
description: "Welcome to MCP Verse Spark! Here you can chat with our AI, explore features, and learn more about MCP."
|
description: "Welcome to MCP Verse Spark! Here you can chat with our AI, explore features, and learn more about MCP."
|
||||||
@ -41,24 +39,23 @@ const Index = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<ThemeProvider>
|
<ThemeProvider>
|
||||||
<div className="bg-gradient-to-br from-white via-gray-50 to-gray-100 dark:from-black dark:via-black dark:to-black transition-all duration-500">
|
<div className="relative bg-gradient-to-br from-white via-gray-50 to-gray-100 dark:from-black dark:via-black dark:to-black transition-all duration-500">
|
||||||
{/* <Header /> */}
|
{/* Chat Interface: fixed, behind everything else */}
|
||||||
|
<div className="fixed inset-0 z-10">
|
||||||
{/* CHAT INTERFACE */}
|
<div className="flex h-full">
|
||||||
<div className="flex h-[calc(100vh-80px)] relative">
|
<div className="flex-1 flex flex-col">
|
||||||
{/* Left Sidebar */}
|
|
||||||
<LeftSidebar onPromptSelect={handlePromptSelect} onStartNewChat={handleStartNewChat} />
|
|
||||||
|
|
||||||
{/* Main Chat Interface */}
|
|
||||||
<div className={`transition-all duration-500 ease-in-out ${
|
|
||||||
selectedPrompt ? 'w-1/2 ml-0' : 'w-full ml-0'
|
|
||||||
}`}>
|
|
||||||
<ChatInterface
|
<ChatInterface
|
||||||
key={chatKey} // Add key to force remount on new chat
|
key={chatKey}
|
||||||
onPromptSelect={handlePromptSelect}
|
onPromptSelect={handlePromptSelect}
|
||||||
isExpanded={!selectedPrompt}
|
isExpanded={!selectedPrompt}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Left Sidebar and Sidebar Panel (z-20) */}
|
||||||
|
<div className="relative z-20">
|
||||||
|
<LeftSidebar onPromptSelect={handlePromptSelect} onStartNewChat={handleStartNewChat} />
|
||||||
|
|
||||||
{/* Sidebar Open Icon */}
|
{/* Sidebar Open Icon */}
|
||||||
{!selectedPrompt && (
|
{!selectedPrompt && (
|
||||||
@ -71,7 +68,6 @@ const Index = () => {
|
|||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Right Sliding Sidebar Panel */}
|
|
||||||
<SidebarPanel
|
<SidebarPanel
|
||||||
isOpen={!!selectedPrompt}
|
isOpen={!!selectedPrompt}
|
||||||
content={sidebarContent}
|
content={sidebarContent}
|
||||||
@ -79,40 +75,38 @@ const Index = () => {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Subtle light leaks */}
|
<div className='h-screen z-0'></div>
|
||||||
{/* <div className="fixed inset-0 pointer-events-none overflow-hidden">
|
|
||||||
<div className="absolute -top-1/2 -right-1/2 w-full h-full bg-gradient-radial from-blue-500/5 via-transparent to-transparent dark:from-blue-400/10"></div>
|
|
||||||
<div className="absolute -bottom-1/2 -left-1/2 w-full h-full bg-gradient-radial from-purple-500/5 via-transparent to-transparent dark:from-purple-400/10"></div>
|
|
||||||
</div> */}
|
|
||||||
|
|
||||||
{/* Authentic light leaks with warmth and blur */}
|
{/* Main Content Sections glide over the chat */}
|
||||||
{/* <div className="fixed inset-0 pointer-events-none overflow-hidden z-0">
|
<div className="relative z-10 bg-white dark:bg-black">
|
||||||
<div className="absolute top-[10%] left-[5%] w-[300px] h-[300px] bg-red-400 opacity-20 rounded-full mix-blend-screen blur-3xl animate-pulse-slow" />
|
<HeroSection />
|
||||||
<div className="absolute bottom-[15%] right-[10%] w-[250px] h-[250px] bg-yellow-300 opacity-15 rounded-full mix-blend-screen blur-2xl animate-pulse-slower" />
|
<MCPSection />
|
||||||
<div className="absolute top-[30%] right-[20%] w-[200px] h-[200px] bg-pink-400 opacity-10 rounded-full mix-blend-screen blur-3xl animate-pulse" />
|
<MonetizeSection />
|
||||||
<div className="absolute bottom-[20%] left-[25%] w-[280px] h-[280px] bg-orange-300 opacity-20 rounded-full mix-blend-screen blur-2xl animate-pulse" />
|
|
||||||
</div> */}
|
|
||||||
|
|
||||||
{/* Realistic Film Camera Light Leaks */}
|
{/* Realistic Film Camera Light Leaks */}
|
||||||
<div className="fixed inset-0 pointer-events-none overflow-hidden z-0">
|
<div className="fixed inset-0 pointer-events-none overflow-hidden z-0">
|
||||||
{/* Horizontal streak from left */}
|
{/* Horizontal streak from left */}
|
||||||
<div className="absolute left-0 top-1/4 w-[600px] h-[200px] bg-gradient-to-r from-red-400/30 via-orange-300/20 to-transparent blur-3xl rotate-[-5deg] skew-y-6 mix-blend-screen" />
|
<div className="absolute left-0 top-1/4 w-[600px] h-[200px] bg-gradient-to-r from-red-400/30 via-orange-300/20 to-transparent blur-3xl rotate-[-5deg] skew-y-6 mix-blend-screen" />
|
||||||
|
|
||||||
{/* Vertical burn from bottom */}
|
{/* Vertical burn from bottom */}
|
||||||
<div className="absolute bottom-0 left-1/3 w-[300px] h-[580px] bg-gradient-to-t from-yellow-300/20 via-pink-400/10 to-transparent blur-3xl rotate-12 mix-blend-screen" />
|
<div className="absolute bottom-0 left-1/3 w-[300px] h-[580px] bg-gradient-to-t from-yellow-300/20 via-pink-400/10 to-transparent blur-3xl rotate-12 mix-blend-screen" />
|
||||||
|
|
||||||
{/* Angled streak from top right */}
|
{/* Angled streak from top right */}
|
||||||
<div className="absolute top-0 right-0 w-[400px] h-[300px] bg-gradient-to-bl from-red-500/20 via-orange-300/10 to-transparent blur-2xl -rotate-12 mix-blend-screen" />
|
<div className="absolute top-0 right-0 w-[400px] h-[300px] bg-gradient-to-bl from-red-500/20 via-orange-300/10 to-transparent blur-2xl -rotate-12 mix-blend-screen" />
|
||||||
|
|
||||||
{/* Blobby irregular light spot */}
|
{/* Blobby irregular light spot */}
|
||||||
<div className="absolute bottom-[10%] right-[20%] w-[350px] h-[250px] bg-pink-300/15 rounded-3xl blur-[100px] rotate-[18deg] mix-blend-screen" />
|
<div className="absolute bottom-[10%] right-[20%] w-[350px] h-[250px] bg-pink-300/15 rounded-3xl blur-[100px] rotate-[18deg] mix-blend-screen" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Realistic Film Camera Light Leaks */}
|
||||||
<HeroSection />
|
<div className="fixed inset-0 pointer-events-none overflow-hidden z-0">
|
||||||
<MCPSection />
|
{/* Horizontal streak from left */}
|
||||||
<MonetizeSection />
|
<div className="absolute left-0 top-1/4 w-[600px] h-[200px] bg-gradient-to-r from-red-400/30 via-orange-300/20 to-transparent blur-3xl rotate-[-5deg] skew-y-6 mix-blend-screen" />
|
||||||
|
{/* Vertical burn from bottom */}
|
||||||
|
<div className="absolute bottom-0 left-1/3 w-[300px] h-[580px] bg-gradient-to-t from-yellow-300/20 via-pink-400/10 to-transparent blur-3xl rotate-12 mix-blend-screen" />
|
||||||
|
{/* Angled streak from top right */}
|
||||||
|
<div className="absolute top-0 right-0 w-[400px] h-[300px] bg-gradient-to-bl from-red-500/20 via-orange-300/10 to-transparent blur-2xl -rotate-12 mix-blend-screen" />
|
||||||
|
{/* Blobby irregular light spot */}
|
||||||
|
<div className="absolute bottom-[10%] right-[20%] w-[350px] h-[250px] bg-pink-300/15 rounded-3xl blur-[100px] rotate-[18deg] mix-blend-screen" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</ThemeProvider>
|
</ThemeProvider>
|
||||||
);
|
);
|
||||||
|
@ -4,6 +4,8 @@ import WhatIsMCPContent from '../components/content/WhatIsMCPContent';
|
|||||||
import WhoIsThisForContent from '../components/content/WhoIsThisForContent';
|
import WhoIsThisForContent from '../components/content/WhoIsThisForContent';
|
||||||
import HowToEarnContent from '../components/content/HowToEarnContent';
|
import HowToEarnContent from '../components/content/HowToEarnContent';
|
||||||
import WhatCanHelpContent from '../components/content/WhatCanHelpContent';
|
import WhatCanHelpContent from '../components/content/WhatCanHelpContent';
|
||||||
|
import Developers from '@/components/content/Developers';
|
||||||
|
import SampleMCPs from '@/components/content/SampleMCPs';
|
||||||
|
|
||||||
export const getPromptContent = (prompt: string) => {
|
export const getPromptContent = (prompt: string) => {
|
||||||
switch (prompt) {
|
switch (prompt) {
|
||||||
@ -27,6 +29,16 @@ export const getPromptContent = (prompt: string) => {
|
|||||||
title: "Platform Features",
|
title: "Platform Features",
|
||||||
component: <WhatCanHelpContent />
|
component: <WhatCanHelpContent />
|
||||||
};
|
};
|
||||||
|
case "Developers":
|
||||||
|
return {
|
||||||
|
title: "Developers",
|
||||||
|
component: <Developers />
|
||||||
|
};
|
||||||
|
case "Sample MCPs":
|
||||||
|
return {
|
||||||
|
title: "Sample MCP Servers",
|
||||||
|
component: <SampleMCPs />
|
||||||
|
};
|
||||||
default:
|
default:
|
||||||
return {
|
return {
|
||||||
title: "Information",
|
title: "Information",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user