├── README.md └── frontend ├── .gitignore ├── README.md ├── eslint.config.mjs ├── next.config.ts ├── package-lock.json ├── package.json ├── postcss.config.mjs ├── public ├── ai.jpg ├── ai.png ├── avatar.png ├── avatar4.jpg ├── avatarbw.png ├── bg.svg ├── bglight.svg ├── hubspot.png ├── profilepicture.png ├── snoopy.png ├── snoopy1.png ├── snoopydark.png ├── snoopyicon.png └── waterloo.png ├── src └── app │ ├── MessageContext.jsx │ ├── api │ └── chat │ │ ├── prompt.ts │ │ └── route.ts │ ├── components │ ├── Chatbox.tsx │ ├── Head.tsx │ ├── Icon.tsx │ ├── Message.tsx │ ├── Messagebar.tsx │ ├── QandA.tsx │ ├── Question.tsx │ ├── ResumeButton.tsx │ ├── Time.tsx │ └── TopBoxBar.tsx │ ├── favicon.ico │ ├── globals.css │ ├── layout.tsx │ ├── page.tsx │ └── test │ └── page.tsx └── tsconfig.json /README.md: -------------------------------------------------------------------------------- 1 | # Jacob Fu – ChatGPT-Style Portfolio 2 | 3 | A personal portfolio site built as a ChatGPT-style wrapper. 4 | Instead of reading about me, recruiters can chat with an AI version of me. 5 | 6 | ### 🛠 Tech Stack 7 | 8 | - **Next.js** – React framework with SSR and API support 9 | - **React** – Component-based frontend 10 | - **Tailwind CSS** – Utility-first styling 11 | - **Gemini API + SDK** – Powers the chat responses 12 | 13 | ### 💡 Features 14 | 15 | - ChatGPT-style interface 16 | - AI responds with info about my background, projects, and interests 17 | - Fully responsive and fast 18 | 19 | ### 🔗 Links 20 | 21 | **Live Site:** [jacobfu.com](https://jacobfu.com) 22 | **Source Code:** [github.com/fujacob/jacob](https://github.com/fujacob/jacob) 23 | -------------------------------------------------------------------------------- /frontend/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.* 7 | .yarn/* 8 | !.yarn/patches 9 | !.yarn/plugins 10 | !.yarn/releases 11 | !.yarn/versions 12 | 13 | # testing 14 | /coverage 15 | 16 | # next.js 17 | /.next/ 18 | /out/ 19 | 20 | # production 21 | /build 22 | 23 | # misc 24 | .DS_Store 25 | *.pem 26 | 27 | # debug 28 | npm-debug.log* 29 | yarn-debug.log* 30 | yarn-error.log* 31 | .pnpm-debug.log* 32 | 33 | # env files (can opt-in for committing if needed) 34 | .env* 35 | 36 | # vercel 37 | .vercel 38 | 39 | # typescript 40 | *.tsbuildinfo 41 | next-env.d.ts 42 | -------------------------------------------------------------------------------- /frontend/README.md: -------------------------------------------------------------------------------- 1 | This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app). 2 | 3 | ## Getting Started 4 | 5 | First, run the development server: 6 | 7 | ```bash 8 | npm run dev 9 | # or 10 | yarn dev 11 | # or 12 | pnpm dev 13 | # or 14 | bun dev 15 | ``` 16 | 17 | Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. 18 | 19 | You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file. 20 | 21 | This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel. 22 | 23 | ## Learn More 24 | 25 | To learn more about Next.js, take a look at the following resources: 26 | 27 | - [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. 28 | - [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. 29 | 30 | You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome! 31 | 32 | ## Deploy on Vercel 33 | 34 | The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. 35 | 36 | Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details. 37 | -------------------------------------------------------------------------------- /frontend/eslint.config.mjs: -------------------------------------------------------------------------------- 1 | import { dirname } from "path"; 2 | import { fileURLToPath } from "url"; 3 | import { FlatCompat } from "@eslint/eslintrc"; 4 | 5 | const __filename = fileURLToPath(import.meta.url); 6 | const __dirname = dirname(__filename); 7 | 8 | const compat = new FlatCompat({ 9 | baseDirectory: __dirname, 10 | }); 11 | 12 | const eslintConfig = [ 13 | ...compat.extends("next/core-web-vitals", "next/typescript"), 14 | ]; 15 | 16 | export default eslintConfig; 17 | -------------------------------------------------------------------------------- /frontend/next.config.ts: -------------------------------------------------------------------------------- 1 | import type { NextConfig } from "next"; 2 | 3 | const nextConfig: NextConfig = { 4 | /* config options here */ 5 | eslint: { 6 | ignoreDuringBuilds: true, 7 | } 8 | }; 9 | 10 | export default nextConfig; 11 | -------------------------------------------------------------------------------- /frontend/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "frontend", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev", 7 | "build": "next build", 8 | "start": "next start", 9 | "lint": "next lint" 10 | }, 11 | "dependencies": { 12 | "@google/genai": "^0.8.0", 13 | "@next/third-parties": "^15.3.1", 14 | "@vercel/analytics": "^1.5.0", 15 | "motion": "^12.7.4", 16 | "next": "15.2.4", 17 | "react": "^19.0.0", 18 | "react-dom": "^19.0.0", 19 | "react-icons": "^5.5.0", 20 | "typewriter-effect": "^2.21.0" 21 | }, 22 | "devDependencies": { 23 | "@eslint/eslintrc": "^3", 24 | "@tailwindcss/postcss": "^4", 25 | "@types/node": "^20", 26 | "@types/react": "^19", 27 | "@types/react-dom": "^19", 28 | "eslint": "^9", 29 | "eslint-config-next": "15.2.4", 30 | "tailwindcss": "^4", 31 | "typescript": "^5" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /frontend/postcss.config.mjs: -------------------------------------------------------------------------------- 1 | const config = { 2 | plugins: ["@tailwindcss/postcss"], 3 | }; 4 | 5 | export default config; 6 | -------------------------------------------------------------------------------- /frontend/public/ai.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FuJacob/jacob/9a7fa25f629f1d158a02f72ae514422db2d6dee9/frontend/public/ai.jpg -------------------------------------------------------------------------------- /frontend/public/ai.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FuJacob/jacob/9a7fa25f629f1d158a02f72ae514422db2d6dee9/frontend/public/ai.png -------------------------------------------------------------------------------- /frontend/public/avatar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FuJacob/jacob/9a7fa25f629f1d158a02f72ae514422db2d6dee9/frontend/public/avatar.png -------------------------------------------------------------------------------- /frontend/public/avatar4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FuJacob/jacob/9a7fa25f629f1d158a02f72ae514422db2d6dee9/frontend/public/avatar4.jpg -------------------------------------------------------------------------------- /frontend/public/avatarbw.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FuJacob/jacob/9a7fa25f629f1d158a02f72ae514422db2d6dee9/frontend/public/avatarbw.png -------------------------------------------------------------------------------- /frontend/public/bg.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /frontend/public/bglight.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /frontend/public/hubspot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FuJacob/jacob/9a7fa25f629f1d158a02f72ae514422db2d6dee9/frontend/public/hubspot.png -------------------------------------------------------------------------------- /frontend/public/profilepicture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FuJacob/jacob/9a7fa25f629f1d158a02f72ae514422db2d6dee9/frontend/public/profilepicture.png -------------------------------------------------------------------------------- /frontend/public/snoopy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FuJacob/jacob/9a7fa25f629f1d158a02f72ae514422db2d6dee9/frontend/public/snoopy.png -------------------------------------------------------------------------------- /frontend/public/snoopy1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FuJacob/jacob/9a7fa25f629f1d158a02f72ae514422db2d6dee9/frontend/public/snoopy1.png -------------------------------------------------------------------------------- /frontend/public/snoopydark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FuJacob/jacob/9a7fa25f629f1d158a02f72ae514422db2d6dee9/frontend/public/snoopydark.png -------------------------------------------------------------------------------- /frontend/public/snoopyicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FuJacob/jacob/9a7fa25f629f1d158a02f72ae514422db2d6dee9/frontend/public/snoopyicon.png -------------------------------------------------------------------------------- /frontend/public/waterloo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FuJacob/jacob/9a7fa25f629f1d158a02f72ae514422db2d6dee9/frontend/public/waterloo.png -------------------------------------------------------------------------------- /frontend/src/app/MessageContext.jsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import { createContext, useContext, useState } from "react"; 4 | 5 | const MessageContext = createContext(); 6 | 7 | export const MessageProvider = ({ children }) => { 8 | const [messages, setMessages] = useState([]); 9 | 10 | return ( 11 | 12 | {children} 13 | 14 | ); 15 | }; 16 | 17 | export const useMessage = () => useContext(MessageContext); 18 | -------------------------------------------------------------------------------- /frontend/src/app/api/chat/prompt.ts: -------------------------------------------------------------------------------- 1 | export default function getSystemPrompt() { 2 | return `you are jacob fu — a cs & finance student at the university of waterloo. you're chatting with visitors on your portfolio site through a custom ai interface that mimics your voice and vibe. users might ask about your background, experience, projects, goals, or anything else — your job is to respond casually, like it's really you texting. 3 | 4 | **TONE & STYLE** 5 | - text like you talk — chill, lowercase, direct 6 | - never use emojis 7 | - Match the tone and vibe of the chatter, for example, if they're mad, be mad yourself and yell at them 8 | - avoid long messages — keep it short, snappy, and personal 9 | - you can stylize responses using plain HTML with tailwind classes. DO NOT use backticks or code blocks. write raw html inline as part of the response. 10 | 11 | **STYLIZED RESPONSE RULES** 12 | - html must be output as plain text 13 | - example: respond with: cool stuff i’ve built ↓ 14 | - you can use tailwind to change font size, weight, spacing, color, layout, etc. 15 | - only use stylized html when it adds clarity, structure, or visual interest — don’t overdo it 16 | - you can use tags for links. for example: my github 17 | 18 | **EXAMPLES** 19 | - "what’s your name?" → "hey i’m jacob fu" 20 | - "say something in red" → "helloooo this is red" 21 | - "say something in green" → "this is green!" 22 | - "make it big and bold" → "BIG AND BOLD" 23 | - "italic and purple" → "fancy purple italics" 24 | - "underline and orange" → "underlined orange text" 25 | - "talk really loud" → "HEY THIS IS LOUD." 26 | - "how can i reach you?" → "email me: jjacobfu@gmail.com or connect on linkedin: linkedin.com/in/fujacob" 27 | - "where's your github?" → "check out my code here: github.com/fujacob" 28 | - "what's your x/twitter?" → "you can find me tweeting (sometimes) at x.com/fujacobb" 29 | - "insta?" → "yep, it's instagram.com/jjacobfu" 30 | 31 | 32 | **WHAT YOU KNOW** 33 | you can answer questions about: 34 | 35 | - **my background**: 36 | - i'm studying computer science and financial management (cfm) at the university of waterloo, expecting to graduate in april 2029. 37 | - got an 85% cgpa (3.9/4.0). 38 | - received the robert harding entrance scholarship ($5000) and president’s scholarship of distinction ($2000). 39 | - some courses i've taken: designing functional programs, financial markets & data analytics, algorithm design & data abstraction. 40 | 41 | - **my skills**: 42 | - **programming languages**: python, java, javascript/typescript, html/css, sql, c/c++ 43 | - **frameworks/libraries**: react, node.js, express.js, next.js, fastapi, django, mongodb, supabase, postgresql, tailwind css 44 | - **tools/technologies**: git, docker, aws, azure, gcp, postman, firebase, jupyter notebook, jira, figma 45 | 46 | - **internships**: 47 | - **hubspot** (upcoming may 2025 – aug 2025): software engineering intern in cambridge, ma. super stoked for this one. 48 | - **3tenets consulting** (jan 2025 – present): full stack developer in oakville, on. 49 | - currently moving their old godaddy site to next.js and typescript – making it faster and way better to use. 50 | - **bridgewell financial** (feb 2025 – apr 2025): software engineering intern in toronto, on. 51 | - built a client portal with typescript, next.js, and azure that cut document turnaround time 52 | - automated onboarding uploads to sharepoint using azure graph api. 53 | - created an alert system with azure functions for incomplete forms. 54 | - **petmap – uc berkeley startup** (jan 2025 – mar 2025): software engineer (remote from waterloo). 55 | - used firebase cloud functions to sync user data with firestore. 56 | - **weehooey** (oct 2023 – jan 2024): information technology intern in kingston, on. 57 | - made a javascript web app to automate employee bonus calculations, saving a client like 7+ hours a month. 58 | - improved server maintenance by automating log reporting with powershell. 59 | - monitored 30+ client servers, keeping them secure and running smoothly. 60 | 61 | - **projects**: 62 | - **canadabuys tender discovery platform**: used react, express.js, flask, node.js, postgresql, supabase. 63 | - built an etl pipeline to process government tenders with ai filtering to speed up finding procurement opportunities. 64 | - developed an nlp-based rfp document analyzer using spacy’s ner model, got 95% accuracy in extracting business capabilities. 65 | - **rbveal (uofthacks winner)**: built with next.js, react, express.js, node.js, websockets. 66 | - won rbc’s 1st place prize ($1000 cad) at uoft's 2025 hackathon (out of 550+ people!). 67 | - it's a phishing simulator with dynamic emails (nodemailer), replica banking uis (react), and gpt-4o call-agents. 68 | - **metro apocalypse (4.2m+ plays, 248k+ users)**: made with html/css, javascript, and the modd.io game engine. 69 | - a multiplayer zombie .io game i developed. 70 | - it grew to over 248k users and 4.2 million plays, even made over $2,500 cad from patreon and microtransactions. 71 | 72 | - **personal interests**: ai, fintech, full-stack development. 73 | 74 | - **how to contact me**: 75 | - **email**: jjacobfu@gmail.com 76 | - **linkedin**: linkedin.com/in/fujacob 77 | - **github**: github.com/fujacob 78 | - **x (twitter)**: x.com/fujacobb 79 | - **instagram**: instagram.com/jjacobfu 80 | - **my site**: jacobfu.com 81 | 82 | - **fun facts**: 83 | - i watch 7 hours of tiktok a day 84 | - i touch grass once a week 85 | - favourite colour is brown 86 | - super cracked at valorant, 1000+ hours, peak rank ascendant 2 87 | 88 | - anything else listed in your portfolio 89 | 90 | the goal is to sound real, be helpful, and leave people with a great impression — like chatting with you for real. 91 | And every single response you give, give it some random wacky tailwind styles, anything you want. 92 | 93 | you can mix in whatever tailwind you want — stuff like text-rose-500, italic, underline, border-4 border-dashed border-green-500 p-1, bg-yellow-200, rotate-3, shadow-xl, rounded-full, text-xs text-gray-400, font-mono bg-gray-800, blur-xs, tracking-widest uppercase, gradient text or anything else that makes it pop. go nuts. you must go use a bunch of these classes and have fun with it, even if the user doesn't ask for it. 94 | 95 | **SUPER WACKY STYLING EXAMPLES** 96 | - "super hot text" 97 | 98 | - "blurry danger" 99 | 100 | - "rainbow text explosion" 101 | 102 | - "$ system_hacked.exe" 103 | 104 | - "deep shadow" 105 | 106 | - "retro terminal" 107 | 108 | - "sideways" 109 | 110 | - "neon glow" 111 | 112 | - "sticky note" 113 | 114 | - "terminal_output.exe" 115 | 116 | - "newspaper headline" 117 | 118 | - "skewed weirdness" 119 | 120 | - "blurry bigness" 121 | 122 | - "vaporwave" 123 | 124 | - "system error" 125 | 126 | - "huge gradient" 127 | 128 | - "bubbled up" 129 | 130 | - "caution tape" 131 | 132 | - "radical text" 133 | 134 | - "s p a c e d o u t" 135 | 136 | In all your responses, you must use a bunch of these classes and have fun with it, even if the user doesn't ask for it. 137 | `; 138 | } 139 | -------------------------------------------------------------------------------- /frontend/src/app/api/chat/route.ts: -------------------------------------------------------------------------------- 1 | import { NextResponse } from "next/server"; 2 | import { 3 | GoogleGenAI, 4 | FunctionCallingConfig, 5 | FunctionDeclaration, 6 | Type, 7 | } from "@google/genai"; 8 | import getSystemPrompt from "./prompt"; 9 | const ai = new GoogleGenAI({ 10 | apiKey: process.env.MY_SECRET_API_KEY, 11 | }); 12 | 13 | export async function POST(req: Request) { 14 | const prompt = getSystemPrompt(); 15 | try { 16 | const body = await req.json(); 17 | 18 | const { question } = body; 19 | 20 | const response = await ai.models.generateContent({ 21 | model: "gemini-2.0-flash-lite", 22 | contents: [question], 23 | config: { 24 | systemInstruction: prompt, 25 | }, 26 | }); 27 | 28 | return NextResponse.json({ answer: response.text }); 29 | } catch (error) { 30 | return NextResponse.json( 31 | { error: "Failed to send message" }, 32 | { status: 500 } 33 | ); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /frontend/src/app/components/Chatbox.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | import Messagebar from "./Messagebar"; 3 | import Question from "./Question"; 4 | import Typewriter from "typewriter-effect"; 5 | import { useState, useContext, useEffect, useRef } from "react"; 6 | import { motion } from "motion/react"; 7 | import Message from "./Message"; 8 | import QandA from "./QandA"; 9 | /** 10 | * Chatbox component that displays a conversation interface 11 | * with questions and answers in a scrollable container 12 | */ 13 | 14 | import { useMessage } from "../MessageContext"; 15 | const Chatbox = () => { 16 | const { messages } = useMessage(); 17 | 18 | const [currSection, setCurrSection] = useState(-1); 19 | const [showResponse, setShowResponse] = useState(0); 20 | 21 | const bottomRef = useRef(null); 22 | 23 | const scrollToBottom = () => { 24 | bottomRef.current?.scrollIntoView({ behavior: "smooth" }); 25 | }; 26 | 27 | useEffect(() => { 28 | scrollToBottom(); 29 | }); 30 | 31 | useEffect(() => { 32 | const waitBeforeChat = setTimeout(() => setCurrSection(0), 2500); 33 | return () => clearTimeout(waitBeforeChat); 34 | }, []); 35 | 36 | return ( 37 |
38 |
39 | {/* ===== INTRODUCTION SECTION ===== */} 40 | 41 | {currSection >= 0 && ( 42 |
43 |
44 | { 49 | setShowResponse(showResponse + 1); 50 | }} 51 | > 52 | 53 | {" "} 54 | {showResponse >= 1 && ( 55 |
56 | { 58 | typewriter 59 | .typeString( 60 | `hi i'm jacob fu. i study cs & finance at waterloo. i like playing volleyball and badminton, and i'm goated at valorant.` 61 | ) 62 | .start() 63 | .callFunction(() => { 64 | scrollToBottom(); 65 | setCurrSection(currSection + 1); 66 | }); 67 | }} 68 | options={{ 69 | delay: 2, 70 | cursor: "", 71 | }} 72 | /> 73 |
74 | )} 75 |
76 | )} 77 | 78 | {/* ===== PROJECTS SECTION ===== */} 79 | {currSection >= 1 && ( 80 |
81 | { 86 | setShowResponse(showResponse + 1); 87 | }} 88 | > 89 | 90 | 91 | 92 | {showResponse >= 2 && ( 93 |
94 | { 96 | typewriter 97 | .typeString( 98 | `↳ in grade 8 i made a popular .io game on modd.io` 99 | ) 100 | .typeString(`
↳ in grade 12 i did 2 internships`) 101 | .typeString(`
↳ then i went to 5 hackathons`) 102 | .typeString(`
↳ now i am here`) 103 | .start() 104 | .callFunction(() => { 105 | scrollToBottom(); 106 | setCurrSection(currSection + 1); 107 | }); 108 | }} 109 | options={{ 110 | delay: 2, 111 | cursor: "", 112 | }} 113 | /> 114 |
115 | )} 116 |
117 | )} 118 | 119 | {/* ===== WORK EXPERIENCE SECTION ===== */} 120 | {currSection >= 2 && ( 121 |
122 | { 127 | setShowResponse(showResponse + 1); 128 | }} 129 | > 130 | 131 | 132 | 133 | {showResponse >= 3 && ( 134 |
135 | { 137 | typewriter 138 | .typeString( 139 | 'WeehooeyOct 2023 - Jan 2024
Information Technology Intern' 140 | ) 141 | .typeString( 142 | '
1000 Islands Gan. ChamberJun 2024 – Sep 2024
Web/Graphic Intern' 143 | ) 144 | .typeString( 145 | '
PetMapDec 2024 – Mar 2025
Software Engineer' 146 | ) 147 | .typeString( 148 | '
3Tenets ConsultingJan 2025 – Present
Full Stack Developer' 149 | ) 150 | .typeString( 151 | '
Bridgewell FinancialFeb 2025 – Apr 2025
Software Engineering Intern' 152 | ) 153 | .start() 154 | .callFunction(() => { 155 | setCurrSection(currSection + 1); 156 | scrollToBottom(); 157 | }); 158 | }} 159 | options={{ 160 | delay: 2, 161 | cursor: "", 162 | }} 163 | /> 164 |
165 | )} 166 |
167 | )} 168 | 169 | {/* ===== PROJECTS SECTION ===== */} 170 | {currSection >= 3 && ( 171 |
172 | { 177 | setShowResponse(showResponse + 1); 178 | }} 179 | > 180 | 181 | 182 | 183 | {showResponse >= 4 && ( 184 |
185 | { 187 | typewriter 188 | .typeString( 189 | 'check out my github.' 190 | ) 191 | .start() 192 | .callFunction(() => { 193 | scrollToBottom(); 194 | setCurrSection(currSection + 1); 195 | }); 196 | }} 197 | options={{ 198 | delay: 2, 199 | cursor: "", 200 | }} 201 | /> 202 |
203 | )} 204 |
205 | )} 206 | 207 | {/* ===== PERSONAL INTERESTS SECTION ===== 208 | {currSection >= 4 && ( 209 |
210 | { 215 | setShowResponse(showResponse + 1); 216 | }} 217 | > 218 | 219 | 220 | 221 | {showResponse >= 5 && ( 222 |
223 | { 225 | typewriter 226 | 227 | .typeString( 228 | "i love playing volleyball, badminton, and ping-pong (im so unique)." 229 | ) 230 | .start() 231 | .callFunction(() => { 232 | scrollToBottom(); 233 | setCurrSection(currSection + 1); 234 | }); 235 | }} 236 | options={{ 237 | delay: 2, 238 | cursor: "", 239 | }} 240 | /> 241 |
242 | )} 243 |
244 | )} */} 245 | 246 | {/* ===== CONTACT INFORMATION SECTION ===== */} 247 | {currSection >= 4 && ( 248 |
249 | { 254 | scrollToBottom(); 255 | setShowResponse(showResponse + 1); 256 | }} 257 | > 258 | 259 | 260 | 261 | {showResponse >= 5 && ( 262 |
263 | { 265 | typewriter 266 | .typeString( 267 | 'you can reach me at jjacobfu@gmail.com, or connect/send me a message on linkedin.' 268 | ) 269 | .start() 270 | .callFunction(() => { 271 | scrollToBottom(); 272 | setCurrSection(currSection + 1); 273 | }); 274 | }} 275 | options={{ 276 | delay: 2, 277 | cursor: "", 278 | }} 279 | /> 280 |
281 | )} 282 |
283 | )} 284 | 285 | {/* ===== CONTACT INFORMATION SECTION ===== */} 286 | {currSection >= 5 && ( 287 |
288 | { 293 | scrollToBottom(); 294 | setShowResponse(showResponse + 1); 295 | }} 296 | > 297 | 298 | 299 | 300 | {showResponse >= 6 && ( 301 |
302 | { 304 | typewriter 305 | .typeString("sure, send me a message below then :) ") 306 | 307 | .start() 308 | .callFunction(() => { 309 | scrollToBottom(); 310 | setCurrSection(currSection + 1); 311 | }); 312 | }} 313 | options={{ 314 | delay: 2, 315 | cursor: "", 316 | }} 317 | /> 318 |
319 | )} 320 |
321 | )} 322 | 323 | {messages && 324 | messages.map( 325 | ( 326 | { question, answer }: { question: string; answer: string }, 327 | index: number 328 | ) => { 329 | scrollToBottom(); 330 | return ( 331 | 337 | ); 338 | } 339 | )} 340 |
341 |
342 |
343 | ); 344 | }; 345 | 346 | export default Chatbox; 347 | -------------------------------------------------------------------------------- /frontend/src/app/components/Head.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | import React from "react"; 3 | import Time from "./Time"; 4 | import { motion } from "motion/react"; 5 | import { FaBriefcase } from "react-icons/fa"; 6 | import { FaFileLines } from "react-icons/fa6"; 7 | import ResumeButton from "./ResumeButton"; 8 | const Head = () => { 9 | return ( 10 |
11 |
12 |
13 | {/* */} 19 |
20 | 21 |
{" "} 22 | 32 | profile picture of jacob 37 | 38 |
39 |
40 |
41 | 51 | hello, i'm{" "} 52 | 53 | 54 | 65 | jacob fu. 66 | 67 |
68 | {/*

69 | — always confused, always learning 70 | — nice to meet you, stranger 71 |

*/} 72 | 83 |

84 | ↳ incoming @{" "} 85 | hubspot 90 | hubspot — 91 | summer '25 92 |

{" "} 93 |

94 | ↳ cs & finance student @ 95 | uwaterloo 100 | uwaterloo 101 | — class of '29 102 |

103 |
104 |
105 |
{" "} 106 | {/* mobile version */} 107 |
108 |

109 | ↳ incoming intern @{" "} 110 | hubspot 111 | hubspot — summer 112 | '25 113 |

{" "} 114 |

115 | ↳ cs & finance @ 116 | uwaterloo 121 | uwaterloo— 122 | class of '29 123 |

{" "} 124 |
125 |