diff --git a/app/page.tsx b/app/page.tsx index 9709f36..946c81b 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -1,66 +1,17 @@ "use client"; -import { useState, useEffect } from "react"; +import { useState } from "react"; import Sidebar from "@/components/Sidebar"; import type { View } from "@/components/Sidebar"; import PromptEnhancer from "@/components/PromptEnhancer"; import PRDGenerator from "@/components/PRDGenerator"; import ActionPlanGenerator from "@/components/ActionPlanGenerator"; +import UXDesignerPrompt from "@/components/UXDesignerPrompt"; import HistoryPanel from "@/components/HistoryPanel"; import SettingsPanel from "@/components/SettingsPanel"; -import useStore from "@/lib/store"; -import modelAdapter from "@/lib/services/adapter-instance"; export default function Home() { const [currentView, setCurrentView] = useState("enhance"); - const { setQwenTokens, setApiKey } = useStore(); - - useEffect(() => { - // Handle OAuth callback - if (typeof window !== "undefined") { - const urlParams = new URLSearchParams(window.location.search); - const code = urlParams.get("code"); - - if (code) { - // In a real app, you would exchange the code for tokens here - // Since we don't have a backend or real client secret, we'll simulate it - console.log("OAuth code received:", code); - - // Mock token exchange - const mockAccessToken = "mock_access_token_" + Math.random().toString(36).substr(2, 9); - const tokens = { - accessToken: mockAccessToken, - expiresAt: Date.now() + 3600 * 1000, // 1 hour - }; - - setQwenTokens(tokens); - modelAdapter.setQwenOAuthTokens(tokens.accessToken, undefined, 3600); - - // Save to localStorage - localStorage.setItem("promptarch-qwen-tokens", JSON.stringify(tokens)); - - // Clear the code from URL - window.history.replaceState({}, document.title, window.location.pathname); - - // Switch to settings to show success (optional) - setCurrentView("settings"); - } - - // Load tokens from localStorage on init - const savedTokens = localStorage.getItem("promptarch-qwen-tokens"); - if (savedTokens) { - try { - const tokens = JSON.parse(savedTokens); - if (tokens.expiresAt > Date.now()) { - setQwenTokens(tokens); - modelAdapter.setQwenOAuthTokens(tokens.accessToken, tokens.refreshToken, (tokens.expiresAt - Date.now()) / 1000); - } - } catch (e) { - console.error("Failed to load Qwen tokens:", e); - } - } - } - }, []); const renderContent = () => { switch (currentView) { @@ -70,6 +21,8 @@ export default function Home() { return ; case "action": return ; + case "uxdesigner": + return ; case "history": return ; case "settings": diff --git a/components/Sidebar.tsx b/components/Sidebar.tsx index ac7b84a..2d093e6 100644 --- a/components/Sidebar.tsx +++ b/components/Sidebar.tsx @@ -2,10 +2,10 @@ import { Button } from "@/components/ui/button"; import useStore from "@/lib/store"; -import { Sparkles, FileText, ListTodo, Settings, History } from "lucide-react"; +import { Sparkles, FileText, ListTodo, Palette, History, Settings } from "lucide-react"; import { cn } from "@/lib/utils"; -export type View = "enhance" | "prd" | "action" | "history" | "settings"; +export type View = "enhance" | "prd" | "action" | "uxdesigner" | "history" | "settings"; interface SidebarProps { currentView: View; @@ -19,6 +19,7 @@ export default function Sidebar({ currentView, onViewChange }: SidebarProps) { { id: "enhance" as View, label: "Prompt Enhancer", icon: Sparkles }, { id: "prd" as View, label: "PRD Generator", icon: FileText }, { id: "action" as View, label: "Action Plan", icon: ListTodo }, + { id: "uxdesigner" as View, label: "UX Designer Prompt", icon: Palette }, { id: "history" as View, label: "History", icon: History, count: history.length }, { id: "settings" as View, label: "Settings", icon: Settings }, ]; @@ -81,6 +82,7 @@ export default function Sidebar({ currentView, onViewChange }: SidebarProps) {
  • • Use different providers for best results
  • • Copy enhanced prompts to your AI agent
  • • PRDs generate better action plans
  • +
  • • UX Designer Prompt for design tasks
  • diff --git a/components/UXDesignerPrompt.tsx b/components/UXDesignerPrompt.tsx new file mode 100644 index 0000000..f97b3d1 --- /dev/null +++ b/components/UXDesignerPrompt.tsx @@ -0,0 +1,242 @@ +"use client"; + +import { useState, useEffect } from "react"; +import { Button } from "@/components/ui/button"; +import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; +import { Textarea } from "@/components/ui/textarea"; +import useStore from "@/lib/store"; +import modelAdapter from "@/lib/services/adapter-instance"; +import { Palette, Copy, Loader2, CheckCircle2, Settings } from "lucide-react"; +import { cn } from "@/lib/utils"; + +export default function UXDesignerPrompt() { + const { + currentPrompt, + selectedProvider, + selectedModels, + availableModels, + apiKeys, + isProcessing, + error, + setSelectedProvider, + setCurrentPrompt, + setEnhancedPrompt, + setProcessing, + setError, + setAvailableModels, + setSelectedModel, + } = useStore(); + + const [copied, setCopied] = useState(false); + const [generatedPrompt, setGeneratedPrompt] = useState(null); + + const selectedModel = selectedModels[selectedProvider]; + const models = availableModels[selectedProvider] || modelAdapter.getAvailableModels(selectedProvider); + + useEffect(() => { + if (typeof window !== "undefined") { + loadAvailableModels(); + const saved = localStorage.getItem("promptarch-api-keys"); + if (saved) { + try { + const keys = JSON.parse(saved); + if (keys.ollama) modelAdapter.updateOllamaApiKey(keys.ollama); + if (keys.zai) modelAdapter.updateZaiApiKey(keys.zai); + } catch (e) { + console.error("Failed to load API keys:", e); + } + } + } + }, [selectedProvider]); + + const loadAvailableModels = async () => { + const fallbackModels = modelAdapter.getAvailableModels(selectedProvider); + setAvailableModels(selectedProvider, fallbackModels); + + try { + const result = await modelAdapter.listModels(selectedProvider); + if (result.success && result.data) { + setAvailableModels(selectedProvider, result.data[selectedProvider] || fallbackModels); + } + } catch (error) { + console.error("Failed to load models:", error); + } + }; + + const handleGenerate = async () => { + if (!currentPrompt.trim()) { + setError("Please enter an app description"); + return; + } + + const apiKey = apiKeys[selectedProvider]; + if (!apiKey || !apiKey.trim()) { + setError(`Please configure your ${selectedProvider.toUpperCase()} API key in Settings`); + return; + } + + setProcessing(true); + setError(null); + setGeneratedPrompt(null); + + try { + const result = await modelAdapter.generateUXDesignerPrompt(currentPrompt, selectedProvider, selectedModel); + + if (result.success && result.data) { + setGeneratedPrompt(result.data); + setEnhancedPrompt(result.data); + } else { + setError(result.error || "Failed to generate UX designer prompt"); + } + } catch (err) { + setError(err instanceof Error ? err.message : "An error occurred"); + } finally { + setProcessing(false); + } + }; + + const handleCopy = async () => { + if (generatedPrompt) { + await navigator.clipboard.writeText(generatedPrompt); + setCopied(true); + setTimeout(() => setCopied(false), 2000); + } + }; + + const handleClear = () => { + setCurrentPrompt(""); + setGeneratedPrompt(null); + setEnhancedPrompt(null); + setError(null); + }; + + return ( +
    + + + + + UX Designer Prompt + + + Describe your app idea and get the BEST EVER prompt for UX design + + + +
    + +
    + {(["ollama", "zai"] as const).map((provider) => ( + + ))} +
    +
    + +
    + + +
    + +
    + +