Skip to content

Commit

Permalink
docs: update README with accurate file structure and personalization …
Browse files Browse the repository at this point in the history
…guide

- Update personalization guide with correct file paths
- Organize sections based on actual project structure
- Add component-specific instructions
- Update environment variables section
- Fix chat component types and error handling
  • Loading branch information
while-basic committed Dec 1, 2024
1 parent b0dced4 commit b8009ae
Show file tree
Hide file tree
Showing 6 changed files with 193 additions and 89 deletions.
162 changes: 126 additions & 36 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,132 @@ The workflow checks:
- ESLint linting
- Next.js build process

## Personalizing Your Portfolio

After forking this repository, you'll need to update various files with your personal information. Here's a comprehensive guide based on the actual project structure:

### 1. Core Components
- **Navbar** (`/components/navbar.tsx`)
- Update navigation links
- Modify logo and branding
- Customize menu items

- **Hero Section** (`/components/hero.tsx`)
- Update main headline
- Modify tagline and description
- Change call-to-action buttons

- **Layout** (`/app/layout.tsx`)
- Update metadata and SEO settings
- Modify default page structure
- Customize loading screen

### 2. Main Pages
- **Home Page** (`/app/page.tsx`)
- Update hero content
- Modify featured projects
- Customize welcome message

- **About Page** (`/app/about/page.tsx`)
- Update biography
- Modify personal story
- Add professional background

- **Projects** (`/app/projects/page.tsx`)
- Update project cards (`/components/project-card.tsx`)
- Add your own projects
- Customize project descriptions

- **Experience** (`/app/experience/page.tsx`)
- Update work history (`/components/experience-card.tsx`)
- Add education details (`/components/education-card.tsx`)
- Modify role descriptions

### 3. Skills and Expertise
- **Skills Page** (`/app/skills/page.tsx`)
- Update skill sections (`/components/skills-section.tsx`)
- Modify skill cards (`/components/skill-card.tsx`)
- Customize tag cloud (`/components/skills-tag-cloud.tsx`)

### 4. Interactive Features
- **Gallery** (`/app/gallery/page.tsx`)
- Update gallery items (`/components/gallery-item.tsx`)
- Modify filters (`/components/gallery-filter.tsx`)
- Add your own images

- **Chat** (`/app/chat/page.tsx`)
- Customize chat interface
- Update AI settings
- Modify authentication requirements

- **Audio** (`/app/audio/page.tsx`)
- Add your audio content
- Update audio player settings
- Customize audio descriptions

### 5. Professional Content
- **Resume** (`/app/resume/page.tsx`)
- Update resume content
- Add professional experience
- Upload new resume PDF

- **Case Studies** (`/app/case-studies/page.tsx`)
- Add detailed project analyses
- Include project outcomes
- Update metrics and results

### 6. Blog
- **Blog Posts** (`/app/blog/`)
- Add your own posts
- Update blog layout
- Customize categories

### 7. Environment Variables
Create a `.env.local` file with these variables:
```bash
# Authentication
NEXTAUTH_URL=http://localhost:3000
NEXTAUTH_SECRET=your-secret-key

# OpenAI (for Chat Feature)
OPENAI_API_KEY=your-openai-key

# Supabase
NEXT_PUBLIC_SUPABASE_URL=your-supabase-url
NEXT_PUBLIC_SUPABASE_ANON_KEY=your-supabase-key

# Email (for Contact Form)
RESEND_API_KEY=your-resend-key
```

### 8. Assets and Media
- **Public Directory** (`/public/`)
- Replace profile images
- Update project screenshots
- Add custom icons and media
- Update resume PDF
- Modify audio files

### 9. UI Components
- **Custom Components** (`/components/ui/`)
- Customize button styles
- Update card designs
- Modify form elements
- Adjust animations

### 10. Additional Features
- **Dashboard** (`/app/dashboard/page.tsx`)
- Configure visitor counter
- Set up analytics
- Customize admin features

Remember to:
1. Test all changes locally using `npm run dev`
2. Verify responsive design on multiple devices
3. Check all links and media work correctly
4. Update SEO metadata for all pages
5. Remove placeholder content

## Todos should be completed starting from the most easiest to implement. The Todo list should be updated periodically and in order from easiest to most difficult for the AI to implement.

