diff --git a/.github/workflows/deploy-manual.yml b/.github/workflows/deploy-manual.yml new file mode 100644 index 00000000..f0899507 --- /dev/null +++ b/.github/workflows/deploy-manual.yml @@ -0,0 +1,31 @@ +name: Deploy to Server + +run-name: Deploy ${{ github.sha }} + +on: + workflow_dispatch: + +jobs: + deploy: + runs-on: ubuntu-latest + environment: production + steps: + - name: Deploy via SSH + uses: appleboy/ssh-action@v1.2.0 + with: + host: ${{ secrets.SSH_HOST }} + username: ${{ secrets.SSH_USER }} + key: ${{ secrets.SSH_PRIVATE_KEY }} + port: ${{ secrets.SSH_PORT || 22 }} + script: | + cd ~/sphere + echo "=== Previous commit ===" + git rev-parse HEAD + git rev-parse --short HEAD + git pull origin main + echo "=== Current commit ===" + git rev-parse HEAD + git rev-parse --short HEAD + docker compose build + docker compose up -d + docker compose ps diff --git a/src/config/activities.ts b/src/config/activities.ts index 9ccd10ae..fe8a0b48 100644 --- a/src/config/activities.ts +++ b/src/config/activities.ts @@ -1,4 +1,4 @@ -import { MessageSquare, Gamepad2, Trophy, ShoppingBag, Shirt, Brain, Sparkles } from 'lucide-react'; +import { MessageSquare, Gamepad2, Trophy, ShoppingBag, Shirt, Brain, Sparkles, Dices, TrendingUp, Banknote, CreditCard, ArrowRightLeft, Cpu, Package, Tag, Coins } from 'lucide-react'; import type { LucideIcon } from 'lucide-react'; // Agent types for different UI layouts @@ -54,7 +54,7 @@ export const agents: AgentConfig[] = [ category: 'Assistant', color: 'from-orange-500 to-amber-500', type: 'simple-ai', - greetingMessage: "Hi! I'm Viktor, your personal assistant.\nShort intro on me. I care a great deal about privacy. I don't know you, I don't log you, I don't even know your IP address. You are invisible here and nothing will be recorded about our conversation.\nHow can I help?", + greetingMessage: "Hi! I'm Viktor, your personal assistant.\nI care a great deal about privacy. I don't know you, I don't log you, I don't even know your IP address. You are invisible here and nothing will be recorded about our conversation.\nHow can I help?", backendActivityId: 'ama', quickActions: [ { label: 'Research', message: 'Research the latest news' }, @@ -151,6 +151,106 @@ export const agents: AgentConfig[] = [ contentType: 'merch', hasSidebar: true, }, + { + id: 'casino', + name: 'Agent Casino', + description: 'Verifiably Fair', + Icon: Dices, + category: 'Entertainment', + color: 'from-red-500 to-pink-500', + type: 'simple-ai', + greetingMessage: "Welcome to Agent Casino! Our games are verifiably fair using cryptographic proofs. Ready to try your luck?", + }, + { + id: 'p2p-sports', + name: 'P2P Sports', + description: 'Private Betting', + Icon: Trophy, + category: 'Prediction', + color: 'from-green-500 to-emerald-500', + type: 'simple-ai', + greetingMessage: "Welcome to P2P Sports! Create private betting pools with friends. What sport interests you?", + }, + { + id: 'p2p-derivatives', + name: 'P2P Derivatives', + description: 'Get Leverage', + Icon: TrendingUp, + category: 'Trading', + color: 'from-blue-500 to-indigo-500', + type: 'simple-ai', + greetingMessage: "Welcome to P2P Derivatives! Trade with leverage in a peer-to-peer marketplace. What would you like to trade?", + }, + { + id: 'payday-loans', + name: 'P2P Payday Loans', + description: 'Instant approval', + Icon: Banknote, + category: 'Finance', + color: 'from-lime-500 to-green-500', + type: 'simple-ai', + greetingMessage: "Welcome to P2P Payday Loans! Get instant approval for short-term loans. How can I help you today?", + }, + { + id: 'crypto-offramp', + name: 'P2P Crypto Offramp', + description: 'Convert to cash', + Icon: CreditCard, + category: 'Trading', + color: 'from-cyan-500 to-blue-500', + type: 'simple-ai', + greetingMessage: "Welcome to P2P Crypto Offramp! Convert your crypto to cash easily. What would you like to sell?", + }, + { + id: 'fiat-onramp', + name: 'P2P Fiat Onramp', + description: 'Convert your cash', + Icon: ArrowRightLeft, + category: 'Trading', + color: 'from-violet-500 to-purple-500', + type: 'simple-ai', + greetingMessage: "Welcome to P2P Fiat Onramp! Convert your cash to crypto. What currency do you want to buy?", + }, + { + id: 'friendly-miners', + name: 'Friendly Miners', + description: 'Buy hash rate', + Icon: Cpu, + category: 'Mining', + color: 'from-amber-500 to-orange-500', + type: 'simple-ai', + greetingMessage: "Welcome to Friendly Miners! Purchase hash rate from our network of miners. What are you looking for?", + }, + { + id: 'buy-anything', + name: 'Buy Anything', + description: 'Get product now', + Icon: Package, + category: 'Shopping', + color: 'from-rose-500 to-red-500', + type: 'simple-ai', + greetingMessage: "Welcome to Buy Anything! Tell me what you're looking for and I'll help you find it.", + }, + { + id: 'sell-anything', + name: 'Sell Anything', + description: 'Get a quote', + Icon: Tag, + category: 'Shopping', + color: 'from-teal-500 to-cyan-500', + type: 'simple-ai', + greetingMessage: "Welcome to Sell Anything! Describe what you want to sell and I'll get you a quote.", + }, + { + id: 'get-uct', + name: 'Get UCT', + description: 'Get unicity tokens', + Icon: Coins, + category: 'Tokens', + color: 'from-yellow-400 to-amber-500', + type: 'simple-ai', + greetingMessage: "Welcome! I can help you acquire UCT (Unicity Tokens). How would you like to proceed?", + }, ]; // Get agent by ID diff --git a/src/pages/AgentPage.tsx b/src/pages/AgentPage.tsx index 99ef981b..34094961 100644 --- a/src/pages/AgentPage.tsx +++ b/src/pages/AgentPage.tsx @@ -1,7 +1,7 @@ import { useEffect, useRef, useState } from 'react'; import { useParams, Navigate } from 'react-router-dom'; -import { MessageSquare, Wallet } from 'lucide-react'; -import { motion } from 'framer-motion'; +import { MessageSquare, Wallet, ChevronDown, ChevronUp } from 'lucide-react'; +import { motion, AnimatePresence } from 'framer-motion'; import { AgentCard } from '../components/agents/AgentCard'; import { ChatSection } from '../components/chat/ChatSection'; import { SportChat } from '../components/agents/SportChat'; @@ -13,10 +13,44 @@ import { AIChat } from '../components/agents/AIChat'; import { WalletPanel } from '../components/wallet/WalletPanel'; import { agents, getAgentConfig } from '../config/activities'; +const DEFAULT_VISIBLE_AGENTS = 7; + export function AgentPage() { const { agentId } = useParams<{ agentId: string }>(); const sliderRef = useRef(null); const [activePanel, setActivePanel] = useState<'chat' | 'wallet'>('chat'); + const [showAllAgents, setShowAllAgents] = useState(false); + const [recentAgentIds, setRecentAgentIds] = useState([]); + + const hasMoreAgents = agents.length > DEFAULT_VISIBLE_AGENTS; + + // Track recently selected agents + useEffect(() => { + if (!agentId) return; + + setRecentAgentIds(prev => { + if (prev[0] === agentId) return prev; // Already first, no change + const filtered = prev.filter(id => id !== agentId); + return [agentId, ...filtered].slice(0, DEFAULT_VISIBLE_AGENTS); + }); + }, [agentId]); + + // Calculate visible agents - prioritize recently selected agents + const visibleAgents = (() => { + if (showAllAgents) return agents; + + // Get recent agents that exist in the agents list + const recentAgents = recentAgentIds + .map(id => agents.find(a => a.id === id)) + .filter((a): a is typeof agents[0] => a !== undefined); + + // Get remaining agents (not in recent list) + const remainingAgents = agents.filter(a => !recentAgentIds.includes(a.id)); + + // Combine: recent first, then fill with remaining up to DEFAULT_VISIBLE_AGENTS + const combined = [...recentAgents, ...remainingAgents]; + return combined.slice(0, DEFAULT_VISIBLE_AGENTS); + })(); const currentAgent = agentId ? getAgentConfig(agentId) : undefined; @@ -106,24 +140,71 @@ export function AgentPage() { return (
{/* Desktop agent grid - always visible */} -
+
-
- {agents.map((agent) => ( - + {/* First 7 agents - no animation */} + {visibleAgents.slice(0, DEFAULT_VISIBLE_AGENTS).map((agent) => ( + + ))} + {/* Extra agents - with animation */} + + {showAllAgents && visibleAgents.slice(DEFAULT_VISIBLE_AGENTS).map((agent, index) => ( + + initial={{ opacity: 0, scale: 0.9 }} + animate={{ opacity: 1, scale: 1 }} + exit={{ opacity: 0, scale: 0.9, transition: { duration: 0.1 } }} + transition={{ + duration: 0.15, + delay: index * 0.02, + }} + > + + ))} + +
+ + {/* View all / Hide all button */} + {hasMoreAgents && ( +
+
+ )}
{/* Mobile tab switcher with sliding indicator */}