mirror of
https://github.com/PinkSheep27/SBU-Hackathon.git
synced 2026-10-10 23:40:27 -04:00
added images, changed css for homepage, dashboard and got rid of templates for cards and made them take actual local variables
This commit is contained in:
+44
-14
@@ -1,20 +1,27 @@
|
||||
"use client";
|
||||
|
||||
import React, { useState, useEffect } from "react";
|
||||
import { getStoredProjects, StoredProject } from "../utils/storage";
|
||||
import { getStoredProjects, StoredProject,setProjectForEditing } from "../utils/storage";
|
||||
import Link from 'next/link';
|
||||
import { useRouter } from "next/navigation";
|
||||
|
||||
export default function Dashboard() {
|
||||
const [query, setQuery] = useState("");
|
||||
const [sideBarOpen, setSidebarOpen] = useState(true);
|
||||
const [sortOrder, setSortOrder] = useState("newest");
|
||||
const [projects, setProjects] = useState<StoredProject[]>([]);
|
||||
const router = useRouter();
|
||||
|
||||
useEffect(() => {
|
||||
const storedProjects = getStoredProjects();
|
||||
setProjects(storedProjects);
|
||||
}, []);
|
||||
|
||||
const handleRerun = (project: StoredProject) => {
|
||||
setProjectForEditing(project);
|
||||
router.push('/formfile');
|
||||
};
|
||||
|
||||
const sortedProjects = [...projects].sort((a, b) => {
|
||||
const dateA = new Date(a.id).getTime();
|
||||
const dateB = new Date(b.id).getTime();
|
||||
@@ -39,15 +46,17 @@ export default function Dashboard() {
|
||||
};
|
||||
|
||||
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 font-sans transition-all duration-300"
|
||||
style={{ backgroundColor: '#FFEAE1' }}>
|
||||
<aside
|
||||
className={`${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`}
|
||||
} transition-all duration-300 flex flex-col `}
|
||||
style={{ backgroundColor: 'rgba(153, 164, 138, 0.9)' }}
|
||||
>
|
||||
<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">
|
||||
{sideBarOpen && (
|
||||
<span className="text-lg font-semibold text-zinc-800 dark:text-zinc-100">
|
||||
More
|
||||
SparkBot
|
||||
</span>
|
||||
)}
|
||||
<button
|
||||
@@ -85,7 +94,7 @@ export default function Dashboard() {
|
||||
|
||||
<div className="flex-1 flex flex-col min-w-0">
|
||||
<header
|
||||
className="sticky top-0 z-10 backdrop-blur-sm border-b"
|
||||
className="sticky top-0 z-10 backdrop-blur-sm"
|
||||
style={{ backgroundColor: 'rgba(153, 164, 138, 0.9)', borderColor: '#8A947E' }} // Top bar background (semi-transparent) and border
|
||||
>
|
||||
<div className="max-w-7xl mx-auto px-6 py-4 flex items-center justify-between gap-4">
|
||||
@@ -134,16 +143,37 @@ export default function Dashboard() {
|
||||
|
||||
<section>
|
||||
<ul className="space-y-3">
|
||||
{filtered.map((project, index) => (
|
||||
{filtered.map((project) => (
|
||||
<li
|
||||
key={index}
|
||||
className="flex justify-between p-4 border rounded-md"
|
||||
style={{ backgroundColor: '#B8C0AD', color: '#222', borderColor: '#A9B29E' }} // Project boxes
|
||||
key={project.id}
|
||||
className="flex flex-col sm:flex-row justify-between items-start sm:items-center p-4 border rounded-md"
|
||||
style={{ backgroundColor: '#B8C0AD', color: '#222', borderColor: '#A9B29E' }}
|
||||
>
|
||||
<span>{project.name}</span>
|
||||
<span className="text-gray-700 text-sm">
|
||||
Created: {project.createdAt}
|
||||
</span>
|
||||
<div className="flex-1 mb-2 sm:mb-0">
|
||||
<Link
|
||||
href={`/chatbot?projectId=${encodeURIComponent(project.id)}&projectTitle=${encodeURIComponent(project.title)}`}
|
||||
className="text-lg font-semibold text-[#173C46] hover:underline"
|
||||
>
|
||||
{project.title}
|
||||
</Link>
|
||||
|
||||
<span className="block text-gray-700 text-sm mt-1">
|
||||
Created: {new Date(project.id).toLocaleString()}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div className="flex gap-2">
|
||||
<button
|
||||
onClick={() => handleRerun(project)}
|
||||
className="px-3 py-1 text-sm font-medium rounded-md shadow hover:opacity-90"
|
||||
style={{
|
||||
color: 'white',
|
||||
backgroundColor: '#EA627F'
|
||||
}}
|
||||
>
|
||||
Re-run
|
||||
</button>
|
||||
</div>
|
||||
</li>
|
||||
))}
|
||||
{filtered.length === 0 && (
|
||||
|
||||
+10
-10
@@ -26,9 +26,13 @@ const parseAiResponse = (markdownString: string): CardData[] => {
|
||||
|
||||
ideaBlocks.forEach((block, index) => {
|
||||
const titleMatch = block.match(/^(.*?)\n/);
|
||||
const conceptMatch = block.match(/\*\*Concept:\*\*\s*(.*)/s);
|
||||
const tracksMatch = block.matchAll(/\*\*(?!Concept|Relevance|Core|Team|Bonus)(.*?):\*\*/g);
|
||||
const tracks = [...tracksMatch].map(match => match[1].trim());
|
||||
const conceptMatch = block.match(/\*\*Concept:\*\*\s*([\s\S]*?)(?=\n\*\*|$)/s); // Improved summary regex
|
||||
|
||||
// --- THIS IS THE FIX ---
|
||||
// It now looks for "**Core Technology:**" and splits the technologies by comma
|
||||
const techMatch = block.match(/\*\*Core Technology:\*\*\s*(.*)/);
|
||||
const tracks = techMatch ? techMatch[1].split(',').map(t => t.trim()) : ["General"];
|
||||
// -----------------------
|
||||
|
||||
ideas.push({
|
||||
id: index + 1,
|
||||
@@ -60,13 +64,9 @@ export default function CardsPage() {
|
||||
setCards(parsedCards.reverse());
|
||||
setInitialCards(parsedCards.reverse());
|
||||
} else {
|
||||
console.warn("No AI response found. Using hardcoded cards as fallback.");
|
||||
const hardcodedCards: CardData[] = [
|
||||
{ id: 1, title: "AI Project Idea 1", summary: "A cool project...", tracks: ["AI", "Web"] },
|
||||
{ id: 2, title: "AI Project Idea 2", summary: "Another cool project...", tracks: ["Mobile", "Game"] },
|
||||
];
|
||||
setCards(hardcodedCards.reverse());
|
||||
setInitialCards(hardcodedCards.reverse());
|
||||
// If no AI response is found, we do nothing.
|
||||
// The 'cards' state will remain empty, showing the "No more cards!" UI.
|
||||
console.warn("No 'temp_aiResponse' found in localStorage. Displaying empty deck.");
|
||||
}
|
||||
setIsLoading(false);
|
||||
}, []);
|
||||
|
||||
@@ -41,7 +41,7 @@ function ChatbotContent() {
|
||||
const historyRef = useRef<ChatHistory>(history);
|
||||
const [settings] = useState<ChatSetting>({
|
||||
temperature: 1,
|
||||
model: "gemini-2.5-pro",
|
||||
model: "gemini-2.5-flash-lite",
|
||||
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"
|
||||
});
|
||||
|
||||
|
||||
+23
-18
@@ -1,8 +1,10 @@
|
||||
"use client";
|
||||
import React, { useState, useEffect, useCallback } from "react";
|
||||
import { useRouter } from "next/navigation";
|
||||
import FormPage from './FormPage';
|
||||
import { ChatSetting } from "../exportType/types";
|
||||
import { FormData, PROFICIENCY_LEVELS } from './formTypes';
|
||||
import { saveProject } from "../utils/storage";
|
||||
|
||||
// --- Helper function to get default form data ---
|
||||
const getDefaultFormData = (): FormData => ({
|
||||
@@ -44,21 +46,21 @@ const getInitialState = () => {
|
||||
// This makes it a true constant.
|
||||
const AI_SETTINGS: ChatSetting = {
|
||||
temperature: 1,
|
||||
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.
|
||||
The output MUST be in Markdown format and strictly follow this structure:
|
||||
### Project Idea Title
|
||||
**Relevance to Theme:** [Explain briefly]
|
||||
**Core Technology:** [List 3-5 primary technologies]
|
||||
**Team Fit:** [How the team's skills apply]
|
||||
**Concept:** [A concise, single paragraph description of the product and its primary function.]
|
||||
**Bonus Feature:** [A single, ambitious feature to impress judges.]`,
|
||||
model: "gemini-2.5-flash-lite",
|
||||
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:
|
||||
### Project Idea Title
|
||||
**Relevance to Theme:** [Explain briefly]
|
||||
**Core Technology:** [List 3-5 primary technologies]
|
||||
**Team Fit:** [How the team's skills apply]
|
||||
**Concept:** [A concise, single paragraph description of the product and its primary function.]
|
||||
**Bonus Feature:** [A single, ambitious feature to impress judges.]`,
|
||||
};
|
||||
|
||||
// ------------------------------------------------
|
||||
|
||||
export default function Home() {
|
||||
|
||||
const router = useRouter();
|
||||
const [initialState] = useState(getInitialState);
|
||||
const [showForm, setShowForm] = useState(initialState.showForm);
|
||||
const [formData, setFormData] = useState<FormData>(initialState.data);
|
||||
@@ -75,6 +77,10 @@ export default function Home() {
|
||||
// Wrapped generateIdeas in useCallback
|
||||
const generateIdeas = useCallback(async (dataToProcess: FormData) => {
|
||||
// 1. Data Cleaning
|
||||
const newProject = saveProject(dataToProcess);
|
||||
const projectId = newProject.id;
|
||||
const projectTitle = newProject.title;
|
||||
|
||||
const submissionData: FormData = {
|
||||
...dataToProcess,
|
||||
tracksStack: dataToProcess.tracksStack.filter(tracks => tracks.trim() !== ''),
|
||||
@@ -94,8 +100,7 @@ export default function Home() {
|
||||
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.`;
|
||||
`;
|
||||
|
||||
// 3. API Call
|
||||
try {
|
||||
@@ -116,8 +121,11 @@ export default function Home() {
|
||||
setIdeaResponse(`Error: Failed to generate idea. ${data.error || response.statusText}`);
|
||||
return;
|
||||
}
|
||||
setIdeaResponse(data.response);
|
||||
|
||||
localStorage.setItem('temp_aiResponse', data.response);
|
||||
|
||||
// Redirect to the cards page with the new project ID and title
|
||||
router.push(`/cards?projectId=${encodeURIComponent(projectId)}&projectTitle=${encodeURIComponent(projectTitle)}`);
|
||||
|
||||
// FIX 2 (Unexpected any): Changed 'any' to 'unknown' and added a type check.
|
||||
} catch (error: unknown) {
|
||||
console.error("Request Failed:", error);
|
||||
@@ -127,10 +135,7 @@ export default function Home() {
|
||||
}
|
||||
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
|
||||
}, []);
|
||||
}, [router]);
|
||||
|
||||
// Replaced useEffect
|
||||
useEffect(() => {
|
||||
|
||||
@@ -1,32 +1,3 @@
|
||||
<<<<<<< HEAD
|
||||
=======
|
||||
/* @import "tailwindcss";
|
||||
|
||||
:root {
|
||||
--background: #ffffff;
|
||||
--foreground: #171717;
|
||||
}
|
||||
|
||||
:root {
|
||||
--color-background: var(--background);
|
||||
--color-foreground: var(--foreground);
|
||||
--font-sans: var(--font-geist-sans);
|
||||
--font-mono: var(--font-geist-mono);
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
:root {
|
||||
--background: #0a0a0a;
|
||||
--foreground: #ededed;
|
||||
}
|
||||
}
|
||||
|
||||
body {
|
||||
background: var(--background);
|
||||
color: var(--foreground);
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
} */
|
||||
/* 1. Import BOTH fonts in one go */
|
||||
@import url('https://fonts.googleapis.com/css2?family=Concert+One&family=Pixelify+Sans:wght@400;700&display=swap');
|
||||
@import "tailwindcss";
|
||||
|
||||
@@ -41,15 +12,9 @@ body {
|
||||
|
||||
/* 3. Assign fonts to Tailwind's theme */
|
||||
|
||||
<<<<<<< HEAD
|
||||
/* Tell Tailwind to use the variables already defined in app/layout.tsx */
|
||||
--font-sans: var(--font-sans);
|
||||
--font-header: var(--font-header);
|
||||
=======
|
||||
/* --font-sans is for regular text (Concert One) */
|
||||
--font-sans: var(--font-concert-one);
|
||||
--font-header: var(--font-pixelify);
|
||||
>>>>>>> 44b5a4dc49ea757e9790ba8309edc6b37d764105
|
||||
|
||||
--font-mono: var(--font-geist-mono);
|
||||
}
|
||||
|
||||
+32
-25
@@ -1,6 +1,7 @@
|
||||
import React from "react";
|
||||
// import Image from "next/image"; // Removed Next.js import
|
||||
// import Link from "next/link"; // Removed Next.js import
|
||||
import Link from "next/link"; // Removed Next.js import
|
||||
|
||||
|
||||
export default function Home() {
|
||||
return (
|
||||
@@ -21,9 +22,6 @@ export default function Home() {
|
||||
<Link href="/Dashboard" className="hover:text-blue-600 dark:hover:text-blue-400 transition-colors">
|
||||
Dashboard
|
||||
</Link>
|
||||
<Link href="/cards" className="hover:text-blue-600 dark:hover:text-blue-400 transition-colors">
|
||||
Cards
|
||||
</Link>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
@@ -35,7 +33,7 @@ export default function Home() {
|
||||
style={{ color: "#173C46" }}
|
||||
className="max-w-xs text-5xl font-semibold leading-tight tracking-tight text-black"
|
||||
>
|
||||
Welcome! This is HackSpark
|
||||
Welcome! This is SparkBot
|
||||
</h1>
|
||||
<p
|
||||
style={{ color: "#173C46" }}
|
||||
@@ -44,12 +42,11 @@ export default function Home() {
|
||||
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!{" "}
|
||||
</p>
|
||||
|
||||
<Link
|
||||
href="/Dashboard"
|
||||
<button
|
||||
style={{ backgroundColor: "#173C46", color: "white" }}
|
||||
className="inline-block px-5 py-2.5 text-lg rounded-md shadow-md font-semibold hover:opacity-90 transition-opacity"
|
||||
>
|
||||
<Link href="/dashboard">Get Started</Link>
|
||||
<Link href="/Dashboard">Get Started</Link>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -58,7 +55,12 @@ export default function Home() {
|
||||
className="w-full max-w-[450px] h-[350px] rounded-xl shadow-md flex items-center justify-center text-white"
|
||||
style={{ backgroundColor: "#173C46" }}
|
||||
>
|
||||
Image Placeholder
|
||||
<img
|
||||
src="s1.jpeg"
|
||||
alt=" Img"
|
||||
width={350}
|
||||
height={350}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -81,11 +83,8 @@ export default function Home() {
|
||||
style={{ backgroundColor: "#B8C0AD" }}
|
||||
>
|
||||
<h2 className="text-3xl font-semibold text-black mb-3">
|
||||
First Text Block
|
||||
Input your hackathon preferences and team skills to get tailored project ideas.
|
||||
</h2>
|
||||
<p className="text-xl text-zinc-800">
|
||||
This is the content for the first text block. You can write anything here.
|
||||
</p>
|
||||
</div>
|
||||
{/* Box 2 (Image) - Standardized Size */}
|
||||
<div className="w-full max-w-lg flex justify-center items-center">
|
||||
@@ -93,7 +92,12 @@ export default function Home() {
|
||||
className="w-full h-[350px] rounded-xl shadow-md flex items-center justify-center text-zinc-800"
|
||||
style={{ backgroundColor: "#B8C0AD" }}
|
||||
>
|
||||
Image Placeholder
|
||||
<img
|
||||
src="s2.jpeg"
|
||||
alt=" Img"
|
||||
width={400}
|
||||
height={400}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -106,7 +110,12 @@ export default function Home() {
|
||||
className="w-full h-[350px] rounded-xl shadow-md flex items-center justify-center text-zinc-800"
|
||||
style={{ backgroundColor: "#B8C0AD" }}
|
||||
>
|
||||
Image Placeholder
|
||||
<img
|
||||
src="s3.jpeg"
|
||||
alt=" Img"
|
||||
width={400}
|
||||
height={400}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
{/* Box 4 (Text) - Standardized Size */}
|
||||
@@ -116,12 +125,8 @@ export default function Home() {
|
||||
style={{ backgroundColor: "#B8C0AD" }}
|
||||
>
|
||||
<h2 className="text-3xl font-semibold text-black mb-3">
|
||||
Second Text Block
|
||||
Choose between generated project ideas by swiping left or right on the cards.
|
||||
</h2>
|
||||
{/* Fixed the </D> typo to </p> */}
|
||||
<p className="text-xl text-zinc-800">
|
||||
This is the content for the second text block. You can write anything here.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -134,11 +139,8 @@ export default function Home() {
|
||||
style={{ backgroundColor: "#B8C0AD" }}
|
||||
>
|
||||
<h2 className="text-3xl font-semibold text-black mb-3">
|
||||
Third Text Block
|
||||
Work on your chosen project idea with your team using our integrated chat-based AI assistant.
|
||||
</h2>
|
||||
<p className="text-xl text-zinc-800">
|
||||
This is the content for the third text block. You can write anything here.
|
||||
</p>
|
||||
</div>
|
||||
{/* Box 6 (Image) - Standardized Size */}
|
||||
<div className="w-full max-w-lg flex justify-center items-center">
|
||||
@@ -146,7 +148,12 @@ export default function Home() {
|
||||
className="w-full h-[350px] rounded-xl shadow-md flex items-center justify-center text-zinc-800"
|
||||
style={{ backgroundColor: "#B8C0AD" }}
|
||||
>
|
||||
Image Placeholder
|
||||
<img
|
||||
src="s5.jpeg"
|
||||
alt=" Img"
|
||||
width={420}
|
||||
height={450}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -15,8 +15,8 @@ export async function chatToGemini(
|
||||
settings:ChatSetting
|
||||
):Promise<string>{
|
||||
const model = genAI.getGenerativeModel({
|
||||
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",
|
||||
model:settings.model || "gemini-2.5-flash-lite",
|
||||
systemInstruction: settings.systemInstructions || "you are going to create a project idea, explain it in summary first before going to detail",
|
||||
});
|
||||
|
||||
const generationConfig:GenerateConfig = {
|
||||
|
||||
Reference in New Issue
Block a user