mirror of
https://github.com/PinkSheep27/SBU-Hackathon.git
synced 2026-10-10 23:50:26 -04:00
Fixed commented out programs
This commit is contained in:
+110
-112
@@ -1,121 +1,119 @@
|
|||||||
// "use client";
|
"use client";
|
||||||
|
|
||||||
// import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
// import { useRouter } from "next/navigation";
|
import { useRouter } from "next/navigation";
|
||||||
// import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
|
|
||||||
// function Dashboard() { // 2. Changed from 'export default function'
|
function Dashboard() { // 2. Changed from 'export default function'
|
||||||
// const router = useRouter();
|
const router = useRouter();
|
||||||
// const [query, setQuery] = useState("");
|
const [query, setQuery] = useState("");
|
||||||
// const [sideBarOpen, setSidebarOpen] = useState(true);
|
const [sideBarOpen, setSidebarOpen] = useState(true);
|
||||||
|
|
||||||
// const projects = [
|
const projects = [
|
||||||
// { name: "Alpha Project", createdAt: "2025-01-01" },
|
{ name: "Alpha Project", createdAt: "2025-01-01" },
|
||||||
// { name: "Beta Board", createdAt: "2025-02-15" },
|
{ name: "Beta Board", createdAt: "2025-02-15" },
|
||||||
// { name: "Gamma Tasl", createdAt: "2025-03-10" },
|
{ name: "Gamma Tasl", createdAt: "2025-03-10" },
|
||||||
// ];
|
];
|
||||||
// const filtered = projects.filter((p) =>
|
const filtered = projects.filter((p) =>
|
||||||
// p.name.toLowerCase().includes(query.toLowerCase())
|
p.name.toLowerCase().includes(query.toLowerCase())
|
||||||
// );
|
);
|
||||||
|
|
||||||
// return (
|
return (
|
||||||
// <div className="flex min-h-screen bg-zinc-50 dark:bg-black font-sans transition-all duration-300">
|
<div className="flex min-h-screen bg-zinc-50 dark:bg-black font-sans transition-all duration-300">
|
||||||
// <aside
|
<aside
|
||||||
// className={`${
|
className={`${sideBarOpen ? "w-64" : "w-16"
|
||||||
// sideBarOpen ? "w-64" : "w-16"
|
} bg-white dark:bg-zinc-900 border-r border-zinc-200 dark:border-zinc-800 transition-all duration-300 flex flex-col`}
|
||||||
// } bg-white dark:bg-zinc-900 border-r border-zinc-200 dark:border-zinc-800 transition-all duration-300 flex flex-col`}
|
>
|
||||||
// >
|
<div className="flex items-center justify-between p-4 border-b border-zinc-200 dark:border-zinc-800">
|
||||||
// <div className="flex items-center justify-between p-4 border-b border-zinc-200 dark:border-zinc-800">
|
{sideBarOpen && (
|
||||||
// {sideBarOpen && (
|
<span className="text-lg font-semibold text-zinc-800 dark:text-zinc-100">
|
||||||
// <span className="text-lg font-semibold text-zinc-800 dark:text-zinc-100">
|
More
|
||||||
// More
|
</span>
|
||||||
// </span>
|
)}
|
||||||
// )}
|
<button
|
||||||
// <button
|
onClick={() => setSidebarOpen(!sideBarOpen)}
|
||||||
// onClick={() => setSidebarOpen(!sideBarOpen)}
|
className="text-zinc-600 dark:text-zinc-300 hover:text-blue-500 transition-colors"
|
||||||
// className="text-zinc-600 dark:text-zinc-300 hover:text-blue-500 transition-colors"
|
title="Toggle Sidebar"
|
||||||
// title="Toggle Sidebar"
|
>
|
||||||
// >
|
☰
|
||||||
// ☰
|
</button>
|
||||||
// </button>
|
</div>
|
||||||
// </div>
|
|
||||||
|
|
||||||
// <nav
|
<nav
|
||||||
// className={`flex flex-col p-4 gap-3 text-zinc-700 dark:text-zinc-300 transition-opacity duration-200 ${
|
className={`flex flex-col p-4 gap-3 text-zinc-700 dark:text-zinc-300 transition-opacity duration-200 ${sideBarOpen ? "opacity-100" : "opacity-0"
|
||||||
// sideBarOpen ? "opacity-100" : "opacity-0"
|
}`}
|
||||||
// }`}
|
>
|
||||||
// >
|
<Link
|
||||||
// <Link
|
href="/"
|
||||||
// href="/"
|
className="hover:text-blue-600 dark:hover:text-blue-400 transition-colors"
|
||||||
// className="hover:text-blue-600 dark:hover:text-blue-400 transition-colors"
|
>
|
||||||
// >
|
Home
|
||||||
// Home
|
</Link>
|
||||||
// </Link>
|
<p
|
||||||
// <p
|
className="hover:text-blue-600 dark:hover:text-blue-400 transition-colors"
|
||||||
// className="hover:text-blue-600 dark:hover:text-blue-400 transition-colors"
|
>
|
||||||
// >
|
Settings
|
||||||
// Settings
|
</p>
|
||||||
// </p>
|
{/* 3. Added the Logout link here */}
|
||||||
// {/* 3. Added the Logout link here */}
|
<Link
|
||||||
// <Link
|
href="/auth/logout"
|
||||||
// href="/auth/logout"
|
className="hover:text-blue-600 dark:hover:text-blue-400 transition-colors"
|
||||||
// className="hover:text-blue-600 dark:hover:text-blue-400 transition-colors"
|
>
|
||||||
// >
|
Logout
|
||||||
// Logout
|
</Link>
|
||||||
// </Link>
|
</nav>
|
||||||
// </nav>
|
</aside>
|
||||||
// </aside>
|
|
||||||
|
|
||||||
// <div className="flex-1 flex flex-col min-w-0">
|
<div className="flex-1 flex flex-col min-w-0">
|
||||||
// <header className="sticky top-0 z-10 bg-white dark:bg-black/80 backdrop-blur-sm border-b border-zinc-200 dark:border-zinc-800">
|
<header className="sticky top-0 z-10 bg-white dark:bg-black/80 backdrop-blur-sm border-b border-zinc-200 dark:border-zinc-800">
|
||||||
// <div className="max-w-7xl mx-auto px-6 py-4 flex items-center justify-between gap-4">
|
<div className="max-w-7xl mx-auto px-6 py-4 flex items-center justify-between gap-4">
|
||||||
// <div className="flex-1">
|
<div className="flex-1">
|
||||||
// <input
|
<input
|
||||||
// id="dashboard-search"
|
id="dashboard-search"
|
||||||
// value={query}
|
value={query}
|
||||||
// onChange={(e) => setQuery(e.target.value)}
|
onChange={(e) => setQuery(e.target.value)}
|
||||||
// placeholder="Search projects, boards or tasks..."
|
placeholder="Search projects, boards or tasks..."
|
||||||
// className="w-full max-w-md px-4 py-2 rounded-md border border-zinc-200 dark:border-zinc-700 bg-white dark:bg-zinc-900 text-zinc-900 dark:text-zinc-100 focus:outline-none focus:ring-2 focus:ring-blue-500"
|
className="w-full max-w-md px-4 py-2 rounded-md border border-zinc-200 dark:border-zinc-700 bg-white dark:bg-zinc-900 text-zinc-900 dark:text-zinc-100 focus:outline-none focus:ring-2 focus:ring-blue-500"
|
||||||
// />
|
/>
|
||||||
// </div>
|
</div>
|
||||||
|
|
||||||
// <div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
// <button
|
<button
|
||||||
// type="button"
|
type="button"
|
||||||
// onClick={() => router.push("/dashbaord/create")}
|
onClick={() => router.push("/dashbaord/create")}
|
||||||
// className="bg-blue-600 hover:bg-blue-700 text-white px-4 py-2 rounded-md shadow-sm"
|
className="bg-blue-600 hover:bg-blue-700 text-white px-4 py-2 rounded-md shadow-sm"
|
||||||
// >
|
>
|
||||||
// Create
|
Create
|
||||||
// </button>
|
</button>
|
||||||
// </div>
|
</div>
|
||||||
// </div>
|
</div>
|
||||||
// </header>
|
</header>
|
||||||
|
|
||||||
// <main className="max-w-7xl w-full mx-auto px-6 py-10">
|
<main className="max-w-7xl w-full mx-auto px-6 py-10">
|
||||||
// <h1 className="text-2xl font-semibold text-black dark:text-zinc-50 mb-4">
|
<h1 className="text-2xl font-semibold text-black dark:text-zinc-50 mb-4">
|
||||||
// Project Names
|
Project Names
|
||||||
// </h1>
|
</h1>
|
||||||
|
|
||||||
// <section>
|
<section>
|
||||||
// <ul className="space-y-3">
|
<ul className="space-y-3">
|
||||||
// {filtered.map((project, index) => (
|
{filtered.map((project, index) => (
|
||||||
// <li
|
<li
|
||||||
// key={index}
|
key={index}
|
||||||
// className="flex justify-between p-4 bg-white dark:bg-zinc-900 border border-zinc-100 dark:border-zinc-800 rounded-md text-zinc-800 dark:text-zinc-100"
|
className="flex justify-between p-4 bg-white dark:bg-zinc-900 border border-zinc-100 dark:border-zinc-800 rounded-md text-zinc-800 dark:text-zinc-100"
|
||||||
// >
|
>
|
||||||
// <span>{project.name}</span>
|
<span>{project.name}</span>
|
||||||
// <span className="text-zinc-500 dark:text-zinc-400 text-sm">
|
<span className="text-zinc-500 dark:text-zinc-400 text-sm">
|
||||||
// Created: {project.createdAt}
|
Created: {project.createdAt}
|
||||||
// </span>
|
</span>
|
||||||
// </li>
|
</li>
|
||||||
// ))}
|
))}
|
||||||
// {filtered.length === 0 && (
|
{filtered.length === 0 && (
|
||||||
// <li className="text-zinc-500">No results found</li>
|
<li className="text-zinc-500">No results found</li>
|
||||||
// )}
|
)}
|
||||||
// </ul>
|
</ul>
|
||||||
// </section>
|
</section>
|
||||||
// </main>
|
</main>
|
||||||
// </div>
|
</div>
|
||||||
// </div>
|
</div>
|
||||||
// );
|
);
|
||||||
// }
|
}
|
||||||
+21
-21
@@ -1,24 +1,24 @@
|
|||||||
// import { NextResponse } from "next/server";
|
import { NextResponse } from "next/server";
|
||||||
// import { chatToGemini } from "@/app/utils/geminiHelper";
|
import { chatToGemini } from "@/app/utils/geminiHelper";
|
||||||
// import { ChatHistory, ChatSetting } from "@/app/exportType/types";
|
import { ChatHistory, ChatSetting } from "@/app/exportType/types";
|
||||||
|
|
||||||
|
|
||||||
// export async function POST(request: Request) {
|
export async function POST(request: Request) {
|
||||||
// try {
|
try {
|
||||||
// const { userMessage, history , settings } = await request.json() as {
|
const { userMessage, history, settings } = await request.json() as {
|
||||||
// userMessage :string;
|
userMessage: string;
|
||||||
// history : ChatHistory;
|
history: ChatHistory;
|
||||||
// settings : ChatSetting;
|
settings: ChatSetting;
|
||||||
// };
|
};
|
||||||
|
|
||||||
// const aiResponse = await chatToGemini(userMessage , history, settings);
|
const aiResponse = await chatToGemini(userMessage, history, settings);
|
||||||
// return NextResponse.json({response : aiResponse});
|
return NextResponse.json({ response: aiResponse });
|
||||||
// }
|
}
|
||||||
// catch(error){
|
catch (error) {
|
||||||
// console.error(error);
|
console.error(error);
|
||||||
// return NextResponse.json(
|
return NextResponse.json(
|
||||||
// {error: "Error with the model response "},
|
{ error: "Error with the model response " },
|
||||||
// {status : 500}
|
{ status: 500 }
|
||||||
// );
|
);
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
|
|||||||
@@ -1,23 +1,23 @@
|
|||||||
// import { NextResponse } from "next/server";
|
import { NextResponse } from "next/server";
|
||||||
// import { chatToGemini } from "@/app/utils/geminiHelper";
|
import { chatToGemini } from "@/app/utils/geminiHelper";
|
||||||
// import { ChatSetting } from "@/app/exportType/types";
|
import { ChatSetting } from "@/app/exportType/types";
|
||||||
|
|
||||||
|
|
||||||
// export async function POST(request: Request) {
|
export async function POST(request: Request) {
|
||||||
// try {
|
try {
|
||||||
// const { prompt, settings } = await request.json() as {
|
const { prompt, settings } = await request.json() as {
|
||||||
// prompt :string;
|
prompt: string;
|
||||||
// settings : ChatSetting;
|
settings: ChatSetting;
|
||||||
// };
|
};
|
||||||
|
|
||||||
// const aiResponse = await chatToGemini(prompt , [], settings);
|
const aiResponse = await chatToGemini(prompt, [], settings);
|
||||||
// return NextResponse.json({response : aiResponse});
|
return NextResponse.json({ response: aiResponse });
|
||||||
// }
|
}
|
||||||
// catch(error){
|
catch (error) {
|
||||||
// console.error(error);
|
console.error(error);
|
||||||
// return NextResponse.json(
|
return NextResponse.json(
|
||||||
// {error: "Error with the model response "},
|
{ error: "Error with the model response " },
|
||||||
// {status : 500}
|
{ status: 500 }
|
||||||
// );
|
);
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
|
|||||||
+189
-189
@@ -1,210 +1,210 @@
|
|||||||
// "use client";
|
"use client";
|
||||||
|
|
||||||
// import React, { useState, useEffect } from "react";
|
import React, { useState, useEffect } from "react";
|
||||||
// import { motion, useMotionValue, useTransform, useAnimation } from "framer-motion";
|
import { motion, useMotionValue, useTransform, useAnimation } from "framer-motion";
|
||||||
// import { useRouter } from "next/navigation";
|
import { useRouter } from "next/navigation";
|
||||||
|
|
||||||
// // 1. Updated ColorWay interface
|
// 1. Updated ColorWay interface
|
||||||
// interface ColorWay {
|
interface ColorWay {
|
||||||
// card: string;
|
card: string;
|
||||||
// text: string;
|
text: string;
|
||||||
// titleColor: string; // Added title color
|
titleColor: string; // Added title color
|
||||||
// }
|
}
|
||||||
|
|
||||||
// // 2. Updated COLOR_WAYS array
|
// 2. Updated COLOR_WAYS array
|
||||||
// const COLOR_WAYS: ColorWay[] = [
|
const COLOR_WAYS: ColorWay[] = [
|
||||||
// { card: "#FEEEDF", text: "#173C46", titleColor: "#173C46" },
|
{ card: "#FEEEDF", text: "#173C46", titleColor: "#173C46" },
|
||||||
// { card: "#FEEEDF", text: "#EA627F", titleColor: "#173C46" }, // Example: Title is dark, text is pink
|
{ card: "#FEEEDF", text: "#EA627F", titleColor: "#173C46" }, // Example: Title is dark, text is pink
|
||||||
// { card: "#DEE5D4", text: "#173C46", titleColor: "#EA627F" },
|
{ card: "#DEE5D4", text: "#173C46", titleColor: "#EA627F" },
|
||||||
// { card: "#DEE5D4", text: "#EA627F", titleColor: "#173C46" },
|
{ card: "#DEE5D4", text: "#EA627F", titleColor: "#173C46" },
|
||||||
// { card: "#B8C0AD", text: "#173C46", titleColor: "#173C46" },
|
{ card: "#B8C0AD", text: "#173C46", titleColor: "#173C46" },
|
||||||
// { card: "#B8C0AD", text: "#173C46", titleColor: "#EA627F" },
|
{ card: "#B8C0AD", text: "#173C46", titleColor: "#EA627F" },
|
||||||
// ];
|
];
|
||||||
|
|
||||||
// interface CardData {
|
interface CardData {
|
||||||
// id: number;
|
id: number;
|
||||||
// title: string;
|
title: string;
|
||||||
// summary: string;
|
summary: string;
|
||||||
// tracks: string[];
|
tracks: string[];
|
||||||
// }
|
}
|
||||||
|
|
||||||
// const SwipeCards: React.FC<{ initialCards: CardData[] }> = ({ initialCards }) => {
|
const SwipeCards: React.FC<{ initialCards: CardData[] }> = ({ initialCards }) => {
|
||||||
// const [cards, setCards] = useState<CardData[]>(initialCards);
|
const [cards, setCards] = useState<CardData[]>(initialCards);
|
||||||
// const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
// // Update cards state when initialCards prop changes
|
// Update cards state when initialCards prop changes
|
||||||
// useEffect(() => {
|
useEffect(() => {
|
||||||
// setCards(initialCards);
|
setCards(initialCards);
|
||||||
// }, [initialCards]);
|
}, [initialCards]);
|
||||||
|
|
||||||
// const removeCard = () => {
|
const removeCard = () => {
|
||||||
// setCards((prev) => prev.slice(0, prev.length - 1));
|
setCards((prev) => prev.slice(0, prev.length - 1));
|
||||||
// };
|
};
|
||||||
|
|
||||||
// const handleAccept = (cardData: CardData) => {
|
const handleAccept = (cardData: CardData) => {
|
||||||
// removeCard();
|
removeCard();
|
||||||
// // Redirect to chatbot with card data
|
// Redirect to chatbot with card data
|
||||||
// router.push(`/chatbot?title=${encodeURIComponent(cardData.title)}&summary=${encodeURIComponent(cardData.summary)}`);
|
router.push(`/chatbot?title=${encodeURIComponent(cardData.title)}&summary=${encodeURIComponent(cardData.summary)}`);
|
||||||
// };
|
};
|
||||||
|
|
||||||
// const handleReject = () => {
|
const handleReject = () => {
|
||||||
// removeCard();
|
removeCard();
|
||||||
// };
|
};
|
||||||
|
|
||||||
// const handleReset = () => {
|
const handleReset = () => {
|
||||||
// setCards([]); // Reset to initial cards
|
setCards([]); // Reset to initial cards
|
||||||
// };
|
};
|
||||||
|
|
||||||
// return (
|
return (
|
||||||
// <div
|
<div
|
||||||
// className="grid h-screen w-full place-items-center bg-orange-100"
|
className="grid h-screen w-full place-items-center bg-orange-100"
|
||||||
// // -gradient-to-tr from-orange-200 to-orange-100
|
// -gradient-to-tr from-orange-200 to-orange-100
|
||||||
// style={{
|
style={{
|
||||||
// backgroundImage: `url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg'
|
backgroundImage: `url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg'
|
||||||
// viewBox='0 0 32 32' width='32' height='32' fill='none'
|
viewBox='0 0 32 32' width='32' height='32' fill='none'
|
||||||
// stroke-width='2' stroke='%23d4d4d4'%3e%3cpath d='M0 .5H31.5V32'/%3e%3c/svg%3e")`,
|
stroke-width='2' stroke='%23d4d4d4'%3e%3cpath d='M0 .5H31.5V32'/%3e%3c/svg%3e")`,
|
||||||
// }}
|
}}
|
||||||
// >
|
>
|
||||||
// {cards.length > 0 ? (
|
{cards.length > 0 ? (
|
||||||
// cards.map((card, index) => {
|
cards.map((card, index) => {
|
||||||
// const colorWay = COLOR_WAYS[card.id % COLOR_WAYS.length];
|
const colorWay = COLOR_WAYS[card.id % COLOR_WAYS.length];
|
||||||
// return (
|
return (
|
||||||
// <Card
|
<Card
|
||||||
// key={card.id}
|
key={card.id}
|
||||||
// cardData={card}
|
cardData={card}
|
||||||
// colorWay={colorWay}
|
colorWay={colorWay}
|
||||||
// isFront={index === cards.length - 1}
|
isFront={index === cards.length - 1}
|
||||||
// onAccept={handleAccept}
|
onAccept={handleAccept}
|
||||||
// onReject={handleReject}
|
onReject={handleReject}
|
||||||
// />
|
/>
|
||||||
// );
|
);
|
||||||
// })
|
})
|
||||||
// ) : (
|
) : (
|
||||||
// // ... (empty state)
|
// ... (empty state)
|
||||||
// <div className="text-center">
|
<div className="text-center">
|
||||||
// <h2 className="text-2xl font-bold text-neutral-700">
|
<h2 className="text-2xl font-bold text-neutral-700">
|
||||||
// No more cards!
|
No more cards!
|
||||||
// </h2>
|
</h2>
|
||||||
// <p className="mb-4 text-neutral-500">
|
<p className="mb-4 text-neutral-500">
|
||||||
// You've swiped through them all.
|
You've swiped through them all.
|
||||||
// </p>
|
</p>
|
||||||
// <button
|
<button
|
||||||
// onClick={handleReset}
|
onClick={handleReset}
|
||||||
// className="rounded-md bg-indigo-500 px-4 py-2 font-semibold text-white transition-colors hover:bg-indigo-600"
|
className="rounded-md bg-indigo-500 px-4 py-2 font-semibold text-white transition-colors hover:bg-indigo-600"
|
||||||
// >
|
>
|
||||||
// Reset Deck
|
Reset Deck
|
||||||
// </button>
|
</button>
|
||||||
// </div>
|
</div>
|
||||||
// )}
|
)}
|
||||||
// </div>
|
</div>
|
||||||
// );
|
);
|
||||||
// };
|
};
|
||||||
|
|
||||||
// interface CardProps {
|
interface CardProps {
|
||||||
// cardData: CardData;
|
cardData: CardData;
|
||||||
// colorWay: ColorWay;
|
colorWay: ColorWay;
|
||||||
// isFront: boolean;
|
isFront: boolean;
|
||||||
// onAccept: (cardData: CardData) => void;
|
onAccept: (cardData: CardData) => void;
|
||||||
// onReject: () => void;
|
onReject: () => void;
|
||||||
// }
|
}
|
||||||
|
|
||||||
// const Card: React.FC<CardProps> = ({ cardData, colorWay, isFront, onAccept, onReject }) => {
|
const Card: React.FC<CardProps> = ({ cardData, colorWay, isFront, onAccept, onReject }) => {
|
||||||
// const { title, summary, tracks } = cardData;
|
const { title, summary, tracks } = cardData;
|
||||||
|
|
||||||
// const x = useMotionValue(0);
|
const x = useMotionValue(0);
|
||||||
// const rotate = useTransform(x, [-250, 250], [-25, 25]);
|
const rotate = useTransform(x, [-250, 250], [-25, 25]);
|
||||||
// const opacity = useTransform(
|
const opacity = useTransform(
|
||||||
// x,
|
x,
|
||||||
// [-250, -100, 0, 100, 250],
|
[-250, -100, 0, 100, 250],
|
||||||
// [0, 1, 1, 1, 0],
|
[0, 1, 1, 1, 0],
|
||||||
// );
|
);
|
||||||
// const controls = useAnimation();
|
const controls = useAnimation();
|
||||||
|
|
||||||
// const acceptOpacity = useTransform(x, [50, 150], [0, 1]);
|
const acceptOpacity = useTransform(x, [50, 150], [0, 1]);
|
||||||
// const rejectOpacity = useTransform(x, [-150, -50], [1, 0]);
|
const rejectOpacity = useTransform(x, [-150, -50], [1, 0]);
|
||||||
// const badgeRotate = useTransform(x, [-150, 150], [-15, 15]);
|
const badgeRotate = useTransform(x, [-150, 150], [-15, 15]);
|
||||||
|
|
||||||
// const handleDragEnd = async (event: MouseEvent | TouchEvent | PointerEvent, info: { offset: { x: number } }) => {
|
const handleDragEnd = async (event: MouseEvent | TouchEvent | PointerEvent, info: { offset: { x: number } }) => {
|
||||||
// if (info.offset.x > 100) {
|
if (info.offset.x > 100) {
|
||||||
// // Card accepted
|
// Card accepted
|
||||||
// await controls.start({ x: 1000, opacity: 0, transition: { duration: 0.1 } }); // Animate off-screen quickly
|
await controls.start({ x: 1000, opacity: 0, transition: { duration: 0.1 } }); // Animate off-screen quickly
|
||||||
// onAccept(cardData); // Then call onAccept which removes the card and redirects
|
onAccept(cardData); // Then call onAccept which removes the card and redirects
|
||||||
// } else if (info.offset.x < -100) {
|
} else if (info.offset.x < -100) {
|
||||||
// // Card rejected
|
// Card rejected
|
||||||
// await controls.start({ x: -1000, opacity: 0, transition: { duration: 0.1 } }); // Animate off-screen quickly
|
await controls.start({ x: -1000, opacity: 0, transition: { duration: 0.1 } }); // Animate off-screen quickly
|
||||||
// onReject(); // Then call onReject which removes the card
|
onReject(); // Then call onReject which removes the card
|
||||||
// } else {
|
} else {
|
||||||
// // Card not swiped far enough, snap back to center
|
// Card not swiped far enough, snap back to center
|
||||||
// controls.start({ x: 0, rotate: 0, opacity: 1, transition: { type: "spring", stiffness: 300, damping: 30 } });
|
controls.start({ x: 0, rotate: 0, opacity: 1, transition: { type: "spring", stiffness: 300, damping: 30 } });
|
||||||
// }
|
}
|
||||||
// };
|
};
|
||||||
|
|
||||||
// return (
|
return (
|
||||||
// <motion.div
|
<motion.div
|
||||||
// className="absolute flex h-[56rem] w-[42rem] flex-col justify-between overflow-hidden rounded-2xl p-6 shadow-2xl hover:cursor-grab active:cursor-grabbing"
|
className="absolute flex h-[56rem] w-[42rem] flex-col justify-between overflow-hidden rounded-2xl p-6 shadow-2xl hover:cursor-grab active:cursor-grabbing"
|
||||||
// style={{
|
style={{
|
||||||
// x,
|
x,
|
||||||
// rotate,
|
rotate,
|
||||||
// opacity,
|
opacity,
|
||||||
// backgroundColor: colorWay.card,
|
backgroundColor: colorWay.card,
|
||||||
// color: colorWay.text, // This is the default text color
|
color: colorWay.text, // This is the default text color
|
||||||
// zIndex: isFront ? 2 : 1,
|
zIndex: isFront ? 2 : 1,
|
||||||
// pointerEvents: isFront ? "auto" : "none",
|
pointerEvents: isFront ? "auto" : "none",
|
||||||
// }}
|
}}
|
||||||
// animate={controls}
|
animate={controls}
|
||||||
// transition={{ type: "spring", stiffness: 300, damping: 30 }}
|
transition={{ type: "spring", stiffness: 300, damping: 30 }}
|
||||||
// drag={isFront ? "x" : false}
|
drag={isFront ? "x" : false}
|
||||||
// dragConstraints={{ left: 0, right: 0, top: 0, bottom: 0 }}
|
dragConstraints={{ left: 0, right: 0, top: 0, bottom: 0 }}
|
||||||
// onDragEnd={handleDragEnd}
|
onDragEnd={handleDragEnd}
|
||||||
// >
|
>
|
||||||
// {/* Accept/Reject Badges */}
|
{/* Accept/Reject Badges */}
|
||||||
// <motion.div
|
<motion.div
|
||||||
// className="absolute left-10 top-10 z-10 rounded-2xl border-8 border-green-500 px-10 py-4"
|
className="absolute left-10 top-10 z-10 rounded-2xl border-8 border-green-500 px-10 py-4"
|
||||||
// style={{ opacity: acceptOpacity, rotate: badgeRotate }}
|
style={{ opacity: acceptOpacity, rotate: badgeRotate }}
|
||||||
// >
|
>
|
||||||
// <h3 className="text-5xl font-bold uppercase text-green-500">Accept</h3>
|
<h3 className="text-5xl font-bold uppercase text-green-500">Accept</h3>
|
||||||
// </motion.div>
|
</motion.div>
|
||||||
// <motion.div
|
<motion.div
|
||||||
// className="absolute right-10 top-10 z-10 rounded-2xl border-8 border-red-500 px-10 py-4"
|
className="absolute right-10 top-10 z-10 rounded-2xl border-8 border-red-500 px-10 py-4"
|
||||||
// style={{ opacity: rejectOpacity, rotate: badgeRotate }}
|
style={{ opacity: rejectOpacity, rotate: badgeRotate }}
|
||||||
// >
|
>
|
||||||
// <h3 className="text-5xl font-bold uppercase text-red-500">Reject</h3>
|
<h3 className="text-5xl font-bold uppercase text-red-500">Reject</h3>
|
||||||
// </motion.div>
|
</motion.div>
|
||||||
|
|
||||||
// {/* Card Content */}
|
{/* Card Content */}
|
||||||
// <div className="relative z-0">
|
<div className="relative z-0">
|
||||||
// {/* 3. Applied the specific titleColor here */}
|
{/* 3. Applied the specific titleColor here */}
|
||||||
// <h2
|
<h2
|
||||||
// className="mb-4 text-center text-3xl font-bold"
|
className="mb-4 text-center text-3xl font-bold"
|
||||||
// style={{ color: colorWay.titleColor }}
|
style={{ color: colorWay.titleColor }}
|
||||||
// >
|
>
|
||||||
// {title}
|
{title}
|
||||||
// </h2>
|
</h2>
|
||||||
// {/* This summary <p> will inherit colorWay.text from the parent */}
|
{/* This summary <p> will inherit colorWay.text from the parent */}
|
||||||
// <p className="text-center text-xl font-light">{summary}</p>
|
<p className="text-center text-xl font-light">{summary}</p>
|
||||||
// </div>
|
</div>
|
||||||
|
|
||||||
// <div className="relative z-0 flex flex-wrap items-center justify-center gap-2">
|
<div className="relative z-0 flex flex-wrap items-center justify-center gap-2">
|
||||||
// {tracks.slice(0, 2).map((track, index) => (
|
{tracks.slice(0, 2).map((track, index) => (
|
||||||
// <span
|
<span
|
||||||
// key={track}
|
key={track}
|
||||||
// className="flex items-center justify-center rounded-full px-8 py-3 text-sm font-medium"
|
className="flex items-center justify-center rounded-full px-8 py-3 text-sm font-medium"
|
||||||
// style={{
|
style={{
|
||||||
// // This logic now correctly contrasts with the main text color
|
// This logic now correctly contrasts with the main text color
|
||||||
// backgroundColor:
|
backgroundColor:
|
||||||
// colorWay.text === "#ffffff"
|
colorWay.text === "#ffffff"
|
||||||
// ? "rgba(255, 255, 255, 0.2)"
|
? "rgba(255, 255, 255, 0.2)"
|
||||||
// : "rgba(0, 0, 0, 0.15)",
|
: "rgba(0, 0, 0, 0.15)",
|
||||||
// }}
|
}}
|
||||||
// >
|
>
|
||||||
// {track}
|
{track}
|
||||||
// {index === 0 && tracks.length > 1 && ", "}
|
{index === 0 && tracks.length > 1 && ", "}
|
||||||
// </span>
|
</span>
|
||||||
// ))}
|
))}
|
||||||
// </div>
|
</div>
|
||||||
// </motion.div>
|
</motion.div>
|
||||||
// );
|
);
|
||||||
|
|
||||||
// };
|
};
|
||||||
|
|
||||||
// export default SwipeCards;
|
export default SwipeCards;
|
||||||
|
|||||||
+114
-114
@@ -1,135 +1,135 @@
|
|||||||
// "use client";
|
"use client";
|
||||||
|
|
||||||
// import { useState, useEffect, useRef, useCallback } from "react";
|
import { useState, useEffect, useRef, useCallback } from "react";
|
||||||
// import { useSearchParams } from "next/navigation";
|
import { useSearchParams } from "next/navigation";
|
||||||
// import ChatInput from "../utils/component/ui/ChatInput";
|
import ChatInput from "../utils/component/ui/ChatInput";
|
||||||
// import MessageWindow from "../utils/component/ui/MessageWindow";
|
import MessageWindow from "../utils/component/ui/MessageWindow";
|
||||||
// import { ChatHistory, ChatSetting, Message , MessageRole } from "@/app/exportType/types";
|
import { ChatHistory, ChatSetting, Message, MessageRole } from "@/app/exportType/types";
|
||||||
|
|
||||||
// export default function Home(){
|
export default function Home() {
|
||||||
// const [history, setHistory] = useState<ChatHistory>([])
|
const [history, setHistory] = useState<ChatHistory>([])
|
||||||
// const historyRef = useRef<ChatHistory>([]); // Create a ref for history
|
const historyRef = useRef<ChatHistory>([]); // Create a ref for history
|
||||||
// const [settings] = useState<ChatSetting>({
|
const [settings] = useState<ChatSetting>({
|
||||||
// temperature:1,
|
temperature: 1,
|
||||||
// model:"gemini-2.5-pro",
|
model: "gemini-2.5-pro",
|
||||||
// sysTemInstructions:"you are a ai helper. Your goal is to expand the project idea and interact with the user on any problem or question they have with the project. You are not allow to code the project for them and stray away from your job"
|
sysTemInstructions: "you are a ai helper. Your goal is to expand the project idea and interact with the user on any problem or question they have with the project. You are not allow to code the project for them and stray away from your job"
|
||||||
|
|
||||||
// });
|
|
||||||
// const searchParams = useSearchParams();
|
|
||||||
// const initialMessageSent = useRef(false);
|
|
||||||
|
|
||||||
// useEffect(() => {
|
});
|
||||||
// historyRef.current = history; // Keep the ref updated with the latest history
|
const searchParams = useSearchParams();
|
||||||
// }, [history]);
|
const initialMessageSent = useRef(false);
|
||||||
|
|
||||||
// const handleSend = useCallback(async(message:string)=>{
|
useEffect(() => {
|
||||||
// const newUserMessage:Message = {
|
historyRef.current = history; // Keep the ref updated with the latest history
|
||||||
// role:"user",
|
}, [history]);
|
||||||
// parts:[{text:message}],
|
|
||||||
// };
|
|
||||||
|
|
||||||
// setHistory(prevHistory => {
|
const handleSend = useCallback(async (message: string) => {
|
||||||
// const currentHistory = [...prevHistory, newUserMessage];
|
const newUserMessage: Message = {
|
||||||
|
role: "user",
|
||||||
// const sendApiRequest = async () => {
|
parts: [{ text: message }],
|
||||||
// try{
|
};
|
||||||
// const response = await fetch("/api/chat", {
|
|
||||||
// method: "POST",
|
|
||||||
// headers: {
|
|
||||||
// "Content-Type": "application/json",
|
|
||||||
// },
|
|
||||||
// body: JSON.stringify({
|
|
||||||
// userMessage: message,
|
|
||||||
// history: historyRef.current, // Use the ref for history
|
|
||||||
// settings: settings,
|
|
||||||
// }),
|
|
||||||
// });
|
|
||||||
|
|
||||||
// const data = await response.json();
|
setHistory(prevHistory => {
|
||||||
|
const currentHistory = [...prevHistory, newUserMessage];
|
||||||
|
|
||||||
// if (data.error) {
|
const sendApiRequest = async () => {
|
||||||
// console.error("AI Error:", data.error);
|
try {
|
||||||
// return;
|
const response = await fetch("/api/chat", {
|
||||||
// }
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
userMessage: message,
|
||||||
|
history: historyRef.current, // Use the ref for history
|
||||||
|
settings: settings,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
// const aiMessage: Message = {
|
const data = await response.json();
|
||||||
// role: "model" as MessageRole,
|
|
||||||
// parts: [{ text: data.response }],
|
|
||||||
// };
|
|
||||||
|
|
||||||
// setHistory(prevHistory => [...prevHistory, aiMessage]);
|
if (data.error) {
|
||||||
|
console.error("AI Error:", data.error);
|
||||||
// }
|
return;
|
||||||
// catch (error) {
|
}
|
||||||
// console.error("Request Failed:", error);
|
|
||||||
// }
|
|
||||||
// };
|
|
||||||
// sendApiRequest();
|
|
||||||
|
|
||||||
// return currentHistory;
|
const aiMessage: Message = {
|
||||||
// });
|
role: "model" as MessageRole,
|
||||||
// }, [settings]); // Now handleSend only depends on settings
|
parts: [{ text: data.response }],
|
||||||
|
};
|
||||||
|
|
||||||
// useEffect(() => {
|
setHistory(prevHistory => [...prevHistory, aiMessage]);
|
||||||
// if (!initialMessageSent.current) {
|
|
||||||
// const title = searchParams.get('title');
|
|
||||||
// const summary = searchParams.get('summary');
|
|
||||||
|
|
||||||
// if (title && summary) {
|
}
|
||||||
// const message = `Explain the project titled '${title}' with the summary '${summary}' in detail, and suggest suitable roles for a team working on it.`;
|
catch (error) {
|
||||||
|
console.error("Request Failed:", error);
|
||||||
// const newUserMessage: Message = {
|
}
|
||||||
// role: "user",
|
};
|
||||||
// parts: [{ text: message }],
|
sendApiRequest();
|
||||||
// };
|
|
||||||
|
|
||||||
// setTimeout(() => {
|
return currentHistory;
|
||||||
// setHistory((prevHistory) => [...prevHistory, newUserMessage]); // Add user message to history
|
});
|
||||||
// }, 0);
|
}, [settings]); // Now handleSend only depends on settings
|
||||||
|
|
||||||
// const sendInitialApiRequest = async () => {
|
useEffect(() => {
|
||||||
// try {
|
if (!initialMessageSent.current) {
|
||||||
// const response = await fetch("/api/chat", {
|
const title = searchParams.get('title');
|
||||||
// method: "POST",
|
const summary = searchParams.get('summary');
|
||||||
// headers: {
|
|
||||||
// "Content-Type": "application/json",
|
|
||||||
// },
|
|
||||||
// body: JSON.stringify({
|
|
||||||
// userMessage: message,
|
|
||||||
// history: [...historyRef.current, newUserMessage], // Use ref for history
|
|
||||||
// settings: settings,
|
|
||||||
// }),
|
|
||||||
// });
|
|
||||||
|
|
||||||
// const data = await response.json();
|
if (title && summary) {
|
||||||
|
const message = `Explain the project titled '${title}' with the summary '${summary}' in detail, and suggest suitable roles for a team working on it.`;
|
||||||
|
|
||||||
// if (data.error) {
|
const newUserMessage: Message = {
|
||||||
// console.error("AI Error:", data.error);
|
role: "user",
|
||||||
// return;
|
parts: [{ text: message }],
|
||||||
// }
|
};
|
||||||
|
|
||||||
// const aiMessage: Message = {
|
setTimeout(() => {
|
||||||
// role: "model" as MessageRole,
|
setHistory((prevHistory) => [...prevHistory, newUserMessage]); // Add user message to history
|
||||||
// parts: [{ text: data.response }],
|
}, 0);
|
||||||
// };
|
|
||||||
|
|
||||||
// setHistory((prevHistory) => [...prevHistory, aiMessage]);
|
const sendInitialApiRequest = async () => {
|
||||||
// } catch (error) {
|
try {
|
||||||
// console.error("Request Failed:", error);
|
const response = await fetch("/api/chat", {
|
||||||
// }
|
method: "POST",
|
||||||
// };
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
userMessage: message,
|
||||||
|
history: [...historyRef.current, newUserMessage], // Use ref for history
|
||||||
|
settings: settings,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
// sendInitialApiRequest();
|
const data = await response.json();
|
||||||
// initialMessageSent.current = true;
|
|
||||||
// }
|
if (data.error) {
|
||||||
// }
|
console.error("AI Error:", data.error);
|
||||||
// }, [searchParams, settings]); // Dependencies for this useEffect
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const aiMessage: Message = {
|
||||||
|
role: "model" as MessageRole,
|
||||||
|
parts: [{ text: data.response }],
|
||||||
|
};
|
||||||
|
|
||||||
|
setHistory((prevHistory) => [...prevHistory, aiMessage]);
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Request Failed:", error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
sendInitialApiRequest();
|
||||||
|
initialMessageSent.current = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [searchParams, settings]); // Dependencies for this useEffect
|
||||||
|
|
||||||
|
|
||||||
// return (
|
return (
|
||||||
// <div className="flex flex-col py-32">
|
<div className="flex flex-col py-32">
|
||||||
// <MessageWindow history={history} />
|
<MessageWindow history={history} />
|
||||||
// <ChatInput onSend={handleSend} onOpenSettings={() => {}} />
|
<ChatInput onSend={handleSend} onOpenSettings={() => { }} />
|
||||||
// </div>
|
</div>
|
||||||
// );
|
);
|
||||||
// }
|
}
|
||||||
@@ -0,0 +1,300 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import React, { useState } from "react";
|
||||||
|
import { motion, useMotionValue, useTransform } from "framer-motion";
|
||||||
|
|
||||||
|
// Removed local fallback JSX declaration — use the official React type definitions instead:
|
||||||
|
// install @types/react and @types/react-dom so JSX.IntrinsicElements is provided by those packages.
|
||||||
|
// 1. Updated ColorWay interface
|
||||||
|
interface ColorWay {
|
||||||
|
card: string;
|
||||||
|
text: string;
|
||||||
|
titleColor: string; // Added title color
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Updated COLOR_WAYS array
|
||||||
|
const COLOR_WAYS: ColorWay[] = [
|
||||||
|
{ card: "#FEEEDF", text: "#173C46", titleColor: "#173C46" },
|
||||||
|
{ card: "#FEEEDF", text: "#EA627F", titleColor: "#173C46" }, // Example: Title is dark, text is pink
|
||||||
|
{ card: "#DEE5D4", text: "#173C46", titleColor: "#EA627F" },
|
||||||
|
{ card: "#DEE5D4", text: "#EA627F", titleColor: "#173C46" },
|
||||||
|
{ card: "#B8C0AD", text: "#173C46", titleColor: "#173C46" },
|
||||||
|
{ card: "#B8C0AD", text: "#173C46", titleColor: "#EA627F" },
|
||||||
|
];
|
||||||
|
|
||||||
|
interface CardData {
|
||||||
|
id: number;
|
||||||
|
title: string;
|
||||||
|
summary: string;
|
||||||
|
tracks: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
const cardData: CardData[] = [
|
||||||
|
{
|
||||||
|
|
||||||
|
id: 1,
|
||||||
|
|
||||||
|
title: " WEBSITE",
|
||||||
|
|
||||||
|
summary:
|
||||||
|
|
||||||
|
"FFind out what makes GoonMAXXER unique.With this innovative website you will be able to explore various features and functionalities that set GoonMAXXER apart from the rest.",
|
||||||
|
|
||||||
|
tracks: ["Gemini", "Auth0", "VibeCODING", "SmellyMaxxing", "shitposting"],
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
|
||||||
|
id: 2,
|
||||||
|
|
||||||
|
title: "Intro to React",
|
||||||
|
|
||||||
|
summary:
|
||||||
|
|
||||||
|
"Learn the fundamentals of React, including components, state, and props.",
|
||||||
|
|
||||||
|
tracks: ["React", "JS", "Frontend"],
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
|
||||||
|
id: 3,
|
||||||
|
|
||||||
|
title: "State Management",
|
||||||
|
|
||||||
|
summary:
|
||||||
|
|
||||||
|
"Explore complex state solutions with Zustand, Redux, and Context API.",
|
||||||
|
|
||||||
|
tracks: ["React", "Zustand", "State"],
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
|
||||||
|
id: 4,
|
||||||
|
|
||||||
|
title: "Next.js 14",
|
||||||
|
|
||||||
|
summary: "Master the app router, server actions, and data fetching.",
|
||||||
|
|
||||||
|
tracks: ["Next.js", "React", "Fullstack"],
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
|
||||||
|
id: 5,
|
||||||
|
|
||||||
|
title: "UI/UX Principles",
|
||||||
|
|
||||||
|
summary:
|
||||||
|
|
||||||
|
"A complete guide to user-centric design, prototyping, and testing.",
|
||||||
|
|
||||||
|
tracks: ["Design", "UI", "UX"],
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
|
||||||
|
id: 6,
|
||||||
|
|
||||||
|
title: "Node.js Essentials",
|
||||||
|
|
||||||
|
summary:
|
||||||
|
|
||||||
|
"Build scalable, high-performance backend applications with Node.js.",
|
||||||
|
|
||||||
|
tracks: ["Node", "Backend", "JS"],
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
|
||||||
|
id: 7,
|
||||||
|
|
||||||
|
title: "TypeScript",
|
||||||
|
|
||||||
|
summary:
|
||||||
|
|
||||||
|
"Add static typing to your JavaScript projects for robust, large-scale apps.",
|
||||||
|
|
||||||
|
tracks: ["TypeScript", "JS", "DevOps"],
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
|
||||||
|
id: 8,
|
||||||
|
|
||||||
|
title: "Framer Motion",
|
||||||
|
|
||||||
|
summary: "Create production-ready animations for your React applications.",
|
||||||
|
|
||||||
|
tracks: ["React", "Animation", "Framer"],
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
].reverse();
|
||||||
|
|
||||||
|
const SwipeCards: React.FC = () => {
|
||||||
|
const [cards, setCards] = useState<CardData[]>(cardData);
|
||||||
|
|
||||||
|
const onSwipe = () => {
|
||||||
|
setCards((prev) => prev.slice(0, prev.length - 1));
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleReset = () => {
|
||||||
|
setCards(cardData);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className="grid h-screen w-full place-items-center bg-orange-100"
|
||||||
|
// -gradient-to-tr from-orange-200 to-orange-100
|
||||||
|
style={{
|
||||||
|
backgroundImage: `url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg'
|
||||||
|
viewBox='0 0 32 32' width='32' height='32' fill='none'
|
||||||
|
stroke-width='2' stroke='%23d4d4d4'%3e%3cpath d='M0 .5H31.5V32'/%3e%3c/svg%3e")`,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{cards.length > 0 ? (
|
||||||
|
cards.map((card, index) => {
|
||||||
|
const colorWay = COLOR_WAYS[card.id % COLOR_WAYS.length];
|
||||||
|
return (
|
||||||
|
<Card
|
||||||
|
key={card.id}
|
||||||
|
cardData={card}
|
||||||
|
colorWay={colorWay}
|
||||||
|
isFront={index === cards.length - 1}
|
||||||
|
onSwipe={onSwipe}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
})
|
||||||
|
) : (
|
||||||
|
// ... (empty state)
|
||||||
|
<div className="text-center">
|
||||||
|
<h2 className="text-2xl font-bold text-neutral-700">
|
||||||
|
No more cards!
|
||||||
|
</h2>
|
||||||
|
<p className="mb-4 text-neutral-500">
|
||||||
|
You've swiped through them all.
|
||||||
|
</p>
|
||||||
|
<button
|
||||||
|
onClick={handleReset}
|
||||||
|
className="rounded-md bg-indigo-500 px-4 py-2 font-semibold text-white transition-colors hover:bg-indigo-600"
|
||||||
|
>
|
||||||
|
Reset Deck
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
interface CardProps {
|
||||||
|
cardData: CardData;
|
||||||
|
colorWay: ColorWay;
|
||||||
|
isFront: boolean;
|
||||||
|
onSwipe: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Card: React.FC<CardProps> = ({ cardData, colorWay, isFront, onSwipe }) => {
|
||||||
|
const { title, summary, tracks } = cardData;
|
||||||
|
|
||||||
|
const x = useMotionValue(0);
|
||||||
|
const rotate = useTransform(x, [-250, 250], [-25, 25]);
|
||||||
|
const opacity = useTransform(
|
||||||
|
x,
|
||||||
|
[-250, -100, 0, 100, 250],
|
||||||
|
[0, 1, 1, 1, 0],
|
||||||
|
);
|
||||||
|
|
||||||
|
const acceptOpacity = useTransform(x, [50, 150], [0, 1]);
|
||||||
|
const rejectOpacity = useTransform(x, [-150, -50], [1, 0]);
|
||||||
|
const badgeRotate = useTransform(x, [-150, 150], [-15, 15]);
|
||||||
|
|
||||||
|
const handleDragEnd = (event: MouseEvent | TouchEvent | PointerEvent, info: { offset: { x: number } }) => {
|
||||||
|
if (Math.abs(info.offset.x) > 100) {
|
||||||
|
onSwipe();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<motion.div
|
||||||
|
className="absolute flex h-[48rem] w-[36rem] flex-col justify-between overflow-hidden rounded-2xl p-6 shadow-2xl hover:cursor-grab active:cursor-grabbing"
|
||||||
|
style={{
|
||||||
|
x,
|
||||||
|
rotate,
|
||||||
|
opacity,
|
||||||
|
backgroundColor: colorWay.card,
|
||||||
|
color: colorWay.text, // This is the default text color
|
||||||
|
zIndex: isFront ? 2 : 1,
|
||||||
|
pointerEvents: isFront ? "auto" : "none",
|
||||||
|
}}
|
||||||
|
animate={{
|
||||||
|
scale: isFront ? 1 : 0.95,
|
||||||
|
y: isFront ? 0 : -40,
|
||||||
|
}}
|
||||||
|
transition={{ type: "spring", stiffness: 300, damping: 30 }}
|
||||||
|
drag={isFront ? "x" : false}
|
||||||
|
dragConstraints={{ left: 0, right: 0, top: 0, bottom: 0 }}
|
||||||
|
onDragEnd={handleDragEnd}
|
||||||
|
>
|
||||||
|
{/* Accept/Reject Badges */}
|
||||||
|
<motion.div
|
||||||
|
className="absolute left-10 top-10 z-10 rounded-2xl border-8 border-green-500 px-10 py-4"
|
||||||
|
style={{ opacity: acceptOpacity, rotate: badgeRotate }}
|
||||||
|
>
|
||||||
|
<h3 className="text-5xl font-bold uppercase text-green-500">Accept</h3>
|
||||||
|
</motion.div>
|
||||||
|
<motion.div
|
||||||
|
className="absolute right-10 top-10 z-10 rounded-2xl border-8 border-red-500 px-10 py-4"
|
||||||
|
style={{ opacity: rejectOpacity, rotate: badgeRotate }}
|
||||||
|
>
|
||||||
|
<h3 className="text-5xl font-bold uppercase text-red-500">Reject</h3>
|
||||||
|
</motion.div>
|
||||||
|
|
||||||
|
{/* Card Content */}
|
||||||
|
<div className="relative z-0">
|
||||||
|
{/* 3. Applied the specific titleColor here */}
|
||||||
|
<h2
|
||||||
|
className="mb-4 text-center text-7xl font-bold"
|
||||||
|
style={{ color: colorWay.titleColor }}
|
||||||
|
>
|
||||||
|
{title}
|
||||||
|
</h2>
|
||||||
|
{/* This summary <p> will inherit colorWay.text from the parent */}
|
||||||
|
<p className="text-center text-3xl font-light">{summary}</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="relative z-0 flex flex-wrap items-center justify-center gap-2">
|
||||||
|
{/* This <h3> will also inherit colorWay.text */}
|
||||||
|
<h3 className="mb-4 w-full text-center text-4xl font-semibold">
|
||||||
|
Tracks
|
||||||
|
</h3>
|
||||||
|
{tracks.map((track) => (
|
||||||
|
<span
|
||||||
|
key={track}
|
||||||
|
className="flex items-center justify-center rounded-full px-8 py-3 text-2xl font-medium"
|
||||||
|
style={{
|
||||||
|
// This logic now correctly contrasts with the main text color
|
||||||
|
backgroundColor:
|
||||||
|
colorWay.text === "#ffffff"
|
||||||
|
? "rgba(255, 255, 255, 0.2)"
|
||||||
|
: "rgba(0, 0, 0, 0.15)",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{track}
|
||||||
|
</span>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</motion.div>
|
||||||
|
);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
export default SwipeCards;
|
||||||
@@ -4,32 +4,32 @@ import React from "react";
|
|||||||
import { useRouter } from "next/navigation";
|
import { useRouter } from "next/navigation";
|
||||||
|
|
||||||
export default function ProtectedNavButton({
|
export default function ProtectedNavButton({
|
||||||
children = "Go to Dashboard",
|
children = "Go to Dashboard",
|
||||||
className = "mt-4 inline-block w-fit px-6 py-3 bg-blue-600 hover:bg-blue-700 text-white font-medium rounded-md shadow-md transition-colors",
|
className = "mt-4 inline-block w-fit px-6 py-3 bg-blue-600 hover:bg-blue-700 text-white font-medium rounded-md shadow-md transition-colors",
|
||||||
}: {
|
}: {
|
||||||
children?: React.ReactNode;
|
children?: React.ReactNode;
|
||||||
className?: string;
|
className?: string;
|
||||||
}) {
|
}) {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
const handleClick = () => {
|
const handleClick = () => {
|
||||||
// Simple client-side auth check.
|
// Simple client-side auth check.
|
||||||
// Assumption: if localStorage has 'token' (or 'auth'), user is signed in.
|
// Assumption: if localStorage has 'token' (or 'auth'), user is signed in.
|
||||||
// Adjust key to match your real auth storage (cookie, localStorage key, etc.).
|
// Adjust key to match your real auth storage (cookie, localStorage key, etc.).
|
||||||
const token = typeof window !== "undefined" ? localStorage.getItem("token") : null;
|
const token = typeof window !== "undefined" ? localStorage.getItem("token") : null;
|
||||||
|
|
||||||
if (token) {
|
if (token) {
|
||||||
// The app route folder is named `Dashboard` (capital D).
|
// The app route folder is named `Dashboard` (capital D).
|
||||||
// Use the same path casing to avoid 404s on Next.js routes.
|
// Use the same path casing to avoid 404s on Next.js routes.
|
||||||
router.push("/Dashboard");
|
router.push("/Dashboard");
|
||||||
} else {
|
} else {
|
||||||
router.push("/auth/login");
|
router.push("/auth/login");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<button type="button" onClick={handleClick} className={className}>
|
<button type="button" onClick={handleClick} className={className}>
|
||||||
{children}
|
{children}
|
||||||
</button>
|
</button>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
+25
-25
@@ -1,30 +1,30 @@
|
|||||||
// export type MessageRole = "user" | "model";
|
export type MessageRole = "user" | "model";
|
||||||
|
|
||||||
// export type MessagePart = {
|
export type MessagePart = {
|
||||||
// text: string;
|
text: string;
|
||||||
// }
|
}
|
||||||
|
|
||||||
// export interface Message{
|
export interface Message {
|
||||||
// role: MessageRole;
|
role: MessageRole;
|
||||||
// parts:MessagePart[];
|
parts: MessagePart[];
|
||||||
// }
|
}
|
||||||
// export type ChatHistory = Message[];
|
export type ChatHistory = Message[];
|
||||||
|
|
||||||
// export interface GenerateConfig{
|
export interface GenerateConfig {
|
||||||
// temperature : number;
|
temperature: number;
|
||||||
// topP : number;
|
topP: number;
|
||||||
// responseMimeType : string;
|
responseMimeType: string;
|
||||||
// }
|
}
|
||||||
|
|
||||||
// export interface ChatSetting{
|
export interface ChatSetting {
|
||||||
// temperature :number;
|
temperature: number;
|
||||||
// model: string;
|
model: string;
|
||||||
// sysTemInstructions: string;
|
sysTemInstructions: string;
|
||||||
// }
|
}
|
||||||
|
|
||||||
// export interface CardData {
|
export interface CardData {
|
||||||
// id: number;
|
id: number;
|
||||||
// title: string;
|
title: string;
|
||||||
// tracks: string[];
|
tracks: string[];
|
||||||
// summary: string;
|
summary: string;
|
||||||
// }
|
}
|
||||||
+262
-262
@@ -1,294 +1,294 @@
|
|||||||
// "use client";
|
"use client";
|
||||||
|
|
||||||
// import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
|
|
||||||
// import {
|
import {
|
||||||
// FormData,
|
FormData,
|
||||||
// PROFICIENCY_LEVELS
|
PROFICIENCY_LEVELS
|
||||||
// } from './formTypes'; // Ensure path is correct
|
} from './formTypes'; // Ensure path is correct
|
||||||
|
|
||||||
// interface FormPageProps {
|
interface FormPageProps {
|
||||||
// onFormSubmit: (data: FormData) => void;
|
onFormSubmit: (data: FormData) => void;
|
||||||
// }
|
}
|
||||||
|
|
||||||
// const FormPage: React.FC<FormPageProps> = ({ onFormSubmit }) => {
|
const FormPage: React.FC<FormPageProps> = ({ onFormSubmit }) => {
|
||||||
// const [formData, setFormData] = useState<FormData>({
|
const [formData, setFormData] = useState<FormData>({
|
||||||
// Hackathon: '',
|
Hackathon: '',
|
||||||
// mainTheme: '',
|
mainTheme: '',
|
||||||
// tracksStack: [''],
|
tracksStack: [''],
|
||||||
// students: [{
|
students: [{
|
||||||
// studentName: '',
|
studentName: '',
|
||||||
// skills: [{ skillName: '', proficiency: PROFICIENCY_LEVELS[1] }]
|
skills: [{ skillName: '', proficiency: PROFICIENCY_LEVELS[1] }]
|
||||||
// }],
|
}],
|
||||||
// });
|
});
|
||||||
|
|
||||||
// const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
// setFormData({
|
setFormData({
|
||||||
// ...formData,
|
...formData,
|
||||||
// [event.target.name]: event.target.value,
|
[event.target.name]: event.target.value,
|
||||||
// });
|
});
|
||||||
// };
|
};
|
||||||
|
|
||||||
// const handleTracksChange = (event: React.ChangeEvent<HTMLInputElement>, index: number) => {
|
const handleTracksChange = (event: React.ChangeEvent<HTMLInputElement>, index: number) => {
|
||||||
// const newTracksStack = [...formData.tracksStack];
|
const newTracksStack = [...formData.tracksStack];
|
||||||
// newTracksStack[index] = event.target.value;
|
newTracksStack[index] = event.target.value;
|
||||||
|
|
||||||
// setFormData({
|
setFormData({
|
||||||
// ...formData,
|
...formData,
|
||||||
// tracksStack: newTracksStack,
|
tracksStack: newTracksStack,
|
||||||
// });
|
});
|
||||||
// };
|
};
|
||||||
|
|
||||||
// const handleAddTracks = () => {
|
const handleAddTracks = () => {
|
||||||
// setFormData({
|
setFormData({
|
||||||
// ...formData,
|
...formData,
|
||||||
// tracksStack: [...formData.tracksStack, ''],
|
tracksStack: [...formData.tracksStack, ''],
|
||||||
// });
|
});
|
||||||
// };
|
};
|
||||||
|
|
||||||
// const handleRemoveTracks = (index: number) => {
|
const handleRemoveTracks = (index: number) => {
|
||||||
// const newTracksStack = formData.tracksStack.filter((_, i) => i !== index);
|
const newTracksStack = formData.tracksStack.filter((_, i) => i !== index);
|
||||||
// setFormData({
|
setFormData({
|
||||||
// ...formData,
|
...formData,
|
||||||
// tracksStack: newTracksStack,
|
tracksStack: newTracksStack,
|
||||||
// });
|
});
|
||||||
// };
|
};
|
||||||
|
|
||||||
// const handleStudentNameChange = (e: React.ChangeEvent<HTMLInputElement>, studentIndex: number) => {
|
const handleStudentNameChange = (e: React.ChangeEvent<HTMLInputElement>, studentIndex: number) => {
|
||||||
// const newStudents = [...formData.students];
|
const newStudents = [...formData.students];
|
||||||
// newStudents[studentIndex].studentName = e.target.value;
|
newStudents[studentIndex].studentName = e.target.value;
|
||||||
// setFormData({ ...formData, students: newStudents });
|
setFormData({ ...formData, students: newStudents });
|
||||||
// };
|
};
|
||||||
|
|
||||||
// const handleAddStudent = () => {
|
const handleAddStudent = () => {
|
||||||
// setFormData({
|
setFormData({
|
||||||
// ...formData,
|
...formData,
|
||||||
// students: [...formData.students, { studentName: '', skills: [{ skillName: '', proficiency: PROFICIENCY_LEVELS[1] }] }]
|
students: [...formData.students, { studentName: '', skills: [{ skillName: '', proficiency: PROFICIENCY_LEVELS[1] }] }]
|
||||||
// });
|
});
|
||||||
// };
|
};
|
||||||
|
|
||||||
// const handleRemoveStudent = (studentIndex: number) => {
|
const handleRemoveStudent = (studentIndex: number) => {
|
||||||
// const newStudents = formData.students.filter((_, i) => i !== studentIndex);
|
const newStudents = formData.students.filter((_, i) => i !== studentIndex);
|
||||||
// setFormData({ ...formData, students: newStudents });
|
setFormData({ ...formData, students: newStudents });
|
||||||
// };
|
};
|
||||||
|
|
||||||
// const handleSkillChange = (
|
const handleSkillChange = (
|
||||||
// e: React.ChangeEvent<HTMLInputElement | HTMLSelectElement>,
|
e: React.ChangeEvent<HTMLInputElement | HTMLSelectElement>,
|
||||||
// studentIndex: number,
|
studentIndex: number,
|
||||||
// skillIndex: number
|
skillIndex: number
|
||||||
// ) => {
|
) => {
|
||||||
// const newStudents = [...formData.students];
|
const newStudents = [...formData.students];
|
||||||
// const targetName = e.target.name;
|
const targetName = e.target.name;
|
||||||
// const targetValue = e.target.value;
|
const targetValue = e.target.value;
|
||||||
|
|
||||||
// if (targetName === 'skillName') {
|
if (targetName === 'skillName') {
|
||||||
// newStudents[studentIndex].skills[skillIndex].skillName = targetValue;
|
newStudents[studentIndex].skills[skillIndex].skillName = targetValue;
|
||||||
// } else if (targetName === 'proficiency') {
|
} else if (targetName === 'proficiency') {
|
||||||
// newStudents[studentIndex].skills[skillIndex].proficiency = targetValue;
|
newStudents[studentIndex].skills[skillIndex].proficiency = targetValue;
|
||||||
// }
|
}
|
||||||
|
|
||||||
// setFormData({ ...formData, students: newStudents });
|
setFormData({ ...formData, students: newStudents });
|
||||||
// };
|
};
|
||||||
|
|
||||||
// const handleAddSkill = (studentIndex: number) => {
|
const handleAddSkill = (studentIndex: number) => {
|
||||||
// const newStudents = [...formData.students];
|
const newStudents = [...formData.students];
|
||||||
// newStudents[studentIndex].skills.push({ skillName: '', proficiency: PROFICIENCY_LEVELS[1] });
|
newStudents[studentIndex].skills.push({ skillName: '', proficiency: PROFICIENCY_LEVELS[1] });
|
||||||
// setFormData({ ...formData, students: newStudents });
|
setFormData({ ...formData, students: newStudents });
|
||||||
// };
|
};
|
||||||
|
|
||||||
// const handleRemoveSkill = (studentIndex: number, skillIndex: number) => {
|
const handleRemoveSkill = (studentIndex: number, skillIndex: number) => {
|
||||||
// const newStudents = [...formData.students];
|
const newStudents = [...formData.students];
|
||||||
// newStudents[studentIndex].skills = newStudents[studentIndex].skills.filter((_, i) => i !== skillIndex);
|
newStudents[studentIndex].skills = newStudents[studentIndex].skills.filter((_, i) => i !== skillIndex);
|
||||||
// setFormData({ ...formData, students: newStudents });
|
setFormData({ ...formData, students: newStudents });
|
||||||
// };
|
};
|
||||||
|
|
||||||
// const handleSubmit = (event: React.FormEvent) => {
|
const handleSubmit = (event: React.FormEvent) => {
|
||||||
// event.preventDefault();
|
event.preventDefault();
|
||||||
// onFormSubmit(formData); // Call the prop function with formData
|
onFormSubmit(formData); // Call the prop function with formData
|
||||||
// };
|
};
|
||||||
|
|
||||||
// return (
|
return (
|
||||||
// <div className="min-h-screen bg-gray-50 flex items-start justify-center p-4 sm:p-6 font-inter">
|
<div className="min-h-screen bg-gray-50 flex items-start justify-center p-4 sm:p-6 font-inter">
|
||||||
// <div className="w-full max-w-2xl bg-white p-8 shadow-2xl rounded-xl mt-8">
|
<div className="w-full max-w-2xl bg-white p-8 shadow-2xl rounded-xl mt-8">
|
||||||
// <h1 className="text-3xl font-extrabold text-center text-gray-800 mb-8 tracking-tight">
|
<h1 className="text-3xl font-extrabold text-center text-gray-800 mb-8 tracking-tight">
|
||||||
// Generate Project Idea
|
Generate Project Idea
|
||||||
// </h1>
|
</h1>
|
||||||
|
|
||||||
// <form className="space-y-8" onSubmit={handleSubmit}>
|
<form className="space-y-8" onSubmit={handleSubmit}>
|
||||||
// <div className="space-y-6 border-b pb-6 border-gray-200">
|
<div className="space-y-6 border-b pb-6 border-gray-200">
|
||||||
// <h2 className="text-xl font-bold text-gray-700">Project Context</h2>
|
<h2 className="text-xl font-bold text-gray-700">Project Context</h2>
|
||||||
// <div>
|
<div>
|
||||||
// <label htmlFor="hackathonName" className="block text-sm font-medium text-gray-700 mb-1">
|
<label htmlFor="hackathonName" className="block text-sm font-medium text-gray-700 mb-1">
|
||||||
// Hackathon Name
|
Hackathon Name
|
||||||
// </label>
|
</label>
|
||||||
// <input
|
<input
|
||||||
// id="hackathonName"
|
id="hackathonName"
|
||||||
// required
|
required
|
||||||
// type="text"
|
type="text"
|
||||||
// placeholder="e.g., Google Code Jam"
|
placeholder="e.g., Google Code Jam"
|
||||||
// name="Hackathon"
|
name="Hackathon"
|
||||||
// value={formData.Hackathon}
|
value={formData.Hackathon}
|
||||||
// onChange={handleChange}
|
onChange={handleChange}
|
||||||
// className="mt-1 block w-full px-4 py-2 border border-gray-300 rounded-lg shadow-sm focus:ring-blue-500 focus:border-blue-500 transition duration-150"
|
className="mt-1 block w-full px-4 py-2 border border-gray-300 rounded-lg shadow-sm focus:ring-blue-500 focus:border-blue-500 transition duration-150"
|
||||||
// />
|
/>
|
||||||
// </div>
|
</div>
|
||||||
|
|
||||||
// <div>
|
<div>
|
||||||
// <label htmlFor="mainTheme" className="block text-sm font-medium text-gray-700 mb-1">
|
<label htmlFor="mainTheme" className="block text-sm font-medium text-gray-700 mb-1">
|
||||||
// Main Theme
|
Main Theme
|
||||||
// </label>
|
</label>
|
||||||
// <input
|
<input
|
||||||
// id="mainTheme"
|
id="mainTheme"
|
||||||
// required
|
required
|
||||||
// type="text"
|
type="text"
|
||||||
// placeholder="e.g., Sustainability or AI Ethics"
|
placeholder="e.g., Sustainability or AI Ethics"
|
||||||
// name="mainTheme"
|
name="mainTheme"
|
||||||
// value={formData.mainTheme}
|
value={formData.mainTheme}
|
||||||
// onChange={handleChange}
|
onChange={handleChange}
|
||||||
// className="mt-1 block w-full px-4 py-2 border border-gray-300 rounded-lg shadow-sm focus:ring-blue-500 focus:border-blue-500 transition duration-150"
|
className="mt-1 block w-full px-4 py-2 border border-gray-300 rounded-lg shadow-sm focus:ring-blue-500 focus:border-blue-500 transition duration-150"
|
||||||
// />
|
/>
|
||||||
// </div>
|
</div>
|
||||||
// </div>
|
</div>
|
||||||
|
|
||||||
// <div className="space-y-4 border-b pb-6 border-gray-200">
|
<div className="space-y-4 border-b pb-6 border-gray-200">
|
||||||
// <label className="block text-xl font-bold text-gray-700">
|
<label className="block text-xl font-bold text-gray-700">
|
||||||
// Tracks Stack
|
Tracks Stack
|
||||||
// </label>
|
</label>
|
||||||
// <div className="space-y-3">
|
<div className="space-y-3">
|
||||||
// {formData.tracksStack.map((tracks, index) => (
|
{formData.tracksStack.map((tracks, index) => (
|
||||||
// <div key={index} className="flex gap-2 items-center">
|
<div key={index} className="flex gap-2 items-center">
|
||||||
// <input
|
<input
|
||||||
// type="text"
|
type="text"
|
||||||
// required
|
required
|
||||||
// placeholder={`Tracks #${index + 1}`}
|
placeholder={`Tracks #${index + 1}`}
|
||||||
// name={`tracksStack-${index}`}
|
name={`tracksStack-${index}`}
|
||||||
// value={tracks}
|
value={tracks}
|
||||||
// onChange={(e) => handleTracksChange(e, index)}
|
onChange={(e) => handleTracksChange(e, index)}
|
||||||
// className="flex-grow px-4 py-2 border border-gray-300 rounded-lg shadow-sm focus:ring-green-500 focus:border-green-500 transition duration-150"
|
className="flex-grow px-4 py-2 border border-gray-300 rounded-lg shadow-sm focus:ring-green-500 focus:border-green-500 transition duration-150"
|
||||||
// />
|
/>
|
||||||
// {formData.tracksStack.length > 1 && (
|
{formData.tracksStack.length > 1 && (
|
||||||
// <button
|
<button
|
||||||
// type="button"
|
type="button"
|
||||||
// onClick={() => handleRemoveTracks(index)}
|
onClick={() => handleRemoveTracks(index)}
|
||||||
// className="text-sm px-3 py-2 bg-red-500 text-white rounded-lg hover:bg-red-600 transition duration-150 flex-shrink-0"
|
className="text-sm px-3 py-2 bg-red-500 text-white rounded-lg hover:bg-red-600 transition duration-150 flex-shrink-0"
|
||||||
// aria-label={`Remove tracks ${index + 1}`}
|
aria-label={`Remove tracks ${index + 1}`}
|
||||||
// >
|
>
|
||||||
// Remove
|
Remove
|
||||||
// </button>
|
</button>
|
||||||
// )}
|
)}
|
||||||
// </div>
|
</div>
|
||||||
// ))}
|
))}
|
||||||
// </div>
|
</div>
|
||||||
|
|
||||||
// <button
|
<button
|
||||||
// type="button"
|
type="button"
|
||||||
// onClick={handleAddTracks}
|
onClick={handleAddTracks}
|
||||||
// className="flex items-center justify-center gap-1 py-2 px-4 border border-transparent rounded-lg shadow-sm text-sm font-medium text-white bg-green-600 hover:bg-green-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-green-500 transition duration-150"
|
className="flex items-center justify-center gap-1 py-2 px-4 border border-transparent rounded-lg shadow-sm text-sm font-medium text-white bg-green-600 hover:bg-green-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-green-500 transition duration-150"
|
||||||
// >
|
>
|
||||||
// <svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M12 6v6m0 0v6m0-6h6m-6 0H6"></path></svg>
|
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M12 6v6m0 0v6m0-6h6m-6 0H6"></path></svg>
|
||||||
// Add Tracks
|
Add Tracks
|
||||||
// </button>
|
</button>
|
||||||
// </div>
|
</div>
|
||||||
|
|
||||||
// <div className="space-y-4">
|
<div className="space-y-4">
|
||||||
// <h2 className="text-xl font-bold text-gray-700">Team Members and Skills</h2>
|
<h2 className="text-xl font-bold text-gray-700">Team Members and Skills</h2>
|
||||||
|
|
||||||
// <div className="space-y-6">
|
<div className="space-y-6">
|
||||||
// {formData.students.map((student, studentIndex) => (
|
{formData.students.map((student, studentIndex) => (
|
||||||
// <div key={studentIndex} className="p-4 border-2 border-indigo-200 rounded-lg bg-indigo-50 shadow-inner space-y-4">
|
<div key={studentIndex} className="p-4 border-2 border-indigo-200 rounded-lg bg-indigo-50 shadow-inner space-y-4">
|
||||||
|
|
||||||
// <div className="flex justify-between items-center pb-2 border-b border-indigo-300">
|
<div className="flex justify-between items-center pb-2 border-b border-indigo-300">
|
||||||
// <h4 className="text-lg font-semibold text-indigo-700">Student #{studentIndex + 1}</h4>
|
<h4 className="text-lg font-semibold text-indigo-700">Student #{studentIndex + 1}</h4>
|
||||||
// {formData.students.length > 1 && (
|
{formData.students.length > 1 && (
|
||||||
// <button
|
<button
|
||||||
// type="button"
|
type="button"
|
||||||
// onClick={() => handleRemoveStudent(studentIndex)}
|
onClick={() => handleRemoveStudent(studentIndex)}
|
||||||
// className="text-xs px-2 py-1 bg-red-400 text-white rounded-md hover:bg-red-500 transition duration-150"
|
className="text-xs px-2 py-1 bg-red-400 text-white rounded-md hover:bg-red-500 transition duration-150"
|
||||||
// >
|
>
|
||||||
// Remove Student
|
Remove Student
|
||||||
// </button>
|
</button>
|
||||||
// )}
|
)}
|
||||||
// </div>
|
</div>
|
||||||
|
|
||||||
// <div>
|
<div>
|
||||||
// <label className="block text-sm font-medium text-indigo-700 mb-1">Student Name</label>
|
<label className="block text-sm font-medium text-indigo-700 mb-1">Student Name</label>
|
||||||
// <input
|
<input
|
||||||
// type="text"
|
type="text"
|
||||||
// required
|
required
|
||||||
// placeholder="Student Name"
|
placeholder="Student Name"
|
||||||
// value={student.studentName}
|
value={student.studentName}
|
||||||
// onChange={(e) => handleStudentNameChange(e, studentIndex)}
|
onChange={(e) => handleStudentNameChange(e, studentIndex)}
|
||||||
// className="w-full px-4 py-2 border border-indigo-300 rounded-lg shadow-sm focus:ring-indigo-500 focus:border-indigo-500"
|
className="w-full px-4 py-2 border border-indigo-300 rounded-lg shadow-sm focus:ring-indigo-500 focus:border-indigo-500"
|
||||||
// />
|
/>
|
||||||
// </div>
|
</div>
|
||||||
|
|
||||||
// <div className="space-y-3 p-3 bg-white rounded-lg border border-indigo-100">
|
<div className="space-y-3 p-3 bg-white rounded-lg border border-indigo-100">
|
||||||
// <h5 className="text-md font-medium text-indigo-700">Skills</h5>
|
<h5 className="text-md font-medium text-indigo-700">Skills</h5>
|
||||||
// {student.skills.map((skill, skillIndex) => (
|
{student.skills.map((skill, skillIndex) => (
|
||||||
// <div key={skillIndex} className="flex gap-2 items-center">
|
<div key={skillIndex} className="flex gap-2 items-center">
|
||||||
// <input
|
<input
|
||||||
// type="text"
|
type="text"
|
||||||
// required
|
required
|
||||||
// name="skillName"
|
name="skillName"
|
||||||
// placeholder="Skill (e.g., React, Python)"
|
placeholder="Skill (e.g., React, Python)"
|
||||||
// value={skill.skillName}
|
value={skill.skillName}
|
||||||
// onChange={(e) => handleSkillChange(e, studentIndex, skillIndex)}
|
onChange={(e) => handleSkillChange(e, studentIndex, skillIndex)}
|
||||||
// className="flex-grow px-3 py-2 border border-gray-300 rounded-lg text-sm focus:ring-purple-500 focus:border-purple-500"
|
className="flex-grow px-3 py-2 border border-gray-300 rounded-lg text-sm focus:ring-purple-500 focus:border-purple-500"
|
||||||
// />
|
/>
|
||||||
// <select
|
<select
|
||||||
// name="proficiency"
|
name="proficiency"
|
||||||
// value={skill.proficiency}
|
value={skill.proficiency}
|
||||||
// onChange={(e) => handleSkillChange(e, studentIndex, skillIndex)}
|
onChange={(e) => handleSkillChange(e, studentIndex, skillIndex)}
|
||||||
// className="px-3 py-2 border border-gray-300 rounded-lg text-sm focus:ring-purple-500 focus:border-purple-500 w-1/3"
|
className="px-3 py-2 border border-gray-300 rounded-lg text-sm focus:ring-purple-500 focus:border-purple-500 w-1/3"
|
||||||
// >
|
>
|
||||||
// {PROFICIENCY_LEVELS.map(level => (
|
{PROFICIENCY_LEVELS.map(level => (
|
||||||
// <option key={level} value={level}>{level}</option>
|
<option key={level} value={level}>{level}</option>
|
||||||
// ))}
|
))}
|
||||||
// </select>
|
</select>
|
||||||
// {student.skills.length > 1 && (
|
{student.skills.length > 1 && (
|
||||||
// <button
|
<button
|
||||||
// type="button"
|
type="button"
|
||||||
// onClick={() => handleRemoveSkill(studentIndex, skillIndex)}
|
onClick={() => handleRemoveSkill(studentIndex, skillIndex)}
|
||||||
// className="text-xs px-2 py-1 bg-red-500 text-white rounded-md hover:bg-red-600 transition duration-150 flex-shrink-0"
|
className="text-xs px-2 py-1 bg-red-500 text-white rounded-md hover:bg-red-600 transition duration-150 flex-shrink-0"
|
||||||
// >
|
>
|
||||||
// X
|
X
|
||||||
// </button>
|
</button>
|
||||||
// )}
|
)}
|
||||||
// </div>
|
</div>
|
||||||
// ))}
|
))}
|
||||||
// <button
|
<button
|
||||||
// type="button"
|
type="button"
|
||||||
// onClick={() => handleAddSkill(studentIndex)}
|
onClick={() => handleAddSkill(studentIndex)}
|
||||||
// className="mt-2 text-xs flex items-center gap-1 py-1 px-3 border border-transparent rounded-lg text-white bg-purple-600 hover:bg-purple-700 transition duration-150"
|
className="mt-2 text-xs flex items-center gap-1 py-1 px-3 border border-transparent rounded-lg text-white bg-purple-600 hover:bg-purple-700 transition duration-150"
|
||||||
// >
|
>
|
||||||
// + Add Skill
|
+ Add Skill
|
||||||
// </button>
|
</button>
|
||||||
// </div>
|
</div>
|
||||||
// </div>
|
</div>
|
||||||
// ))}
|
))}
|
||||||
// </div>
|
</div>
|
||||||
|
|
||||||
// <button
|
<button
|
||||||
// type="button"
|
type="button"
|
||||||
// onClick={handleAddStudent}
|
onClick={handleAddStudent}
|
||||||
// className="mt-4 w-full flex items-center justify-center gap-2 py-2 px-4 border border-transparent rounded-lg shadow-sm font-medium text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 transition duration-150"
|
className="mt-4 w-full flex items-center justify-center gap-2 py-2 px-4 border border-transparent rounded-lg shadow-sm font-medium text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 transition duration-150"
|
||||||
// >
|
>
|
||||||
// <svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M18 9v3m0 0v3m0-3h3m-3 0h-3m-2-5a4 4 0 11-8 0 4 4 0 018 0zM3 20a6 6 0 0112 0v1H3v-1z"></path></svg>
|
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M18 9v3m0 0v3m0-3h3m-3 0h-3m-2-5a4 4 0 11-8 0 4 4 0 018 0zM3 20a6 6 0 0112 0v1H3v-1z"></path></svg>
|
||||||
// Add Team Member
|
Add Team Member
|
||||||
// </button>
|
</button>
|
||||||
// </div>
|
</div>
|
||||||
|
|
||||||
// <button
|
<button
|
||||||
// type="submit"
|
type="submit"
|
||||||
// className="w-full flex justify-center py-3 px-4 border border-transparent rounded-lg shadow-lg text-lg font-semibold text-white bg-blue-600 hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 transition duration-150 mt-6"
|
className="w-full flex justify-center py-3 px-4 border border-transparent rounded-lg shadow-lg text-lg font-semibold text-white bg-blue-600 hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 transition duration-150 mt-6"
|
||||||
// >
|
>
|
||||||
// Generate Idea
|
Generate Idea
|
||||||
// </button>
|
</button>
|
||||||
// </form>
|
</form>
|
||||||
|
|
||||||
// </div>
|
</div>
|
||||||
// </div>
|
</div>
|
||||||
// );
|
);
|
||||||
// };
|
};
|
||||||
|
|
||||||
// export default FormPage;
|
export default FormPage;
|
||||||
+18
-18
@@ -1,21 +1,21 @@
|
|||||||
// // Define Skill structure
|
// Define Skill structure
|
||||||
// export interface Skill {
|
export interface Skill {
|
||||||
// skillName: string;
|
skillName: string;
|
||||||
// proficiency: string;
|
proficiency: string;
|
||||||
// }
|
}
|
||||||
|
|
||||||
// // Define Student structure
|
// Define Student structure
|
||||||
// export interface Student {
|
export interface Student {
|
||||||
// studentName: string;
|
studentName: string;
|
||||||
// skills: Skill[];
|
skills: Skill[];
|
||||||
// }
|
}
|
||||||
|
|
||||||
// // Updated main form interface
|
// Updated main form interface
|
||||||
// export interface FormData {
|
export interface FormData {
|
||||||
// Hackathon: string;
|
Hackathon: string;
|
||||||
// mainTheme: string;
|
mainTheme: string;
|
||||||
// tracksStack: string[];
|
tracksStack: string[];
|
||||||
// students: Student[]; // Array for dynamic students
|
students: Student[]; // Array for dynamic students
|
||||||
// }
|
}
|
||||||
|
|
||||||
// export const PROFICIENCY_LEVELS = ['Beginner', 'Intermediate', 'Expert', 'Master'];
|
export const PROFICIENCY_LEVELS = ['Beginner', 'Intermediate', 'Expert', 'Master'];
|
||||||
@@ -1,71 +1,71 @@
|
|||||||
// import { GoogleGenerativeAI } from "@google/generative-ai";
|
import { GoogleGenerativeAI } from "@google/generative-ai";
|
||||||
// import type { NextApiRequest, NextApiResponse } from 'next';
|
import type { NextApiRequest, NextApiResponse } from 'next';
|
||||||
|
|
||||||
// // Initialize the Gemini Client with your API Key
|
// Initialize the Gemini Client with your API Key
|
||||||
// // IMPORTANT: The GEMINI_API_KEY should be an environment variable.
|
// IMPORTANT: The GEMINI_API_KEY should be an environment variable.
|
||||||
// const apiKey = process.env.GEMINI_API_KEY;
|
const apiKey = process.env.GEMINI_API_KEY;
|
||||||
|
|
||||||
// if(!apiKey){
|
if (!apiKey) {
|
||||||
// throw new Error("api key not found");
|
throw new Error("api key not found");
|
||||||
// }
|
}
|
||||||
// const ai = new GoogleGenerativeAI(apiKey);
|
const ai = new GoogleGenerativeAI(apiKey);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// // Define the handler function for the API route
|
// Define the handler function for the API route
|
||||||
// export default async function handler(
|
export default async function handler(
|
||||||
// req: NextApiRequest,
|
req: NextApiRequest,
|
||||||
// res: NextApiResponse
|
res: NextApiResponse
|
||||||
// ) {
|
) {
|
||||||
// // Only allow POST requests
|
// Only allow POST requests
|
||||||
// if (req.method !== 'POST') {
|
if (req.method !== 'POST') {
|
||||||
// return res.status(405).json({ error: 'Method Not Allowed' });
|
return res.status(405).json({ error: 'Method Not Allowed' });
|
||||||
// }
|
}
|
||||||
|
|
||||||
// // Destructure the data sent from the frontend
|
// Destructure the data sent from the frontend
|
||||||
// let { prompt, settings } = req.body;
|
let { prompt, settings } = req.body;
|
||||||
|
|
||||||
// // Basic validation
|
|
||||||
// if (!prompt || typeof prompt !== 'string') {
|
|
||||||
// return res.status(400).json({ error: 'Prompt is required' });
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // Modify the prompt to instruct the AI to generate only the game, concept, and track
|
// Basic validation
|
||||||
// prompt = `You're going to fill out a card base off the document.
|
if (!prompt || typeof prompt !== 'string') {
|
||||||
// you will Generate the project short title.
|
return res.status(400).json({ error: 'Prompt is required' });
|
||||||
// you will list out the track you used ${prompt}`;
|
}
|
||||||
|
|
||||||
// try {
|
// Modify the prompt to instruct the AI to generate only the game, concept, and track
|
||||||
// // 1. Call the Gemini API using the correct method signature
|
prompt = `You're going to fill out a card base off the document.
|
||||||
|
you will Generate the project short title.
|
||||||
// const model = settings?.model || 'gemini-2.5-flash-lite';
|
you will list out the track you used ${prompt}`;
|
||||||
// const generativeModel = ai.getGenerativeModel({ model });
|
|
||||||
|
|
||||||
// // 1. Define the generation configuration object
|
try {
|
||||||
// const generationConfig = {
|
// 1. Call the Gemini API using the correct method signature
|
||||||
// temperature: settings?.temperature || 0.9,
|
|
||||||
// // The SDK property name for system instructions is 'systemInstruction'
|
|
||||||
// systemInstruction: settings?.sysTemInstructions,
|
|
||||||
// };
|
|
||||||
|
|
||||||
// // 2. Call generateContent with the single GenerateContentRequest object.
|
const model = settings?.model || 'gemini-2.5-flash-lite';
|
||||||
// const result = await generativeModel.generateContent({
|
const generativeModel = ai.getGenerativeModel({ model });
|
||||||
// // contents must be an array of Content objects
|
|
||||||
// contents: [{
|
|
||||||
// role: "user",
|
|
||||||
// parts: [{ text: prompt }]
|
|
||||||
// }],
|
|
||||||
|
|
||||||
// // The fixed property name that resolves the TypeScript error
|
|
||||||
// generationConfig: generationConfig,
|
|
||||||
// });
|
|
||||||
|
|
||||||
// // 2. Extract the response text
|
// 1. Define the generation configuration object
|
||||||
// // The result object now contains a property 'text' at the top level for simple text generation
|
const generationConfig = {
|
||||||
// const geminiResponseText = result.response.text(); res.status(200).json({ response: geminiResponseText });
|
temperature: settings?.temperature || 0.9,
|
||||||
|
// The SDK property name for system instructions is 'systemInstruction'
|
||||||
|
systemInstruction: settings?.sysTemInstructions,
|
||||||
|
};
|
||||||
|
|
||||||
// } catch (error) {
|
// 2. Call generateContent with the single GenerateContentRequest object.
|
||||||
// console.error("Gemini API Error:", error);
|
const result = await generativeModel.generateContent({
|
||||||
// res.status(500).json({ error: 'Failed to generate idea from AI.' });
|
// contents must be an array of Content objects
|
||||||
// }
|
contents: [{
|
||||||
// }
|
role: "user",
|
||||||
|
parts: [{ text: prompt }]
|
||||||
|
}],
|
||||||
|
|
||||||
|
// The fixed property name that resolves the TypeScript error
|
||||||
|
generationConfig: generationConfig,
|
||||||
|
});
|
||||||
|
|
||||||
|
// 2. Extract the response text
|
||||||
|
// The result object now contains a property 'text' at the top level for simple text generation
|
||||||
|
const geminiResponseText = result.response.text(); res.status(200).json({ response: geminiResponseText });
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Gemini API Error:", error);
|
||||||
|
res.status(500).json({ error: 'Failed to generate idea from AI.' });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
+159
-159
@@ -1,172 +1,172 @@
|
|||||||
// "use client";
|
"use client";
|
||||||
// import React, { useState, useEffect, useCallback } from "react";
|
import React, { useState, useEffect, useCallback } from "react";
|
||||||
// import FormPage from './FormPage';
|
import FormPage from './FormPage';
|
||||||
// import { ChatSetting } from "../exportType/types";
|
import { ChatSetting } from "../exportType/types";
|
||||||
// import { FormData, PROFICIENCY_LEVELS } from './formTypes';
|
import { FormData, PROFICIENCY_LEVELS } from './formTypes';
|
||||||
|
|
||||||
// // --- Helper function to get default form data ---
|
// --- Helper function to get default form data ---
|
||||||
// const getDefaultFormData = (): FormData => ({
|
const getDefaultFormData = (): FormData => ({
|
||||||
// Hackathon: '',
|
Hackathon: '',
|
||||||
// mainTheme: '',
|
mainTheme: '',
|
||||||
// tracksStack: [''],
|
tracksStack: [''],
|
||||||
// students: [{
|
students: [{
|
||||||
// studentName: '',
|
studentName: '',
|
||||||
// skills: [{ skillName: '', proficiency: PROFICIENCY_LEVELS[1] }]
|
skills: [{ skillName: '', proficiency: PROFICIENCY_LEVELS[1] }]
|
||||||
// }],
|
}],
|
||||||
// });
|
});
|
||||||
|
|
||||||
// // --- New Initializer Function ---
|
// --- New Initializer Function ---
|
||||||
// const getInitialState = () => {
|
const getInitialState = () => {
|
||||||
// if (typeof window === 'undefined') {
|
if (typeof window === 'undefined') {
|
||||||
// return {
|
return {
|
||||||
// data: getDefaultFormData(),
|
data: getDefaultFormData(),
|
||||||
// showForm: true,
|
showForm: true,
|
||||||
// runEffect: false
|
runEffect: false
|
||||||
// };
|
};
|
||||||
// }
|
}
|
||||||
// const storedFormData = localStorage.getItem('formData');
|
const storedFormData = localStorage.getItem('formData');
|
||||||
// if (storedFormData) {
|
if (storedFormData) {
|
||||||
// localStorage.removeItem('formData');
|
localStorage.removeItem('formData');
|
||||||
// return {
|
return {
|
||||||
// data: JSON.parse(storedFormData) as FormData,
|
data: JSON.parse(storedFormData) as FormData,
|
||||||
// showForm: false,
|
showForm: false,
|
||||||
// runEffect: true,
|
runEffect: true,
|
||||||
// };
|
};
|
||||||
// }
|
}
|
||||||
// return {
|
return {
|
||||||
// data: getDefaultFormData(),
|
data: getDefaultFormData(),
|
||||||
// showForm: true,
|
showForm: true,
|
||||||
// runEffect: false
|
runEffect: false
|
||||||
// };
|
};
|
||||||
// };
|
};
|
||||||
|
|
||||||
// // FIX 1 (Memoization): Moved settings OUTSIDE the component.
|
// FIX 1 (Memoization): Moved settings OUTSIDE the component.
|
||||||
// // This makes it a true constant.
|
// This makes it a true constant.
|
||||||
// const AI_SETTINGS: ChatSetting = {
|
const AI_SETTINGS: ChatSetting = {
|
||||||
// temperature: 1,
|
temperature: 1,
|
||||||
// model: "gemini-2.5-pro",
|
model: "gemini-2.5-pro",
|
||||||
// sysTemInstructions: `You are an elite hackathon idea generator. Your task is to generate five different creative, feasible, and relevant project idea.
|
sysTemInstructions: `You are an elite hackathon idea generator. Your task is to generate five different creative, feasible, and relevant project idea.
|
||||||
// The output MUST be in Markdown format and strictly follow this structure:
|
The output MUST be in Markdown format and strictly follow this structure:
|
||||||
// ### Project Idea Title
|
### Project Idea Title
|
||||||
// **Relevance to Theme:** [Explain briefly]
|
**Relevance to Theme:** [Explain briefly]
|
||||||
// **Core Technology:** [List 3-5 primary technologies]
|
**Core Technology:** [List 3-5 primary technologies]
|
||||||
// **Team Fit:** [How the team's skills apply]
|
**Team Fit:** [How the team's skills apply]
|
||||||
// **Concept:** [A concise, single paragraph description of the product and its primary function.]
|
**Concept:** [A concise, single paragraph description of the product and its primary function.]
|
||||||
// **Bonus Feature:** [A single, ambitious feature to impress judges.]`,
|
**Bonus Feature:** [A single, ambitious feature to impress judges.]`,
|
||||||
// };
|
};
|
||||||
|
|
||||||
// // ------------------------------------------------
|
// ------------------------------------------------
|
||||||
|
|
||||||
// export default function Home() {
|
export default function Home() {
|
||||||
|
|
||||||
// const [initialState] = useState(getInitialState);
|
|
||||||
// const [showForm, setShowForm] = useState(initialState.showForm);
|
|
||||||
// const [formData, setFormData] = useState<FormData>(initialState.data);
|
|
||||||
// const [ideaResponse, setIdeaResponse] = useState<string>("");
|
|
||||||
|
|
||||||
// // The 'settings' state [useState] is now removed from here.
|
|
||||||
|
|
||||||
// const handleFormSubmitFromFormPage = (submittedData: FormData) => {
|
const [initialState] = useState(getInitialState);
|
||||||
// setFormData(submittedData);
|
const [showForm, setShowForm] = useState(initialState.showForm);
|
||||||
// setShowForm(false);
|
const [formData, setFormData] = useState<FormData>(initialState.data);
|
||||||
// generateIdeas(submittedData);
|
const [ideaResponse, setIdeaResponse] = useState<string>("");
|
||||||
// };
|
|
||||||
|
|
||||||
// // Wrapped generateIdeas in useCallback
|
// The 'settings' state [useState] is now removed from here.
|
||||||
// const generateIdeas = useCallback(async (dataToProcess: FormData) => {
|
|
||||||
// // 1. Data Cleaning
|
|
||||||
// const submissionData: FormData = {
|
|
||||||
// ...dataToProcess,
|
|
||||||
// tracksStack: dataToProcess.tracksStack.filter(tracks => tracks.trim() !== ''),
|
|
||||||
// students: dataToProcess.students
|
|
||||||
// .map(student => ({
|
|
||||||
// ...student,
|
|
||||||
// skills: student.skills.filter(skill => skill.skillName.trim() !== ''),
|
|
||||||
// }))
|
|
||||||
// .filter(student => student.studentName.trim() !== '' || student.skills.length > 0),
|
|
||||||
// };
|
|
||||||
|
|
||||||
// // 2. Prompt Construction
|
const handleFormSubmitFromFormPage = (submittedData: FormData) => {
|
||||||
// const prompt = `
|
setFormData(submittedData);
|
||||||
// Hackathon: ${submissionData.Hackathon}
|
setShowForm(false);
|
||||||
// Main Theme: ${submissionData.mainTheme}
|
generateIdeas(submittedData);
|
||||||
// Required Tracks Stack: ${submissionData.tracksStack.join(', ')}
|
};
|
||||||
// Team Members and Skills: ${submissionData.students.map(s =>
|
|
||||||
// `${s.studentName || 'Unamed Member'} (Skills: ${s.skills.map(sk => `${sk.skillName} - ${sk.proficiency}`).join(', ')})`
|
// Wrapped generateIdeas in useCallback
|
||||||
// ).join('; ')}
|
const generateIdeas = useCallback(async (dataToProcess: FormData) => {
|
||||||
|
// 1. Data Cleaning
|
||||||
|
const submissionData: FormData = {
|
||||||
|
...dataToProcess,
|
||||||
|
tracksStack: dataToProcess.tracksStack.filter(tracks => tracks.trim() !== ''),
|
||||||
|
students: dataToProcess.students
|
||||||
|
.map(student => ({
|
||||||
|
...student,
|
||||||
|
skills: student.skills.filter(skill => skill.skillName.trim() !== ''),
|
||||||
|
}))
|
||||||
|
.filter(student => student.studentName.trim() !== '' || student.skills.length > 0),
|
||||||
|
};
|
||||||
|
|
||||||
|
// 2. Prompt Construction
|
||||||
|
const prompt = `
|
||||||
|
Hackathon: ${submissionData.Hackathon}
|
||||||
|
Main Theme: ${submissionData.mainTheme}
|
||||||
|
Required Tracks Stack: ${submissionData.tracksStack.join(', ')}
|
||||||
|
Team Members and Skills: ${submissionData.students.map(s =>
|
||||||
|
`${s.studentName || 'Unamed Member'} (Skills: ${s.skills.map(sk => `${sk.skillName} - ${sk.proficiency}`).join(', ')})`
|
||||||
|
).join('; ')}
|
||||||
|
|
||||||
// Using the SYSTEM INSTRUCTIONS, generate 5 project ideas based on the data above.`;
|
Using the SYSTEM INSTRUCTIONS, generate 5 project ideas based on the data above.`;
|
||||||
|
|
||||||
// // 3. API Call
|
// 3. API Call
|
||||||
// try {
|
try {
|
||||||
// setIdeaResponse("Generating ideas... Please wait.");
|
setIdeaResponse("Generating ideas... Please wait.");
|
||||||
|
|
||||||
// const response = await fetch("/api/generate-idea", {
|
|
||||||
// method: "POST",
|
|
||||||
// headers: { "Content-Type": "application/json" },
|
|
||||||
// body: JSON.stringify({
|
|
||||||
// prompt: prompt,
|
|
||||||
// settings: AI_SETTINGS, // Use the constant
|
|
||||||
// }),
|
|
||||||
// });
|
|
||||||
|
|
||||||
// const data = await response.json();
|
const response = await fetch("/api/generate-idea", {
|
||||||
// if (data.error || !response.ok) {
|
method: "POST",
|
||||||
// console.error("AI Error:", data.error);
|
headers: { "Content-Type": "application/json" },
|
||||||
// setIdeaResponse(`Error: Failed to generate idea. ${data.error || response.statusText}`);
|
body: JSON.stringify({
|
||||||
// return;
|
prompt: prompt,
|
||||||
// }
|
settings: AI_SETTINGS, // Use the constant
|
||||||
// setIdeaResponse(data.response);
|
}),
|
||||||
|
});
|
||||||
// // FIX 2 (Unexpected any): Changed 'any' to 'unknown' and added a type check.
|
|
||||||
// } catch (error: unknown) {
|
|
||||||
// console.error("Request Failed:", error);
|
|
||||||
// let errorMessage = "A network error occurred. Please try again.";
|
|
||||||
// if (error instanceof Error) {
|
|
||||||
// errorMessage += ` Details: ${error.message}`;
|
|
||||||
// }
|
|
||||||
// setIdeaResponse(errorMessage);
|
|
||||||
// }
|
|
||||||
// // FIX 3 (Linter): Disable the faulty memoization rule.
|
|
||||||
// // The empty array is correct because setIdeaResponse is a stable state setter.
|
|
||||||
// // eslint-disable-next-line react-hooks/preserve-manual-memoization
|
|
||||||
// }, []);
|
|
||||||
|
|
||||||
// // Replaced useEffect
|
const data = await response.json();
|
||||||
// useEffect(() => {
|
if (data.error || !response.ok) {
|
||||||
// if (initialState.runEffect) {
|
console.error("AI Error:", data.error);
|
||||||
// generateIdeas(initialState.data);
|
setIdeaResponse(`Error: Failed to generate idea. ${data.error || response.statusText}`);
|
||||||
// }
|
return;
|
||||||
// }, [initialState, generateIdeas]);
|
}
|
||||||
|
setIdeaResponse(data.response);
|
||||||
|
|
||||||
// // --- JSX Rendering ---
|
// FIX 2 (Unexpected any): Changed 'any' to 'unknown' and added a type check.
|
||||||
// return (
|
} catch (error: unknown) {
|
||||||
// <main className="min-h-screen bg-gray-50 flex items-start justify-center p-4 sm:p-6 font-inter">
|
console.error("Request Failed:", error);
|
||||||
// <div className="w-full max-w-2xl bg-white p-8 shadow-2xl rounded-xl mt-8">
|
let errorMessage = "A network error occurred. Please try again.";
|
||||||
// {showForm ? (
|
if (error instanceof Error) {
|
||||||
// <FormPage onFormSubmit={handleFormSubmitFromFormPage} />
|
errorMessage += ` Details: ${error.message}`;
|
||||||
// ) : (
|
}
|
||||||
// <>
|
setIdeaResponse(errorMessage);
|
||||||
// <h1 className="text-3xl font-extrabold text-center text-gray-800 mb-8 tracking-tight">
|
}
|
||||||
// Generated Project Idea 💡
|
// FIX 3 (Linter): Disable the faulty memoization rule.
|
||||||
// </h1>
|
// The empty array is correct because setIdeaResponse is a stable state setter.
|
||||||
// <div className="mt-8 p-4 bg-yellow-50 rounded-lg border border-yellow-200">
|
// eslint-disable-next-line react-hooks/preserve-manual-memoization
|
||||||
// <h2 className="text-xl font-bold text-gray-700 mb-2">Generated Ideas:</h2>
|
}, []);
|
||||||
// <div
|
|
||||||
// className="prose max-w-none"
|
// Replaced useEffect
|
||||||
// dangerouslySetInnerHTML={{ __html: ideaResponse.replace(/\n/g, '<br/>') }}
|
useEffect(() => {
|
||||||
// />
|
if (initialState.runEffect) {
|
||||||
// {ideaResponse === "" && <p className="text-gray-500">Submit the form to generate project ideas.</p>}
|
generateIdeas(initialState.data);
|
||||||
// </div>
|
}
|
||||||
// <button
|
}, [initialState, generateIdeas]);
|
||||||
// onClick={() => setShowForm(true)}
|
|
||||||
// className="mt-6 w-full flex justify-center py-3 px-4 border border-transparent rounded-lg shadow-lg text-lg font-semibold text-white bg-blue-600 hover:bg-blue-700 transition duration-150"
|
// --- JSX Rendering ---
|
||||||
// >
|
return (
|
||||||
// Go Back to Form
|
<main className="min-h-screen bg-gray-50 flex items-start justify-center p-4 sm:p-6 font-inter">
|
||||||
// </button>
|
<div className="w-full max-w-2xl bg-white p-8 shadow-2xl rounded-xl mt-8">
|
||||||
// </>
|
{showForm ? (
|
||||||
// )}
|
<FormPage onFormSubmit={handleFormSubmitFromFormPage} />
|
||||||
// </div>
|
) : (
|
||||||
// </main>
|
<>
|
||||||
// );
|
<h1 className="text-3xl font-extrabold text-center text-gray-800 mb-8 tracking-tight">
|
||||||
// }
|
Generated Project Idea 💡
|
||||||
|
</h1>
|
||||||
|
<div className="mt-8 p-4 bg-yellow-50 rounded-lg border border-yellow-200">
|
||||||
|
<h2 className="text-xl font-bold text-gray-700 mb-2">Generated Ideas:</h2>
|
||||||
|
<div
|
||||||
|
className="prose max-w-none"
|
||||||
|
dangerouslySetInnerHTML={{ __html: ideaResponse.replace(/\n/g, '<br/>') }}
|
||||||
|
/>
|
||||||
|
{ideaResponse === "" && <p className="text-gray-500">Submit the form to generate project ideas.</p>}
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
onClick={() => setShowForm(true)}
|
||||||
|
className="mt-6 w-full flex justify-center py-3 px-4 border border-transparent rounded-lg shadow-lg text-lg font-semibold text-white bg-blue-600 hover:bg-blue-700 transition duration-150"
|
||||||
|
>
|
||||||
|
Go Back to Form
|
||||||
|
</button>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
);
|
||||||
|
}
|
||||||
+9
-4
@@ -39,10 +39,10 @@ body {
|
|||||||
--color-foreground: var(--foreground);
|
--color-foreground: var(--foreground);
|
||||||
|
|
||||||
/* 3. Assign fonts to Tailwind's theme */
|
/* 3. Assign fonts to Tailwind's theme */
|
||||||
|
|
||||||
/* --font-sans is for regular text (Concert One) */
|
/* --font-sans is for regular text (Concert One) */
|
||||||
--font-sans: var(--font-concert-one);
|
--font-sans: var(--font-concert-one);
|
||||||
|
|
||||||
/* We add a new font family for headers (Pixelify Sans) */
|
/* We add a new font family for headers (Pixelify Sans) */
|
||||||
/* This also creates a 'font-header' utility class */
|
/* This also creates a 'font-header' utility class */
|
||||||
--font-header: var(--font-pixelify);
|
--font-header: var(--font-pixelify);
|
||||||
@@ -60,12 +60,17 @@ body {
|
|||||||
body {
|
body {
|
||||||
background: var(--background);
|
background: var(--background);
|
||||||
color: var(--foreground);
|
color: var(--foreground);
|
||||||
|
|
||||||
/* 4. Body uses --font-sans (Concert One) by default */
|
/* 4. Body uses --font-sans (Concert One) by default */
|
||||||
font-family: var(--font-sans);
|
font-family: var(--font-sans);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 5. (Optional but helpful) Apply header font to h-tags by default */
|
/* 5. (Optional but helpful) Apply header font to h-tags by default */
|
||||||
h1, h2, h3, h4, h5, h6 {
|
h1,
|
||||||
|
h2,
|
||||||
|
h3,
|
||||||
|
h4,
|
||||||
|
h5,
|
||||||
|
h6 {
|
||||||
font-family: var(--font-header);
|
font-family: var(--font-header);
|
||||||
}
|
}
|
||||||
+141
-142
@@ -1,46 +1,45 @@
|
|||||||
import Image from "next/image";
|
import Image from "next/image";
|
||||||
import ProtectedNavButton from "./components/ProtectedNavButton";
|
|
||||||
|
|
||||||
export default function Home() {
|
export default function Home() {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
style={{ backgroundColor: "#FEEEDF" }}
|
style={{ backgroundColor: "#FEEEDF" }}
|
||||||
className="flex items-center justify-center font-sans "
|
className="flex items-center justify-center font-sans "
|
||||||
>
|
>
|
||||||
<header className="absolute top-6 left-8 right-8 flex items-center justify-between text-sm font-medium text-zinc-700 dark:text-zinc-300">
|
<header className="absolute top-6 left-8 right-8 flex items-center justify-between text-sm font-medium text-zinc-700 dark:text-zinc-300">
|
||||||
<Image
|
<Image
|
||||||
className="dark:invert"
|
className="dark:invert"
|
||||||
src="/next.svg"
|
src="/next.svg"
|
||||||
alt="Next.js logo"
|
alt="Next.js logo"
|
||||||
width={100}
|
width={100}
|
||||||
height={20}
|
height={20}
|
||||||
priority
|
priority
|
||||||
/>
|
/>
|
||||||
<div className="flex items-center gap-4">
|
<div className="flex items-center gap-4">
|
||||||
<a href="/signin" className="hover:text-blue-600 dark:hover:text-blue-400 transition-colors">
|
<a href="/signin" className="hover:text-blue-600 dark:hover:text-blue-400 transition-colors">
|
||||||
Sign in
|
Sign in
|
||||||
</a>
|
</a>
|
||||||
<a href="/register" className="hover:text-blue-600 dark:hover:text-blue-400 transition-colors">
|
<a href="/register" className="hover:text-blue-600 dark:hover:text-blue-400 transition-colors">
|
||||||
Register
|
Register
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<main className="flex min-h-screen w-full flex-col justify-between py-32 max-w-[1200px] mx-auto">
|
<main className="flex min-h-screen w-full flex-col justify-between py-32 max-w-[1200px] mx-auto">
|
||||||
<div className="flex flex-col sm:flex-row items-center justify-center gap-12 text-left w-full max-w-[1200px] mx-auto">
|
<div className="flex flex-col sm:flex-row items-center justify-center gap-12 text-left w-full max-w-[1200px] mx-auto">
|
||||||
<div className="flex-1 flex flex-col gap-5 justify-center items-start">
|
<div className="flex-1 flex flex-col gap-5 justify-center items-start">
|
||||||
<h1
|
<h1
|
||||||
style = {{color:"#173C46"}}
|
style={{ color: "#173C46" }}
|
||||||
className="max-w-xs text-3xl font-semibold leading-10 tracking-tight text-black dark:text-zinc-50"
|
className="max-w-xs text-3xl font-semibold leading-10 tracking-tight text-black dark:text-zinc-50"
|
||||||
>
|
>
|
||||||
Welcome! This is HackSpark
|
Welcome! This is HackSpark
|
||||||
</h1>
|
</h1>
|
||||||
<p
|
<p
|
||||||
style = {{color:"#173C46"}}
|
style={{ color: "#173C46" }}
|
||||||
className="max-w-md text-lg leading-8 text-zinc-600 dark:text-zinc-400"
|
className="max-w-md text-lg leading-8 text-zinc-600 dark:text-zinc-400"
|
||||||
>
|
>
|
||||||
Got a hackathon coming up? Tell us your track, your team’s skills, what you’re passionate about, and more — and we’ll provide you with the perfect project idea!{" "}
|
Got a hackathon coming up? Tell us your track, your team’s skills, what you’re passionate about, and more — and we’ll provide you with the perfect project idea!{" "}
|
||||||
{/* <a
|
{/* <a
|
||||||
href="https://vercel.com/templates?framework=next.js&utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
|
href="https://vercel.com/templates?framework=next.js&utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
|
||||||
className="font-medium text-zinc-950 dark:text-zinc-50"
|
className="font-medium text-zinc-950 dark:text-zinc-50"
|
||||||
>
|
>
|
||||||
@@ -53,113 +52,113 @@ export default function Home() {
|
|||||||
>
|
>
|
||||||
Learning
|
Learning
|
||||||
</a>{" "} */}
|
</a>{" "} */}
|
||||||
{/* center. */}
|
{/* center. */}
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
{/* <ProtectedNavButton>Get Started</ProtectedNavButton> */}
|
{/* <ProtectedNavButton>Get Started</ProtectedNavButton> */}
|
||||||
<button
|
<button
|
||||||
style={{ backgroundColor: "#173C46", color: "white" }}
|
style={{ backgroundColor: "#173C46", color: "white" }}
|
||||||
className="px-4 py-1.5 rounded-md shadow-md font-semibold hover:opacity-90 transition-opacity"
|
className="px-4 py-1.5 rounded-md shadow-md font-semibold hover:opacity-90 transition-opacity"
|
||||||
>
|
>
|
||||||
{/* {children} */}
|
{/* {children} */}
|
||||||
Get Started
|
Get Started
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex-1 flex justify-center">
|
<div className="flex-1 flex justify-center">
|
||||||
<div
|
<div
|
||||||
className="w-full max-w-[400px] h-[300px] bg-zinc-200 dark:bg-zinc-800 rounded-xl shadow-md flex items-center justify-center text-zinc-500"
|
className="w-full max-w-[400px] h-[300px] bg-zinc-200 dark:bg-zinc-800 rounded-xl shadow-md flex items-center justify-center text-zinc-500"
|
||||||
style={{ backgroundColor: "#173C46"}}
|
style={{ backgroundColor: "#173C46" }}
|
||||||
>
|
>
|
||||||
Image Placeholder
|
Image Placeholder
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
style={{backgroundColor: "#DEE5D4"}}
|
style={{ backgroundColor: "#DEE5D4" }}
|
||||||
className="w-full rounded-xl mt-32"
|
className="w-full rounded-xl mt-32"
|
||||||
>
|
>
|
||||||
{/* <section className="mt-32 w-full flex flex-col items-start gap-12"> */}
|
{/* <section className="mt-32 w-full flex flex-col items-start gap-12"> */}
|
||||||
<section className="px-16 py-18 flex flex-col items-start gap-12 max-w-[1200px] mx-auto">
|
<section className="px-16 py-18 flex flex-col items-start gap-12 max-w-[1200px] mx-auto">
|
||||||
{/* <div> */}
|
{/* <div> */}
|
||||||
<h2 className="text-[28px] font-semibold text-black dark:text-zinc-50 leading-9">
|
<h2 className="text-[28px] font-semibold text-black dark:text-zinc-50 leading-9">
|
||||||
Guide:
|
Guide:
|
||||||
</h2>
|
</h2>
|
||||||
{/* </div> */}
|
{/* </div> */}
|
||||||
|
|
||||||
<div className="flex flex-col sm:flex-row items-center justify-center gap-8 w-full">
|
<div className="flex flex-col sm:flex-row items-center justify-center gap-8 w-full">
|
||||||
<div
|
<div
|
||||||
className="w-full max-w-xl rounded-xl h-[200px] p-6 flex flex-col justify-center"
|
className="w-full max-w-xl rounded-xl h-[200px] p-6 flex flex-col justify-center"
|
||||||
style={{ backgroundColor: "#B8C0AD"}}
|
style={{ backgroundColor: "#B8C0AD" }}
|
||||||
>
|
>
|
||||||
<h2 className="text-2xl font-semibold text-black dark:text-zinc-50 mb-2">
|
<h2 className="text-2xl font-semibold text-black dark:text-zinc-50 mb-2">
|
||||||
First Text Block
|
First Text Block
|
||||||
</h2>
|
</h2>
|
||||||
<p className="text-lg text-zinc-600 dark:text-zinc-400">
|
<p className="text-lg text-zinc-600 dark:text-zinc-400">
|
||||||
This is the content for the first text block. You can write anything here.
|
This is the content for the first text block. You can write anything here.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="sm:w-1/2 flex justify-center items-center">
|
<div className="sm:w-1/2 flex justify-center items-center">
|
||||||
<div
|
<div
|
||||||
className="w-full max-w-[400px] h-[300px] bg-zinc-200 dark:bg-zinc-800 rounded-xl shadow-md flex items-center justify-center text-zinc-500"
|
className="w-full max-w-[400px] h-[300px] bg-zinc-200 dark:bg-zinc-800 rounded-xl shadow-md flex items-center justify-center text-zinc-500"
|
||||||
style={{ backgroundColor: "#B8C0AD"}}
|
style={{ backgroundColor: "#B8C0AD" }}
|
||||||
>
|
>
|
||||||
Image Placeholder
|
Image Placeholder
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex flex-col sm:flex-row items-center justify-between gap-8 w-full mt-30">
|
|
||||||
<div className="sm:w-1/2 flex justify-center items-center">
|
|
||||||
<div
|
|
||||||
className="w-full max-w-[400px] h-[300px] bg-zinc-200 dark:bg-zinc-800 rounded-xl shadow-md flex items-center justify-center text-zinc-500"
|
|
||||||
style={{ backgroundColor: "#B8C0AD"}}
|
|
||||||
>
|
|
||||||
Image Placeholder
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="flex w-full justify-center sm:justify-center">
|
|
||||||
<div
|
|
||||||
className="w-full max-w-xl rounded-xl h-[200px] p-6 flex flex-col justify-center"
|
|
||||||
style={{ backgroundColor: "#B8C0AD"}}
|
|
||||||
>
|
|
||||||
<h2 className="text-2xl font-semibold text-black dark:text-zinc-50 mb-2">
|
|
||||||
Second Text Block
|
|
||||||
</h2>
|
|
||||||
<p className="text-lg text-zinc-600 dark:text-zinc-400">
|
|
||||||
This is the content for the second text block. You can write anything here.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="flex flex-col sm:flex-row items-center justify-center gap-8 w-full mt-30">
|
<div className="flex flex-col sm:flex-row items-center justify-between gap-8 w-full mt-30">
|
||||||
<div
|
<div className="sm:w-1/2 flex justify-center items-center">
|
||||||
className="w-full max-w-xl rounded-xl h-[200px] p-6 flex flex-col justify-center"
|
<div
|
||||||
style={{ backgroundColor: "#B8C0AD"}}
|
className="w-full max-w-[400px] h-[300px] bg-zinc-200 dark:bg-zinc-800 rounded-xl shadow-md flex items-center justify-center text-zinc-500"
|
||||||
>
|
style={{ backgroundColor: "#B8C0AD" }}
|
||||||
<h2 className="text-2xl font-semibold text-black dark:text-zinc-50 mb-2">
|
>
|
||||||
Third Text Block
|
Image Placeholder
|
||||||
</h2>
|
</div>
|
||||||
<p className="text-lg text-zinc-600 dark:text-zinc-400">
|
</div>
|
||||||
This is the content for the third text block. You can write anything here.
|
<div className="flex w-full justify-center sm:justify-center">
|
||||||
</p>
|
<div
|
||||||
</div>
|
className="w-full max-w-xl rounded-xl h-[200px] p-6 flex flex-col justify-center"
|
||||||
<div className="sm:w-1/2 flex justify-center items-center">
|
style={{ backgroundColor: "#B8C0AD" }}
|
||||||
<div
|
>
|
||||||
className="w-full max-w-[400px] h-[300px] bg-zinc-200 dark:bg-zinc-800 rounded-xl shadow-md flex items-center justify-center text-zinc-500"
|
<h2 className="text-2xl font-semibold text-black dark:text-zinc-50 mb-2">
|
||||||
style={{ backgroundColor: "#B8C0AD"}}
|
Second Text Block
|
||||||
>
|
</h2>
|
||||||
Image Placeholder
|
<p className="text-lg text-zinc-600 dark:text-zinc-400">
|
||||||
</div>
|
This is the content for the second text block. You can write anything here.
|
||||||
</div>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</main>
|
|
||||||
</div>
|
<div className="flex flex-col sm:flex-row items-center justify-center gap-8 w-full mt-30">
|
||||||
);
|
<div
|
||||||
|
className="w-full max-w-xl rounded-xl h-[200px] p-6 flex flex-col justify-center"
|
||||||
|
style={{ backgroundColor: "#B8C0AD" }}
|
||||||
|
>
|
||||||
|
<h2 className="text-2xl font-semibold text-black dark:text-zinc-50 mb-2">
|
||||||
|
Third Text Block
|
||||||
|
</h2>
|
||||||
|
<p className="text-lg text-zinc-600 dark:text-zinc-400">
|
||||||
|
This is the content for the third text block. You can write anything here.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div className="sm:w-1/2 flex justify-center items-center">
|
||||||
|
<div
|
||||||
|
className="w-full max-w-[400px] h-[300px] bg-zinc-200 dark:bg-zinc-800 rounded-xl shadow-md flex items-center justify-center text-zinc-500"
|
||||||
|
style={{ backgroundColor: "#B8C0AD" }}
|
||||||
|
>
|
||||||
|
Image Placeholder
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -287,4 +286,4 @@ export default function Home() {
|
|||||||
// </main>
|
// </main>
|
||||||
// </div>
|
// </div>
|
||||||
// );
|
// );
|
||||||
// } fix the formatting of this page, I want the divs to be more centered and the divs below the button to be equal size
|
// }
|
||||||
@@ -17,8 +17,8 @@ export default function ChatInput({ onSend, onOpenSettings }: ChatInputProps) {
|
|||||||
|
|
||||||
const handleSend = () => {
|
const handleSend = () => {
|
||||||
if (message.trim()) {
|
if (message.trim()) {
|
||||||
onSend(message.trim());
|
onSend(message.trim());
|
||||||
setMessage("");
|
setMessage("");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -34,62 +34,61 @@ export default function ChatInput({ onSend, onOpenSettings }: ChatInputProps) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="fixed bottom-0 left-0 right-0 flex flex-col max-w-4xl mx-auto w-full">
|
<div className="fixed bottom-0 left-0 right-0 flex flex-col max-w-4xl mx-auto w-full">
|
||||||
<div
|
<div
|
||||||
className={`
|
className={`
|
||||||
flex items-center border border-black/10 p-3 mx-4 rounded-t-3xl
|
flex items-center border border-black/10 p-3 mx-4 rounded-t-3xl
|
||||||
bg-white
|
bg-white
|
||||||
shadow-md transition-all duration-200
|
shadow-md transition-all duration-200
|
||||||
|
|
||||||
`}
|
`}
|
||||||
>
|
|
||||||
|
|
||||||
<div className="relative flex-1 mx-2">
|
|
||||||
<textarea
|
|
||||||
className="w-full px-3 py-2 bg-transparent border-none focus:outline-none"
|
|
||||||
placeholder="Type a message..."
|
|
||||||
value={message}
|
|
||||||
onChange={handleChange}
|
|
||||||
onKeyDown={handleKeyPress}
|
|
||||||
/>
|
|
||||||
|
|
||||||
{message && (
|
|
||||||
<button
|
|
||||||
className="absolute right-0 top-1/2 transform -translate-y-1/2 p-1 text-gray-400 hover:text-gray-600 "
|
|
||||||
onClick={handleClear}
|
|
||||||
aria-label="Clear input"
|
|
||||||
>
|
|
||||||
<X size={16} />
|
|
||||||
</button>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
<div className="flex items-center">
|
|
||||||
|
|
||||||
<button
|
|
||||||
className="p-2 text-gray-500 hover:text-purple-600 rounded-full hover:bg-gray-100 0 mr-1"
|
|
||||||
onClick={onOpenSettings}
|
|
||||||
aria-label="Open settings"
|
|
||||||
>
|
>
|
||||||
<Settings size={20} />
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<button
|
<div className="relative flex-1 mx-2">
|
||||||
className={`
|
<textarea
|
||||||
|
className="w-full px-3 py-2 bg-transparent border-none focus:outline-none"
|
||||||
|
placeholder="Type a message..."
|
||||||
|
value={message}
|
||||||
|
onChange={handleChange}
|
||||||
|
onKeyDown={handleKeyPress}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{message && (
|
||||||
|
<button
|
||||||
|
className="absolute right-0 top-1/2 transform -translate-y-1/2 p-1 text-gray-400 hover:text-gray-600 "
|
||||||
|
onClick={handleClear}
|
||||||
|
aria-label="Clear input"
|
||||||
|
>
|
||||||
|
<X size={16} />
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div className="flex items-center">
|
||||||
|
|
||||||
|
<button
|
||||||
|
className="p-2 text-gray-500 hover:text-purple-600 rounded-full hover:bg-gray-100 0 mr-1"
|
||||||
|
onClick={onOpenSettings}
|
||||||
|
aria-label="Open settings"
|
||||||
|
>
|
||||||
|
<Settings size={20} />
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button
|
||||||
|
className={`
|
||||||
p-2 rounded-full transition-all
|
p-2 rounded-full transition-all
|
||||||
${
|
${message.trim()
|
||||||
message.trim()
|
? "bg-purple-600 text-white hover:bg-purple-700"
|
||||||
? "bg-purple-600 text-white hover:bg-purple-700"
|
: "bg-gray-200 text-gray-400 cursor-not-allowed"
|
||||||
: "bg-gray-200 text-gray-400 cursor-not-allowed"
|
}
|
||||||
}
|
|
||||||
`}
|
`}
|
||||||
onClick={handleSend}
|
onClick={handleSend}
|
||||||
disabled={!message.trim()}
|
disabled={!message.trim()}
|
||||||
aria-label="Send message"
|
aria-label="Send message"
|
||||||
>
|
>
|
||||||
<Send size={20} />
|
<Send size={20} />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,30 +1,30 @@
|
|||||||
"use client";
|
"use client";
|
||||||
import { useRef, useEffect } from "react";
|
import { useRef, useEffect } from "react";
|
||||||
import { ChatHistory } from "@/app/exportType/types";
|
import { ChatHistory } from "@/app/exportType/types";
|
||||||
import {User, Bot} from "lucide-react"
|
import { User, Bot } from "lucide-react"
|
||||||
|
|
||||||
interface MessageWindowProps{
|
interface MessageWindowProps {
|
||||||
history :ChatHistory
|
history: ChatHistory
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function MessageWindow({history}:MessageWindowProps){
|
export default function MessageWindow({ history }: MessageWindowProps) {
|
||||||
const messageEndRef = useRef<HTMLDivElement>(null);
|
const messageEndRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
useEffect(() =>{
|
useEffect(() => {
|
||||||
messageEndRef.current?.scrollIntoView({behavior:"smooth"});
|
messageEndRef.current?.scrollIntoView({ behavior: "smooth" });
|
||||||
}, [history]);
|
}, [history]);
|
||||||
|
|
||||||
return(
|
return (
|
||||||
<div className="flex-1 p-3 overflow-y-auto">
|
<div className="flex-1 p-3 overflow-y-auto">
|
||||||
<div className="max-w-3xl mx-auto">
|
<div className="max-w-3xl mx-auto">
|
||||||
{history.map((msg,index)=>{
|
{history.map((msg, index) => {
|
||||||
const isUser = msg.role === "user"
|
const isUser = msg.role === "user"
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
key={index}
|
key={index}
|
||||||
className={`flex ${isUser ? "justify-end" : "justify-start"}`}>
|
className={`flex ${isUser ? "justify-end" : "justify-start"}`}>
|
||||||
{!isUser &&(
|
{!isUser && (
|
||||||
<div className="mr-2">
|
<div className="mr-2">
|
||||||
<div className="flex items-center justify-center w-8 h-8 rounded-full bg-gray">
|
<div className="flex items-center justify-center w-8 h-8 rounded-full bg-gray">
|
||||||
<Bot size={15} className="text-gray-700">
|
<Bot size={15} className="text-gray-700">
|
||||||
@@ -41,20 +41,20 @@ export default function MessageWindow({history}:MessageWindowProps){
|
|||||||
<span key={idx}>{part.text}</span>))}
|
<span key={idx}>{part.text}</span>))}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{isUser && (
|
{isUser && (
|
||||||
<div className="ml-2">
|
<div className="ml-2">
|
||||||
<div className="flex items-center justify-center w-8 h-8 rounded-full bg-purple-500">
|
<div className="flex items-center justify-center w-8 h-8 rounded-full bg-purple-500">
|
||||||
<User size={16} className="text-white" />
|
<User size={16} className="text-white" />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
)}
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
|
|
||||||
{/* Invisible element to help scroll to bottom */}
|
{/* Invisible element to help scroll to bottom */}
|
||||||
<div ref={messageEndRef} />
|
<div ref={messageEndRef} />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
+36
-36
@@ -1,42 +1,42 @@
|
|||||||
// import { GoogleGenerativeAI } from "@google/generative-ai";
|
import { GoogleGenerativeAI } from "@google/generative-ai";
|
||||||
// import { ChatHistory, GenerateConfig,ChatSetting } from "../exportType/types";
|
import { ChatHistory, GenerateConfig, ChatSetting } from "../exportType/types";
|
||||||
|
|
||||||
// const apiKey = process.env.GEMINI_API_KEY;
|
const apiKey = process.env.GEMINI_API_KEY;
|
||||||
|
|
||||||
// if(!apiKey){
|
if (!apiKey) {
|
||||||
// throw new Error("api key not found");
|
throw new Error("api key not found");
|
||||||
// }
|
}
|
||||||
|
|
||||||
// const genAI = new GoogleGenerativeAI(apiKey);
|
const genAI = new GoogleGenerativeAI(apiKey);
|
||||||
|
|
||||||
// export async function chatToGemini(
|
export async function chatToGemini(
|
||||||
// userMessage:string ,
|
userMessage: string,
|
||||||
// history:ChatHistory,
|
history: ChatHistory,
|
||||||
// settings:ChatSetting
|
settings: ChatSetting
|
||||||
// ):Promise<string>{
|
): Promise<string> {
|
||||||
// const model = genAI.getGenerativeModel({
|
const model = genAI.getGenerativeModel({
|
||||||
// model:settings.model || "gemini-2.5-flash",
|
model: settings.model || "gemini-2.5-flash",
|
||||||
// systemInstruction: settings.sysTemInstructions || "you are going to create a project idea, explain it in summery first before going to detail",
|
systemInstruction: settings.sysTemInstructions || "you are going to create a project idea, explain it in summery first before going to detail",
|
||||||
// });
|
});
|
||||||
|
|
||||||
// const generationConfig:GenerateConfig = {
|
|
||||||
// temperature : settings.temperature || 1,
|
|
||||||
// topP : 0.9,
|
|
||||||
// responseMimeType: "text/plain",
|
|
||||||
// maxOutputTokens: 1900, // Increased to allow for longer responses
|
|
||||||
// }
|
|
||||||
|
|
||||||
// const chatSession = model.startChat({
|
const generationConfig: GenerateConfig = {
|
||||||
// generationConfig,
|
temperature: settings.temperature || 1,
|
||||||
// history
|
topP: 0.9,
|
||||||
// })
|
responseMimeType: "text/plain",
|
||||||
|
maxOutputTokens: 1900, // Increased to allow for longer responses
|
||||||
|
}
|
||||||
|
|
||||||
// try {
|
const chatSession = model.startChat({
|
||||||
// const result = await chatSession.sendMessage(userMessage);
|
generationConfig,
|
||||||
// return result.response.text();
|
history
|
||||||
// }
|
})
|
||||||
// catch(error){
|
|
||||||
// console.error(error)
|
try {
|
||||||
// throw error
|
const result = await chatSession.sendMessage(userMessage);
|
||||||
// }
|
return result.response.text();
|
||||||
// }
|
}
|
||||||
|
catch (error) {
|
||||||
|
console.error(error)
|
||||||
|
throw error
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user