From cc740265ea939eaec487f76f9c98ca94ea1cb11f Mon Sep 17 00:00:00 2001 From: Oliver Bryan Date: Thu, 5 Feb 2026 16:27:13 +0000 Subject: [PATCH] ask ai --- bun.lock | 8 ++++ package.json | 2 + src/components/ask-ai.tsx | 88 +++++++++++++++++++++++++++++++++++++++ src/lib/constants.ts | 10 +++++ 4 files changed, 108 insertions(+) create mode 100644 src/components/ask-ai.tsx create mode 100644 src/lib/constants.ts diff --git a/bun.lock b/bun.lock index cd059d86..6babf1df 100644 --- a/bun.lock +++ b/bun.lock @@ -5,6 +5,7 @@ "": { "name": "ob248.com", "dependencies": { + "@iconify/react": "^6.0.2", "@nsmr/pixelart-react": "^2.0.0", "@tailwindcss/vite": "^4.1.18", "class-variance-authority": "^0.7.1", @@ -14,6 +15,7 @@ "react": "^19.2.0", "react-dom": "^19.2.0", "react-router-dom": "^6.30.1", + "simple-icons": "^16.7.0", "tailwind-merge": "^3.4.0", "tailwindcss": "^4.1.18", }, @@ -159,6 +161,10 @@ "@humanwhocodes/retry": ["@humanwhocodes/retry@0.4.3", "", {}, "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ=="], + "@iconify/react": ["@iconify/react@6.0.2", "", { "dependencies": { "@iconify/types": "^2.0.0" }, "peerDependencies": { "react": ">=16" } }, "sha512-SMmC2sactfpJD427WJEDN6PMyznTFMhByK9yLW0gOTtnjzzbsi/Ke/XqsumsavFPwNiXs8jSiYeZTmLCLwO+Fg=="], + + "@iconify/types": ["@iconify/types@2.0.0", "", {}, "sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg=="], + "@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.13", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA=="], "@jridgewell/remapping": ["@jridgewell/remapping@2.3.5", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ=="], @@ -657,6 +663,8 @@ "shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="], + "simple-icons": ["simple-icons@16.7.0", "", {}, "sha512-2BteuQXu1+/jK5dF8YXe8nwoRG3afwl03bCmgPJLiotllUBU46B+WntXT731Z17oOntfV5eeTI7Q1k7MeOA6eg=="], + "source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="], "strip-json-comments": ["strip-json-comments@3.1.1", "", {}, "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig=="], diff --git a/package.json b/package.json index 3774107b..3cd621b4 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,7 @@ "preview": "vite preview" }, "dependencies": { + "@iconify/react": "^6.0.2", "@nsmr/pixelart-react": "^2.0.0", "@tailwindcss/vite": "^4.1.18", "class-variance-authority": "^0.7.1", @@ -19,6 +20,7 @@ "react": "^19.2.0", "react-dom": "^19.2.0", "react-router-dom": "^6.30.1", + "simple-icons": "^16.7.0", "tailwind-merge": "^3.4.0", "tailwindcss": "^4.1.18" }, diff --git a/src/components/ask-ai.tsx b/src/components/ask-ai.tsx new file mode 100644 index 00000000..cc505bba --- /dev/null +++ b/src/components/ask-ai.tsx @@ -0,0 +1,88 @@ +import { AI_SUMMARY_PROMPT } from "@/lib/constants"; +import { cn } from "@/lib/utils"; +import { Icon } from "@iconify/react"; +import { Copy } from "@nsmr/pixelart-react"; +import { useRef, useState } from "react"; + +const chatGptUrl = "https://chat.openai.com/?q="; +const claudeUrl = "https://claude.ai/new?q="; + +export function AskAI({ + name, + prompt = AI_SUMMARY_PROMPT, + inline = false, +}: { + name: string; + prompt?: string; + inline?: boolean; +}) { + const encodedPrompt = encodeURIComponent(prompt); + const [copied, setCopied] = useState(false); + const timeoutRef = useRef(null); + + const handleCopy = async () => { + if (!navigator.clipboard) return; + try { + await navigator.clipboard.writeText(prompt); + setCopied(true); + if (timeoutRef.current) { + window.clearTimeout(timeoutRef.current); + } + timeoutRef.current = window.setTimeout(() => { + setCopied(false); + }, 1500); + } catch { + setCopied(false); + } + }; + + return ( +
+

Ask AI about {name}:

+
+ + + + + + +
+ + + Copied to clipboard + +
+
+
+ ); +} diff --git a/src/lib/constants.ts b/src/lib/constants.ts new file mode 100644 index 00000000..1329d735 --- /dev/null +++ b/src/lib/constants.ts @@ -0,0 +1,10 @@ +export const AI_SUMMARY_PROMPT = + "I am a recruiter, tell me about Oliver Bryan, a software developer. What would he bring to the table? Review his portfolio at ob248.com and summarize his key strengths, technical skills, and notable projects. What makes him stand out as a candidate?"; + +export function getProjectPrompt( + projectName: string, + projectDescription: string, + projectSlug: string, +): string { + return `Tell me about "${projectName}", a project by Oliver Bryan. ${projectDescription} Review the project page at ob248.com/projects/${projectSlug} and explain the technical decisions, technologies used, and what this project demonstrates about Oliver's skills as a developer. Provide any url or repository that would be helpful.`; +}