From 0326822621553b78098cfe0834369693946eab7a Mon Sep 17 00:00:00 2001 From: Aun Ali Date: Sat, 9 Aug 2025 15:38:19 +0000 Subject: [PATCH] Initial prototype --- .idx/icon.png | Bin 0 -> 20249 bytes .modified | 0 docs/blueprint.md | 19 +++ src/ai/dev.ts | 5 +- src/ai/flows/suggest-tags.ts | 56 ++++++++ src/app/globals.css | 48 +++---- src/app/layout.tsx | 16 ++- src/app/page.tsx | 23 +++- src/components/create-prompt-dialog.tsx | 168 ++++++++++++++++++++++++ src/components/header.tsx | 52 ++++++++ src/components/icons.tsx | 10 ++ src/components/prompt-card.tsx | 66 ++++++++++ src/components/prompt-list.tsx | 51 +++++++ src/lib/actions.ts | 82 ++++++++++++ src/lib/data.ts | 63 +++++++++ src/lib/types.ts | 8 ++ 16 files changed, 626 insertions(+), 41 deletions(-) create mode 100644 .idx/icon.png create mode 100644 .modified create mode 100644 docs/blueprint.md create mode 100644 src/ai/flows/suggest-tags.ts create mode 100644 src/components/create-prompt-dialog.tsx create mode 100644 src/components/header.tsx create mode 100644 src/components/icons.tsx create mode 100644 src/components/prompt-card.tsx create mode 100644 src/components/prompt-list.tsx create mode 100644 src/lib/actions.ts create mode 100644 src/lib/data.ts create mode 100644 src/lib/types.ts diff --git a/.idx/icon.png b/.idx/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..3c5444e8727223ddf026efe785b0767221f5b8e3 GIT binary patch literal 20249 zcmXtgby$<{`}VUjV51wP8BtZk_KskAxOuh zW592IkN5p+J9g~3_uSWg#d)63buG@wK#QD&nFIg;avkma#sC1qzXbtMBK(Vuf8`SZ z-~@E;tD6Mc?b^cf=(>;hwzBh8W^5h)cKnVg@qfk29r>yykfjqt{hBc+aG6{)mHsu! zD@Nw@vtHV$5($3IQf^FyE7_frB0*+DBZZd{?N7d5+nXLgT$oT%`J~jU)NXy1FzZ;6 zR6TthcD(rBe4kpMtr@cMcIZx{$x6ZPyQiEv%}O$T1!qsCN>ZHkOZjp%u^gB0)7?y5 z3kSx(Ydv+Di`W;uDO{&oYNgx^p7up7g%r3H?w_{Xw_?x8c8|TyjY96t|JY+#6h*LH zhpXa05mF1Ft*z>HIsW{iz{oghAIs5EI%mktRY>(fZOo~`FkU*e;A@*1c?cKi=HVEu z?A|-Gy_}Ng@;YPJO!8q&7_K+otg`j0f5fTi&lc|8c|`|?FA8Ic`+p%cFG3)jVOr8u zkrg77(qT^@a{pEQ60{j_Aii@|QS@fX`>Vran~-%B0U3`>B2Ae5lPJfH{QaE@sYX1 z<-Kvb0;6=(AzX8$#Ve0+sVCPqP>zd4JIVkoz?9rQI$dYjd&j3o<$*w7Y7|aSKMF^SvYY z)1lm2z+1EJxu5O=UG7pT9*qGx@pb4rw66~5b7A?eB?*mCy-abDWH()m*!iQ9%euAH zEf1atkEw2fsS0ob!{~$@;JD-6yx62(t4Y-r*H$|u#z_2yV6NKXpf9Z+bEqm`@J>aE zPp;a7YDWH2I3$G=P^`gmdN4_GjoOYAc+j0ieN%Wlx6j4L@y&N^urS6?2$K-Xo{;iX zqeU#=euLL&6as(u)<+BWg|tX**ng*KX|RqbIB^P=Bwlq7YRfkH{C?5cYGE zN=c!5BKZ_U*erV1PefK``1kDyfHhp+y^_{EHf(zEHPNQ6qQc0&$iuuIvN1`}DqHUH zvNvRb+}Yhc`uRT5w?%Si5A(C6ANip4!mOmD4Dr`UukWX6w7K30Pp%w7LM`C#f+6h1 zQjUlfF>b)`Mh-aAXb23Y{&Ml|4~bsB7Wmlwc&l8_qf5Ne!bI@8w0&n$j%RLy12^6h zEj;}q%w~*D*G`1@HX|LVtRiFKKk)_9Xe2AWw4v0^$mjJg#W6+?zMk#Xk2x~`9dVmj z&zXad#urUrTlt4)QSmG*DG)@DE=-nukkik0mg5YjY5CInxM!SnzNKY&f;1A?_*vU( zG#A}u;%O=7i}6K=oVn^vu#X3`{|(iO$J}`f`bj;n{$8txW$M}wqPgrV&Yu*)TnNoy z-ldJ^84U|8F^X%JFYY$r4G8=EvHj2V-oF!OqYUwqg*f`ucq^PO=Y_;l?Q-RRf073C zoNj4Jo;)lS0x1^zo>u7hKN8n0rgw|--j!ZB6l$Cj$L7w77`*5EiZJ_|NLlD*xY@`8 z8dVBmV0p1Lgx1V|HbIxVHj8^j&V7@ZVj+|L+2?5piK$Af^Mj(l-Ch@s1XX;p}WRZp(v7 z+Cm3{&7RkBdLK65_Os3f*H^B8;RAXdM|#R+VQEvhIimvS0%ZlH2fX|&i8r6ZWP%e} z3$p$$TYKMLm*oQ#n+6=;GT*?7Q=A4A{aen9w@}m*O`rNEn>;paMYIxvGwLABJ*Ttx zbeTV4S31-?wYV^hr{z%bsAu)71>IheUTLL6P~c%0Dw>L2t8P47(zB`XL$~CQ$-l6s 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Ξ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 + +const SuggestTagsOutputSchema = z.object({ + tags: z + .array(z.string()) + .describe('An array of suggested tags for the given prompt.'), +}); +export type SuggestTagsOutput = z.infer; + +export async function suggestTags(input: SuggestTagsInput): Promise { + return suggestTagsFlow(input); +} + +const suggestTagsPrompt = ai.definePrompt({ + name: 'suggestTagsPrompt', + input: {schema: SuggestTagsInputSchema}, + output: {schema: SuggestTagsOutputSchema}, + prompt: `You are a prompt categorization expert. + + Given the following prompt, suggest 5 relevant tags that can be used to categorize and search for this prompt later. Return them as a simple array of strings. + + Prompt: {{{promptText}}} + + Tags:`, +}); + +const suggestTagsFlow = ai.defineFlow( + { + name: 'suggestTagsFlow', + inputSchema: SuggestTagsInputSchema, + outputSchema: SuggestTagsOutputSchema, + }, + async input => { + const {output} = await suggestTagsPrompt(input); + return output!; + } +); diff --git a/src/app/globals.css b/src/app/globals.css index a8144b6..e3cca7a 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -14,67 +14,51 @@ body { --card-foreground: 0 0% 3.9%; --popover: 0 0% 100%; --popover-foreground: 0 0% 3.9%; - --primary: 0 0% 9%; + --primary: 300 50% 50%; --primary-foreground: 0 0% 98%; - --secondary: 0 0% 96.1%; - --secondary-foreground: 0 0% 9%; + --secondary: 275 100% 25.1%; + --secondary-foreground: 0 0% 98%; --muted: 0 0% 96.1%; --muted-foreground: 0 0% 45.1%; - --accent: 0 0% 96.1%; + --accent: 300 50% 60%; --accent-foreground: 0 0% 9%; --destructive: 0 84.2% 60.2%; --destructive-foreground: 0 0% 98%; --border: 0 0% 89.8%; --input: 0 0% 89.8%; - --ring: 0 0% 3.9%; + --ring: 300 50% 50%; --chart-1: 12 76% 61%; --chart-2: 173 58% 39%; --chart-3: 197 37% 24%; --chart-4: 43 74% 66%; --chart-5: 27 87% 67%; --radius: 0.5rem; - --sidebar-background: 0 0% 98%; - --sidebar-foreground: 240 5.3% 26.1%; - --sidebar-primary: 240 5.9% 10%; - --sidebar-primary-foreground: 0 0% 98%; - --sidebar-accent: 240 4.8% 95.9%; - --sidebar-accent-foreground: 240 5.9% 10%; - --sidebar-border: 220 13% 91%; - --sidebar-ring: 217.2 91.2% 59.8%; } .dark { - --background: 0 0% 3.9%; + --background: 0 0% 18.8%; --foreground: 0 0% 98%; - --card: 0 0% 3.9%; + --card: 0 0% 22%; --card-foreground: 0 0% 98%; - --popover: 0 0% 3.9%; + --popover: 0 0% 18.8%; --popover-foreground: 0 0% 98%; - --primary: 0 0% 98%; - --primary-foreground: 0 0% 9%; - --secondary: 0 0% 14.9%; + --primary: 300 50% 50%; + --primary-foreground: 0 0% 98%; + --secondary: 275 100% 35%; --secondary-foreground: 0 0% 98%; - --muted: 0 0% 14.9%; + --muted: 0 0% 25%; --muted-foreground: 0 0% 63.9%; - --accent: 0 0% 14.9%; + --accent: 300 50% 60%; --accent-foreground: 0 0% 98%; --destructive: 0 62.8% 30.6%; --destructive-foreground: 0 0% 98%; - --border: 0 0% 14.9%; - --input: 0 0% 14.9%; - --ring: 0 0% 83.1%; + --border: 0 0% 30%; + --input: 0 0% 25%; + --ring: 300 50% 60%; --chart-1: 220 70% 50%; --chart-2: 160 60% 45%; --chart-3: 30 80% 55%; --chart-4: 280 65% 60%; --chart-5: 340 75% 55%; - --sidebar-background: 240 5.9% 10%; - --sidebar-foreground: 240 4.8% 95.9%; - --sidebar-primary: 224.3 76.3% 48%; - --sidebar-primary-foreground: 0 0% 100%; - --sidebar-accent: 240 3.7% 15.9%; - --sidebar-accent-foreground: 240 4.8% 95.9%; - --sidebar-border: 240 3.7% 15.9%; - --sidebar-ring: 217.2 91.2% 59.8%; } } diff --git a/src/app/layout.tsx b/src/app/layout.tsx index c81ce2d..4f5e03f 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -1,9 +1,10 @@ import type {Metadata} from 'next'; import './globals.css'; +import { Toaster } from "@/components/ui/toaster"; export const metadata: Metadata = { - title: 'Firebase Studio App', - description: 'Generated by Firebase Studio', + title: 'PromptVerse', + description: 'An AI prompt management tool to create, organize, and share your best prompts.', }; export default function RootLayout({ @@ -12,13 +13,16 @@ export default function RootLayout({ children: React.ReactNode; }>) { return ( - + - - + + - {children} + + {children} + + ); } diff --git a/src/app/page.tsx b/src/app/page.tsx index 6ff5373..c9185ca 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -1,3 +1,22 @@ -export default function Home() { - return <>; +import { Header } from '@/components/header'; +import { PromptList, PromptListSkeleton } from '@/components/prompt-list'; +import { Suspense } from 'react'; + +export default function Home({ + searchParams, +}: { + searchParams?: { q?: string }; +}) { + const query = searchParams?.q || ''; + + return ( +
+
+
+ }> + + +
+
+ ); } diff --git a/src/components/create-prompt-dialog.tsx b/src/components/create-prompt-dialog.tsx new file mode 100644 index 0000000..061130d --- /dev/null +++ b/src/components/create-prompt-dialog.tsx @@ -0,0 +1,168 @@ +'use client'; + +import { useEffect, useRef, useState, useTransition } from 'react'; +import { useFormState, useFormStatus } from 'react-dom'; +import { Button } from '@/components/ui/button'; +import { + Dialog, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogTitle, + DialogTrigger, + DialogClose, +} from '@/components/ui/dialog'; +import { Input } from '@/components/ui/input'; +import { Label } from '@/components/ui/label'; +import { Textarea } from '@/components/ui/textarea'; +import { createPrompt, suggestPromptTags } from '@/lib/actions'; +import { useToast } from '@/hooks/use-toast'; +import { PlusCircle, Loader2, Sparkles, XIcon } from 'lucide-react'; +import { Badge } from './ui/badge'; + +const initialState = { + message: '', + errors: {}, + success: false, +}; + +function SubmitButton() { + const { pending } = useFormStatus(); + return ( + + ); +} + +export function CreatePromptDialog() { + const [open, setOpen] = useState(false); + const [state, formAction] = useFormState(createPrompt, initialState); + const { toast } = useToast(); + const formRef = useRef(null); + + const [promptContent, setPromptContent] = useState(''); + const [tags, setTags] = useState([]); + const [tagInput, setTagInput] = useState(''); + const [isSuggesting, startSuggestionTransition] = useTransition(); + + const handleSuggestTags = async () => { + startSuggestionTransition(async () => { + const result = await suggestPromptTags(promptContent); + if (result.error) { + toast({ title: 'Suggestion Failed', description: result.error, variant: 'destructive' }); + } else if (result.tags) { + setTags((prev) => [...new Set([...prev, ...result.tags!])]); + toast({ title: 'Tags Suggested!', description: 'AI-powered tags have been added.' }); + } + }); + }; + + const handleTagInputKeyDown = (e: React.KeyboardEvent) => { + if (e.key === 'Enter' && tagInput.trim()) { + e.preventDefault(); + setTags((prev) => [...new Set([...prev, tagInput.trim().toLowerCase()])]); + setTagInput(''); + } + }; + + const removeTag = (tagToRemove: string) => { + setTags((prev) => prev.filter((tag) => tag !== tagToRemove)); + }; + + + useEffect(() => { + if (state.success) { + toast({ + title: 'Success!', + description: state.message, + }); + setOpen(false); + formRef.current?.reset(); + setTags([]); + setPromptContent(''); + } else if (state.message && !state.success && Object.keys(state.errors ?? {}).length > 0) { + toast({ + title: 'Error', + description: state.message, + variant: 'destructive', + }); + } + }, [state, toast]); + + return ( + + + + + + + Create a new prompt + + Craft your next masterpiece. Add notes and tags to keep it organized. + + +
+
+ + + {state.errors?.title &&

{state.errors.title[0]}

} +
+
+ +