- [-] Initial setup
Expand Down Expand Up @@ -175,42 +301,6 @@ Built using:
- [shadcn/ui](https://ui.shadcn.com/)
- [shadcn/ui-docs](https://ui.shadcn.com/docs)

## Personalizing Your Fork

After forking this repository, you'll need to update the following:

### Required Updates
1. **Personal Information**
- `/app/config/site.ts`: Update site metadata, name, and social links
- `/app/components/about.tsx`: Modify the about section content
- `/app/components/hero.tsx`: Update hero section with your name and title
- `/public/images/`: Replace profile and project images

2. **Project Details**
- `/app/projects/page.tsx`: Update project cards with your own projects
- `/app/projects/[slug]/page.tsx`: Create case studies for your projects

3. **Resume and Experience**
- `/app/resume/page.tsx`: Update with your experience and education
- `/public/resume.pdf`: Replace with your resume file

4. **Environment Variables**
- Copy `.env.example` to `.env.local`
- Update the following variables:
```
DATABASE_URL=your_database_url
NEXT_PUBLIC_SUPABASE_URL=your_supabase_url
NEXT_PUBLIC_SUPABASE_ANON_KEY=your_supabase_key
RESEND_API_KEY=your_resend_api_key
```
### Optional Updates
- `/app/blog/`: Add your own blog posts
- `/app/components/footer.tsx`: Update footer links and information
- `/app/components/nav.tsx`: Modify navigation items
- `/public/favicon.ico`: Replace with your own favicon
- `/app/layout.tsx`: Update metadata and default SEO settings
## Development Notes

### Git Commands
Expand Down
3 changes: 1 addition & 2 deletions app/chat/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,10 @@

import { useState, useEffect } from "react"
import { Button } from "@/components/ui/button"
import { ArrowLeft, Bot } from "lucide-react"
import { ArrowLeft } from "lucide-react"
import Link from "next/link"
import { MessageList, type Message } from "@/components/chat/message-list"
import { ChatInput } from "@/components/chat/chat-input"
import { motion, AnimatePresence } from "framer-motion"
import { useAuth } from "@/lib/auth-context"
import { AuthDialog } from "@/components/chat/auth-dialog"
import { Breadcrumb } from "@/components/breadcrumb"
Expand Down
18 changes: 9 additions & 9 deletions components/chat/chat-input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,15 @@ import { SendHorizontal } from "lucide-react"

interface ChatInputProps {
onSend: (message: string) => void
disabled?: boolean
isLoading?: boolean
}

export function ChatInput({ onSend, disabled }: ChatInputProps) {
export function ChatInput({ onSend, isLoading }: ChatInputProps) {
const [input, setInput] = useState("")

const handleSubmit = (e: React.FormEvent) => {
e.preventDefault()
if (input.trim()) {
if (input.trim() && !isLoading) {
onSend(input)
setInput("")
}
Expand All @@ -34,17 +34,17 @@ export function ChatInput({ onSend, disabled }: ChatInputProps) {
value={input}
onChange={(e) => setInput(e.target.value)}
onKeyDown={handleKeyDown}
placeholder="Type a message..."
className="min-h-[60px] w-full resize-none rounded-lg border bg-background pr-16 shadow-sm focus:ring-2 focus:ring-primary/20"
disabled={disabled}
placeholder="Type your message..."
className="min-h-[80px] resize-none pr-14"
disabled={isLoading}
/>
<Button
type="submit"
size="icon"
className="absolute right-2 top-1/2 -translate-y-1/2 bg-primary hover:bg-primary/90"
disabled={disabled || !input.trim()}
className="absolute bottom-2 right-2"
disabled={!input.trim() || isLoading}
>
<SendHorizontal className="h-4 w-4" />
<SendHorizontal className="h-5 w-5" />
</Button>
</form>
)
Expand Down
51 changes: 30 additions & 21 deletions components/chat/message-list.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,10 @@ export type Message = {

interface MessageListProps {
messages: Message[]
isLoading?: boolean
}

export function MessageList({ messages }: MessageListProps) {
export function MessageList({ messages, isLoading }: MessageListProps) {
return (
<div className="flex flex-col gap-6">
{messages.map((message, index) => (
Expand All @@ -20,35 +21,43 @@ export function MessageList({ messages }: MessageListProps) {
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.3 }}
className={`flex gap-3 ${
message.role === "user" ? "flex-row-reverse" : ""
message.role === "assistant" ? "flex-row" : "flex-row-reverse"
}`}
>
<div className={`flex h-8 w-8 shrink-0 select-none items-center justify-center rounded-md border ${
message.role === "user"
? "bg-primary text-primary-foreground"
: "bg-muted"
}`}>
{message.role === "user" ? (
<User className="h-4 w-4" />
<div
className={`flex h-8 w-8 shrink-0 select-none items-center justify-center rounded-md border shadow ${
message.role === "assistant"
? "bg-primary text-primary-foreground"
: "bg-muted"
}`}
>
{message.role === "assistant" ? (
<Bot className="h-5 w-5" />
) : (
<Bot className="h-4 w-4" />
<User className="h-5 w-5" />
)}
</div>
<div className={`flex flex-col gap-2 ${
message.role === "user" ? "items-end" : "items-start"
}`}>
<div className={`rounded-lg px-4 py-2 max-w-[85%] shadow-sm ${
message.role === "user"
? "bg-primary text-primary-foreground"
: "bg-muted"
}`}>
<p className="text-sm whitespace-pre-wrap break-words">
{message.content}
</p>
<div className="flex-1 space-y-2">
<div className="prose prose-neutral dark:prose-invert">
{message.content}
</div>
</div>
</motion.div>
))}
{isLoading && (
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
className="flex gap-3"
>
<div className="flex h-8 w-8 shrink-0 items-center justify-center rounded-md border bg-primary text-primary-foreground shadow">
<Bot className="h-5 w-5" />
</div>
<div className="flex-1 space-y-2">
<div className="h-4 w-12 animate-pulse rounded bg-muted"></div>
</div>
</motion.div>
)}
</div>
)
}
14 changes: 10 additions & 4 deletions lib/openai.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ const openai = new OpenAI({
apiKey: process.env.OPENAI_API_KEY,
});

interface OpenAIError extends Error {
code?: string;
}

// Implement exponential backoff for rate limiting
async function withRetry<T>(
fn: () => Promise<T>,
Expand All @@ -15,8 +19,9 @@ async function withRetry<T>(
while (true) {
try {
return await fn();
} catch (error: any) {
if (error?.code === 'rate_limit_exceeded' && retries < maxRetries) {
} catch (error) {
const openAIError = error as OpenAIError;
if (openAIError.code === 'rate_limit_exceeded' && retries < maxRetries) {
retries++;
const delay = initialDelay * Math.pow(2, retries - 1);
console.log(`Rate limit exceeded. Retrying in ${delay}ms...`);
Expand Down Expand Up @@ -45,7 +50,7 @@ export async function generateChatResponse(
try {
const completion = await withRetry(() =>
openai.chat.completions.create({
model: "gpt-4", // Using GPT-4
model: "gpt-4o", // Using GPT-4
messages: messages,
temperature: finalSettings.temperature,
max_tokens: finalSettings.maxTokens,
Expand All @@ -58,7 +63,8 @@ export async function generateChatResponse(
return completion.choices[0].message;
} catch (error) {
console.error('Error calling OpenAI:', error);
if (error?.code === 'rate_limit_exceeded') {
const openAIError = error as OpenAIError;
if (openAIError.code === 'rate_limit_exceeded') {
throw new Error('Rate limit exceeded. Please try again in a few minutes.');
}
throw error;
Expand Down
34 changes: 17 additions & 17 deletions public/sitemap.xml
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:news="http://www.google.com/schemas/sitemap-news/0.9" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:mobile="http://www.google.com/schemas/sitemap-mobile/1.0" xmlns:image="http://www.google.com/schemas/sitemap-image/1.1" xmlns:video="http://www.google.com/schemas/sitemap-video/1.1">
<url><loc>https://chriscelaya.com/audio-recorder</loc><lastmod>2024-12-01T11:58:28.933Z</lastmod><changefreq>weekly</changefreq><priority>0.7</priority></url>
<url><loc>https://chriscelaya.com/blog/hello-world</loc><lastmod>2024-12-01T11:58:28.934Z</lastmod><changefreq>weekly</changefreq><priority>0.7</priority></url>
<url><loc>https://chriscelaya.com/blog</loc><lastmod>2024-12-01T11:58:28.934Z</lastmod><changefreq>weekly</changefreq><priority>0.7</priority></url>
<url><loc>https://chriscelaya.com/auth/sign-in</loc><lastmod>2024-12-01T11:58:28.934Z</lastmod><changefreq>weekly</changefreq><priority>0.7</priority></url>
<url><loc>https://chriscelaya.com/case-studies</loc><lastmod>2024-12-01T11:58:28.934Z</lastmod><changefreq>weekly</changefreq><priority>0.9</priority></url>
<url><loc>https://chriscelaya.com/dashboard</loc><lastmod>2024-12-01T11:58:28.934Z</lastmod><changefreq>weekly</changefreq><priority>0.7</priority></url>
<url><loc>https://chriscelaya.com/chat</loc><lastmod>2024-12-01T11:58:28.934Z</lastmod><changefreq>weekly</changefreq><priority>0.7</priority></url>
<url><loc>https://chriscelaya.com/auth/sign-up</loc><lastmod>2024-12-01T11:58:28.934Z</lastmod><changefreq>weekly</changefreq><priority>0.7</priority></url>
<url><loc>https://chriscelaya.com/profile</loc><lastmod>2024-12-01T11:58:28.934Z</lastmod><changefreq>weekly</changefreq><priority>0.7</priority></url>
<url><loc>https://chriscelaya.com</loc><lastmod>2024-12-01T11:58:28.934Z</lastmod><changefreq>weekly</changefreq><priority>1</priority></url>
<url><loc>https://chriscelaya.com/gallery</loc><lastmod>2024-12-01T11:58:28.934Z</lastmod><changefreq>weekly</changefreq><priority>0.7</priority></url>
<url><loc>https://chriscelaya.com/skills</loc><lastmod>2024-12-01T11:58:28.934Z</lastmod><changefreq>weekly</changefreq><priority>0.7</priority></url>
<url><loc>https://chriscelaya.com/resume</loc><lastmod>2024-12-01T11:58:28.934Z</lastmod><changefreq>weekly</changefreq><priority>0.7</priority></url>
<url><loc>https://chriscelaya.com/projects</loc><lastmod>2024-12-01T11:58:28.934Z</lastmod><changefreq>weekly</changefreq><priority>0.9</priority></url>
<url><loc>https://chriscelaya.com/about</loc><lastmod>2024-12-01T11:58:28.934Z</lastmod><changefreq>weekly</changefreq><priority>0.8</priority></url>
<url><loc>https://chriscelaya.com/experience</loc><lastmod>2024-12-01T11:58:28.934Z</lastmod><changefreq>weekly</changefreq><priority>0.8</priority></url>
<url><loc>https://chriscelaya.com/audio</loc><lastmod>2024-12-01T11:58:28.934Z</lastmod><changefreq>weekly</changefreq><priority>0.7</priority></url>
<url><loc>https://chriscelaya.com/about</loc><lastmod>2024-12-01T12:32:13.749Z</lastmod><changefreq>weekly</changefreq><priority>0.8</priority></url>
<url><loc>https://chriscelaya.com/blog</loc><lastmod>2024-12-01T12:32:13.750Z</lastmod><changefreq>weekly</changefreq><priority>0.7</priority></url>
<url><loc>https://chriscelaya.com/case-studies</loc><lastmod>2024-12-01T12:32:13.750Z</lastmod><changefreq>weekly</changefreq><priority>0.9</priority></url>
<url><loc>https://chriscelaya.com/audio-recorder</loc><lastmod>2024-12-01T12:32:13.750Z</lastmod><changefreq>weekly</changefreq><priority>0.7</priority></url>
<url><loc>https://chriscelaya.com/chat</loc><lastmod>2024-12-01T12:32:13.750Z</lastmod><changefreq>weekly</changefreq><priority>0.7</priority></url>
<url><loc>https://chriscelaya.com/gallery</loc><lastmod>2024-12-01T12:32:13.750Z</lastmod><changefreq>weekly</changefreq><priority>0.7</priority></url>
<url><loc>https://chriscelaya.com</loc><lastmod>2024-12-01T12:32:13.750Z</lastmod><changefreq>weekly</changefreq><priority>1</priority></url>
<url><loc>https://chriscelaya.com/auth/sign-in</loc><lastmod>2024-12-01T12:32:13.750Z</lastmod><changefreq>weekly</changefreq><priority>0.7</priority></url>
<url><loc>https://chriscelaya.com/profile</loc><lastmod>2024-12-01T12:32:13.750Z</lastmod><changefreq>weekly</changefreq><priority>0.7</priority></url>
<url><loc>https://chriscelaya.com/dashboard</loc><lastmod>2024-12-01T12:32:13.750Z</lastmod><changefreq>weekly</changefreq><priority>0.7</priority></url>
<url><loc>https://chriscelaya.com/audio</loc><lastmod>2024-12-01T12:32:13.750Z</lastmod><changefreq>weekly</changefreq><priority>0.7</priority></url>
<url><loc>https://chriscelaya.com/experience</loc><lastmod>2024-12-01T12:32:13.750Z</lastmod><changefreq>weekly</changefreq><priority>0.8</priority></url>
<url><loc>https://chriscelaya.com/projects</loc><lastmod>2024-12-01T12:32:13.750Z</lastmod><changefreq>weekly</changefreq><priority>0.9</priority></url>
<url><loc>https://chriscelaya.com/blog/hello-world</loc><lastmod>2024-12-01T12:32:13.750Z</lastmod><changefreq>weekly</changefreq><priority>0.7</priority></url>
<url><loc>https://chriscelaya.com/resume</loc><lastmod>2024-12-01T12:32:13.750Z</lastmod><changefreq>weekly</changefreq><priority>0.7</priority></url>
<url><loc>https://chriscelaya.com/auth/sign-up</loc><lastmod>2024-12-01T12:32:13.750Z</lastmod><changefreq>weekly</changefreq><priority>0.7</priority></url>
<url><loc>https://chriscelaya.com/skills</loc><lastmod>2024-12-01T12:32:13.750Z</lastmod><changefreq>weekly</changefreq><priority>0.7</priority></url>
</urlset>

0 comments on commit b8009ae

Please sign in to comment.