A modern, interactive portfolio website built with Jekyll, featuring a sleek tech-themed design perfect for developers and tech professionals (or anyone interested!). The idea is to, well, get hired!
A responsive, professional portfolio website template with modern animations and interactive elements. Completely free to use and deploy
Before you begin, make sure you have:
brew install ruby
(macOS)gem install bundler
Clone the repository
git clone https://github.com/yourusername/your-portfolio.git
cd your-portfolio
Install dependencies
bundle install
Start the development server
bundle exec jekyll serve
Open your browser
Visit: http://localhost:4000
Your site will automatically reload when you make changes!
Your portfolio includes a fully functional contact form with Google Forms backend, email notifications, and spam protection. Here's how to set it up:
Go to forms.google.com
Click "Blank Form"
Set form title: "Portfolio Contact Form"
Add these EXACT fields:
Question 1: Name
- Type: Short answer
- Required: YES
Question 2: Email
- Type: Short answer
- Required: YES
Question 3: Subject
- Type: Short answer
- Required: YES
Question 4: Message
- Type: Paragraph
- Required: YES
Responses
tab// =====================================================================================
// PORTFOLIO CONTACT FORM - Google Apps Script Email Notifications
// =====================================================================================
const CONFIG = {
YOUR_EMAIL: '[email protected]', // ๐ฅ UPDATE THIS!
SEND_AUTO_RESPONDER: true,
EMAIL_SIGNATURE: 'Your Name' // ๐ฅ UPDATE THIS!
};
function onFormSubmit(e) {
try {
const values = e.values;
const [timestamp, name, email, subject, message] = values;
// Send notification to you
sendNotificationEmail({ timestamp, name, email, subject, message });
// Send confirmation to form submitter
if (CONFIG.SEND_AUTO_RESPONDER) {
sendAutoResponder({ name, email, subject });
}
console.log('โ
Emails sent successfully');
} catch (error) {
console.error('โ Error:', error);
}
}
function sendNotificationEmail(data) {
const subject = `๐ New Portfolio Contact: ${data.subject}`;
const htmlBody = `
<div style="font-family: 'Segoe UI', Arial, sans-serif; max-width: 900px; margin: 0 auto; border: 1px solid #e0e0e0; border-radius: 8px;">
<div style="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); padding: 30px; color: white; text-align: center;">
<h2 style="margin: 0; font-size: 28px;">๐ New Portfolio Contact</h2>
<p style="margin: 10px 0 0 0; opacity: 0.9;">Professional inquiry received</p>
</div>
<div style="background: #f8f9fa; padding: 30px;">
<div style="background: white; padding: 25px; border-radius: 8px; border-left: 4px solid #667eea;">
<table style="width: 100%;">
<tr>
<td style="width: 50%; padding-right: 20px;">
<strong>๐ค Name:</strong> ${data.name}<br>
<strong>๐ง Email:</strong> <a href="mailto:${data.email}">${data.email}</a>
</td>
<td style="width: 50%; border-left: 1px solid #e9ecef; padding-left: 20px;">
<strong>๐ Subject:</strong> ${data.subject}<br>
<strong>โฐ Time:</strong> ${data.timestamp}
</td>
</tr>
</table>
</div>
</div>
<div style="background: white; padding: 30px;">
<h3 style="margin: 0 0 20px 0; color: #495057;">๐ฌ Message:</h3>
<div style="background: #f8f9fa; padding: 25px; border-left: 4px solid #28a745; border-radius: 8px;">
<p style="margin: 0; line-height: 1.7; color: #495057;">${data.message.replace(/\n/g, '<br>')}</p>
</div>
</div>
<div style="background: #f8f9fa; padding: 25px; text-align: center;">
<a href="mailto:${data.email}?subject=Re: ${data.subject}"
style="background: #667eea; color: white; padding: 15px 30px; text-decoration: none; border-radius: 6px; font-weight: 600;">
๐ง Reply to ${data.name}
</a>
</div>
</div>
`;
MailApp.sendEmail({
to: CONFIG.YOUR_EMAIL,
subject: subject,
htmlBody: htmlBody,
replyTo: data.email
});
}
function sendAutoResponder(data) {
const subject = `โ
Thank you for your message, ${data.name}!`;
const htmlBody = `
<div style="font-family: 'Segoe UI', Arial, sans-serif; max-width: 900px; margin: 0 auto; border: 1px solid #e0e0e0; border-radius: 8px;">
<div style="background: linear-gradient(135deg, #28a745 0%, #20c997 100%); padding: 30px; color: white; text-align: center;">
<h2 style="margin: 0; font-size: 28px;">โ
Message Received</h2>
<p style="margin: 10px 0 0 0; opacity: 0.9;">Thank you for reaching out!</p>
</div>
<div style="background: white; padding: 40px;">
<p style="font-size: 18px; margin: 0 0 20px 0;"><strong>Hello ${data.name},</strong></p>
<p style="margin: 0 0 25px 0; line-height: 1.7; color: #6c757d;">
Thank you for reaching out through my portfolio! I've received your message regarding
"<strong>${data.subject}</strong>" and appreciate you taking the time to connect.
</p>
<div style="background: #f8f9fa; padding: 25px; border-left: 4px solid #28a745; margin: 25px 0; text-align: center;">
<p style="margin: 0; font-weight: 500;"><span style="color: #28a745;">โก</span> I'll respond within 24 hours</p>
</div>
<p style="margin: 0; line-height: 1.7; color: #6c757d;">
Best regards,<br>
<strong>${CONFIG.EMAIL_SIGNATURE}</strong><br>
<span style="color: #adb5bd;">Portfolio & Professional Services</span>
</p>
</div>
</div>
`;
MailApp.sendEmail({
to: data.email,
subject: subject,
htmlBody: htmlBody,
replyTo: CONFIG.YOUR_EMAIL
});
}
// Test function - run this to test email notifications
function testEmails() {
const testData = {
timestamp: new Date().toLocaleString(),
name: "Test Contact",
email: CONFIG.YOUR_EMAIL,
subject: "System Test",
message: "This is a test message to verify the email system works correctly."
};
sendNotificationEmail(testData);
sendAutoResponder(testData);
console.log('โ
Test emails sent!');
}
Update the CONFIG section:
const CONFIG = {
YOUR_EMAIL: '[email protected]', // Your actual email
SEND_AUTO_RESPONDER: true,
EMAIL_SIGNATURE: 'Your Name' // Your actual name
};
Save the project (Ctrl+S or File โ Save)
onFormSubmit
From spreadsheet
On form submit
Get Form ID:
https://docs.google.com/forms/d/FORM_ID_HERE/viewform
Get Entry IDs:
View Page Source
and look for the 4 different form boxes (e.g, Name, Email, Subject, Message)[[
character space. This is where the form id is located (e.g., 000000000)<div jsmodel="CP1oW" data-params="%.@.[1234567890,"Message",null,0,[[000000000,null,true,null,null,null,null,null,null,null,[]]],null,null,null,null,null,null,[null,"Message"]] <!-- Message field -->
In your assets/js/main.js
, update the configuration:
const CONTACT_FORM_CONFIG = {
formId: 'YOUR_ACTUAL_FORM_ID_HERE', // From Step 5
fields: {
name: 'entry.YOUR_NAME_ENTRY_ID', // From Step 5
email: 'entry.YOUR_EMAIL_ENTRY_ID', // From Step 5
subject: 'entry.YOUR_SUBJECT_ENTRY_ID', // From Step 5
message: 'entry.YOUR_MESSAGE_ENTRY_ID' // From Step 5
},
fallbackEmail: '[email protected]' // Your email
};
Test the Apps Script:
testEmails()
functionTest the Live Form:
Troubleshooting:
โ
Spam protection via Google Forms
โ
Custom HTML email notifications
โ
Auto-responder for form submitters
โ
Automatic data storage in Google Sheets
โ
Mobile-friendly emails
โ
Easy maintenance through Google's interface
โ
100% free - no hosting costs
Setup Time: ~5 minutes | Maintenance: Zero
All your content is managed through two main files:
File: _data/portfolio.yml
This YAML file contains all your personal information, experience, and projects. Here's how to edit each section:
๐ค Personal Information:
personal:
name: "Your Full Name" # Appears in hero section
title: "Your Professional Title" # Job title/role
tagline: "// Your Personal Motto" # Appears under title
logo: "Y.N" # Your initials for navigation
email: "[email protected]" # Contact email
phone: "+1 (555) 123-4567" # Phone number
location: "Your City, State" # Where you're located
linkedin: "linkedin.com/in/yourprofile" # LinkedIn profile
github: "github.com/yourusername" # GitHub profile
profileImage: "/assets/img/profile.jpg" # Path to your photo
bio: # About section paragraphs
- "First paragraph about your background..."
- "Second paragraph about your interests..."
- "Third paragraph about your philosophy..."
๐ผ Professional Experience:
experience:
- title: "Your Job Title" # Position name
company: "Company Name" # Employer
period: "2022 - Present" # Employment dates
description: "What you accomplished in this role..."
๐ Education:
education:
- degree: "Bachelor of Computer Science" # Degree name
institution: "University Name" # School name
period: "2016 - 2020" # Dates attended
description: "Relevant coursework, honors, etc."
๐ Certifications:
certifications:
- name: "AWS Certified" # Certification name
issuer: "Amazon Web Services" # Issuing organization
year: "2023" # Year obtained
๐ป Skills:
skills:
- category: "Programming" # E.g., "Programming Languages"
icon: "โก" # Emoji icon for visual appeal
tags: # List of specific skills
- "Python"
- "JavaScript"
- "React"
๐ Projects:
projects:
- title: "Project Name" # Project title
icon: "๐ค" # Emoji icon
description: "Brief description of what this project does..."
links: # Project links
- label: "Demo" # Link text
url: "https://demo-link.com" # Actual URL
- label: "GitHub"
url: "https://github.com/user/repo"
๐งญ Navigation:
navigation:
- label: "HOME"
href: "#home"
- label: "ABOUT"
href: "#about"
- label: "SKILLS"
href: "#skills"
๐ SEO Settings:
seo:
title: "Your Name - Your Title"
description: "Brief description for search engines..."
keywords: "your, skills, here"
ogImage: "/assets/img/og-image.jpg"
File: _config.yml
title: "Your Portfolio Title"
description: "Your professional description"
url: "https://yourusername.github.io"
baseurl: "/repository-name"
author: "Your Name"
google_analytics: "GA_MEASUREMENT_ID" # Optional
Important rules:
-
for multiple itemsExample:
skills:
- category: "Programming"
icon: "โก"
tags:
- "Python"
- "JavaScript"
Validation:
ruby -c _data/portfolio.yml
Or use online: yamllint.com
Add your photo to assets/img/profile.jpg
https://yourusername.github.io/repository-name
Update your portfolio in 4 steps:
_data/portfolio.yml
bundle exec jekyll serve
git add . && git commit -m "Update content" && git push
Files you'll edit regularly:
_data/portfolio.yml
- Your content_config.yml
- Site settingsassets/img/profile.jpg
- Your profile photoFiles to leave alone:
_layouts/default.html
- Site structureassets/css/style.css
- All stylingassets/js/main.js
- Interactive featuresindex.html
- Homepage templateAfter cloning, customize these in order:
_data/portfolio.yml
- All your personal content_config.yml
- Site title, URL, your nameassets/img/profile.jpg
bundle exec jekyll serve
Common issues and solutions:
Problem | Solution |
---|---|
Site not building | Check bundle exec jekyll build --verbose for errors |
Content not updating | Ensure YAML syntax is correct (spaces, not tabs) |
YAML parsing errors | Use yamllint.com to validate |
Contact form not working | Follow the Contact Form Backend Setup section |
Images not loading | Verify file paths and image file names |
YAML syntax check:
ruby -c _data/portfolio.yml
Edit assets/css/style.css
:
:root {
--primary-cyber: #your-color;
--secondary-cyber: #your-color;
}
Add to _config.yml
:
google_analytics: "GA_MEASUREMENT_ID"
โญ If this template helped you, consider starring this repository!