Skip to content

Instantly share code, notes, and snippets.

@nsdevaraj
Created April 1, 2025 01:50
Show Gist options
  • Save nsdevaraj/04732e1f1ae407c63f71623bd205ef43 to your computer and use it in GitHub Desktop.
Save nsdevaraj/04732e1f1ae407c63f71623bd205ef43 to your computer and use it in GitHub Desktop.
resume
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>LinkedIn Resume Builder</title>
<link
href="https://fonts.googleapis.com/css2?family=Open+Sans:wght@300;400;600;700&family=Poppins:wght@400;500;600&display=swap"
rel="stylesheet"
/>
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"
/>
<style>
:root {
--primary: #0077b5;
--primary-dark: #006097;
--secondary: #f5f5f5;
--dark: #313335;
--light: #ffffff;
--gray: #86888a;
--shadow: 0 4px 16px rgba(0, 0, 0, 0.1);
--border-radius: 8px;
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: "Open Sans", sans-serif;
background-color: #f9f9f9;
color: var(--dark);
line-height: 1.6;
}
.container {
max-width: 1200px;
margin: 0 auto;
padding: 0 20px;
}
header {
background-color: var(--light);
box-shadow: var(--shadow);
position: sticky;
top: 0;
z-index: 100;
}
.header-content {
display: flex;
justify-content: space-between;
align-items: center;
padding: 15px 0;
}
.logo {
display: flex;
align-items: center;
gap: 10px;
}
.logo-icon {
color: var(--primary);
font-size: 28px;
}
.logo-text {
font-family: "Poppins", sans-serif;
font-weight: 600;
font-size: 20px;
color: var(--primary);
}
.auth-btn {
background-color: var(--primary);
color: white;
border: none;
padding: 10px 20px;
border-radius: var(--border-radius);
font-weight: 600;
cursor: pointer;
transition: all 0.3s;
display: flex;
align-items: center;
gap: 8px;
}
.auth-btn:hover {
background-color: var(--primary-dark);
}
.auth-btn i {
font-size: 18px;
}
.hero {
padding: 60px 0;
text-align: center;
background: linear-gradient(135deg, #f5f7fa 0%, #e4e8eb 100%);
}
.hero-title {
font-size: 42px;
font-weight: 700;
margin-bottom: 20px;
color: var(--dark);
}
.hero-subtitle {
font-size: 18px;
color: var(--gray);
max-width: 700px;
margin: 0 auto 30px;
}
.section-title {
text-align: center;
font-size: 32px;
margin-bottom: 40px;
color: var(--dark);
}
.templates {
padding: 60px 0;
}
.template-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 30px;
margin-top: 30px;
}
.template-card {
background-color: var(--light);
border-radius: var(--border-radius);
overflow: hidden;
box-shadow: var(--shadow);
transition: transform 0.3s;
cursor: pointer;
border: 1px solid #eaeaea;
}
.template-card:hover {
transform: translateY(-5px);
}
.template-preview {
height: 350px;
overflow: hidden;
border-bottom: 1px solid #eee;
position: relative;
}
.template-preview img {
width: 100%;
height: 100%;
object-fit: cover;
transition: transform 0.5s;
}
.template-card:hover .template-preview img {
transform: scale(1.03);
}
.template-info {
padding: 20px;
}
.template-name {
font-size: 20px;
font-weight: 600;
margin-bottom: 10px;
}
.template-desc {
color: var(--gray);
margin-bottom: 15px;
font-size: 14px;
}
.select-btn {
background-color: transparent;
color: var(--primary);
border: 2px solid var(--primary);
padding: 8px 16px;
border-radius: var(--border-radius);
font-weight: 600;
cursor: pointer;
transition: all 0.3s;
width: 100%;
}
.select-btn:hover {
background-color: var(--primary);
color: white;
}
.resume-form {
background-color: var(--light);
padding: 40px;
border-radius: var(--border-radius);
box-shadow: var(--shadow);
max-width: 800px;
margins: 0 auto;
}
.form-group {
margin-bottom: 25px;
}
.form-label {
display: block;
margin-bottom: 8px;
font-weight: 600;
}
.form-control {
width: 100%;
padding: 12px;
border: 1px solid #ddd;
border-radius: var(--border-radius);
font-family: inherit;
font-size: 16px;
}
.form-control:focus {
outline: none;
border-color: var(--primary);
}
.form-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 20px;
}
.form-actions {
display: flex;
justify-content: flex-end;
gap: 15px;
margin-top: 30px;
}
.btn {
padding: 12px 24px;
border-radius: var(--border-radius);
font-weight: 600;
cursor: pointer;
transition: all 0.3s;
}
.btn-primary {
background-color: var(--primary);
color: white;
border: none;
}
.btn-primary:hover {
background-color: var(--primary-dark);
}
.btn-secondary {
background-color: transparent;
color: var(--gray);
border: 1px solid var(--gray);
}
.btn-secondary:hover {
background-color: #f5f5f5;
}
.preview-section {
padding: 60px 0;
background-color: var(--secondary);
}
.resume-preview {
background-color: white;
box-shadow: var(--shadow);
margin: 0 auto;
max-width: 800px;
padding: 40px;
}
.download-actions {
display: flex;
justify-content: center;
gap: 15px;
margin-top: 30px;
}
footer {
background-color: var(--dark);
color: white;
padding: 30px 0;
text-align: center;
}
.footer-content {
display: flex;
flex-direction: column;
align-items: center;
gap: 20px;
}
.footer-links {
display: flex;
gap: 20px;
}
.footer-link {
color: white;
text-decoration: none;
transition: color 0.3s;
}
.footer-link:hover {
color: var(--primary);
}
.copyright {
font-size: 14px;
color: var(--gray);
}
/* Modal styles */
.modal {
display: none;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
z-index: 1000;
justify-content: center;
align-items: center;
}
.modal-content {
background-color: white;
padding: 30px;
border-radius: var(--border-radius);
max-width: 500px;
width: 90%;
max-height: 90vh;
overflow-y: auto;
}
.modal-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
}
.modal-title {
font-size: 24px;
font-weight: 600;
}
.close-modal {
background: none;
border: none;
font-size: 24px;
cursor: pointer;
color: var(--gray);
}
/* Responsive styles */
@media (max-width: 768px) {
.header-content {
flex-direction: column;
gap: 15px;
}
.hero-title {
font-size: 32px;
}
.hero-subtitle {
font-size: 16px;
}
.form-grid {
grid-template-columns: 1fr;
}
.template-grid {
grid-template-columns: 1fr;
}
}
/* Professional template styles */
.professional-resume {
font-family: "Calibri", "Arial", sans-serif;
line-height: 1.5;
max-width: 800px;
margin: 0 auto;
color: #333;
}
.professional-header {
display: flex;
justify-content: space-between;
align-items: center;
border-bottom: 2px solid #0077b5;
padding-bottom: 20px;
margin-bottom: 20px;
}
.professional-name {
font-size: 28px;
font-weight: bold;
color: #0077b5;
}
.professional-title {
font-size: 18px;
color: #555;
}
.professional-contact {
text-align: right;
}
.professional-section {
margin-bottom: 20px;
}
.professional-section-title {
font-size: 20px;
font-weight: bold;
color: #0077b5;
border-bottom: 1px solid #ddd;
padding-bottom: 5px;
margin-bottom: 10px;
}
.professional-experience-item {
margin-bottom: 15px;
}
.professional-job-title {
font-weight: bold;
font-size: 18px;
}
.professional-company {
font-style: italic;
color: #555;
}
.professional-duration {
color: #777;
}
/* Modern template styles */
.modern-resume {
font-family: "Helvetica Neue", Arial, sans-serif;
line-height: 1.6;
max-width: 800px;
margin: 0 auto;
color: #2c3e50;
}
.modern-header {
display: flex;
justify-content: space-between;
margin-bottom: 30px;
}
.modern-name {
font-size: 32px;
font-weight: 800;
letter-spacing: 1px;
margin-bottom: 5px;
}
.modern-title {
font-size: 18px;
color: #7f8c8d;
text-transform: uppercase;
letter-spacing: 1px;
}
.modern-contact {
text-align: right;
padding-top: 5px;
}
.modern-contact-item {
display: flex;
align-items: center;
justify-content: flex-end;
gap: 5px;
margin-bottom: 5px;
}
.modern-section {
margin-bottom: 25px;
}
.modern-section-title {
font-size: 22px;
font-weight: 700;
color: #3498db;
margin-bottom: 10px;
text-transform: uppercase;
}
.modern-experience-item {
margin-bottom: 20px;
}
.modern-job-header {
display: flex;
justify-content: space-between;
margin-bottom: 5px;
}
.modern-job-title {
font-weight: 700;
font-size: 18px;
}
.modern-company {
font-weight: 600;
color: #3498db;
}
.modern-duration {
color: #95a5a6;
font-size: 14px;
}
/* Minimalist template styles */
.minimalist-resume {
font-family: "Lato", sans-serif;
line-height: 1.6;
max-width: 800px;
margin: 0 auto;
color: #333;
}
.minimalist-header {
text-align: center;
margin-bottom: 30px;
}
.minimalist-name {
font-size: 36px;
font-weight: 300;
letter-spacing: 3px;
margin-bottom: 10px;
text-transform: uppercase;
}
.minimalist-title {
font-size: 16px;
color: #999;
letter-spacing: 1px;
}
.minimalist-divider {
height: 1px;
background-color: #eee;
width: 100px;
margin: 20px auto;
}
.minimalist-section {
margin-bottom: 30px;
}
.minimalist-section-title {
font-size: 18px;
font-weight: 400;
color: #666;
letter-spacing: 1px;
margin-bottom: 15px;
}
.minimalist-experience-item {
margin-bottom: 20px;
}
.minimalist-job-header {
display: flex;
justify-content: space-between;
margin-bottom: 5px;
}
.minimalist-job-title {
font-weight: 400;
font-style: italic;
}
.minimalist-company {
font-weight: 400;
}
.minimalist-duration {
color: #999;
font-size: 14px;
}
.hidden {
display: none;
}
/* Progress indicator */
.progress-indicator {
display: flex;
justify-content: center;
margin-bottom: 40px;
}
.progress-step {
display: flex;
flex-direction: column;
align-items: center;
position: relative;
margin: 0 20px;
}
.step-number {
width: 40px;
height: 40px;
border-radius: 50%;
background-color: #e0e0e0;
color: #999;
display: flex;
justify-content: center;
align-items: center;
font-weight: bold;
margin-bottom: 8px;
z-index: 2;
}
.step-active .step-number {
background-color: var(--primary);
color: white;
}
.step-completed .step-number {
background-color: var(--primary);
color: white;
}
.step-label {
font-size: 14px;
color: #999;
}
.step-active .step-label {
color: var(--primary);
font-weight: 600;
}
.step-completed .step-label {
color: var(--primary);
font-weight: 600;
}
.progress-connector {
position: absolute;
top: 20px;
left: calc(100% + 10px);
width: 40px;
height: 2px;
background-color: #e0e0e0;
}
.step-completed .progress-connector,
.step-active + .step-completed .progress-connector {
background-color: var(--primary);
}
/* Toggle between templates */
.template-toggle {
display: flex;
justify-content: center;
margin-bottom: 30px;
border-bottom: 1px solid #ddd;
}
.template-tab {
padding: 12px 25px;
cursor: pointer;
border-bottom: 3px solid transparent;
font-weight: 600;
color: var(--gray);
}
.template-tab.active {
color: var(--primary);
border-bottom-color: var(--primary);
}
.loading-overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(255, 255, 255, 0.8);
display: none;
justify-content: center;
align-items: center;
z-index: 1001;
}
.spinner {
width: 50px;
height: 50px;
border: 5px solid rgba(0, 119, 181, 0.2);
border-radius: 50%;
border-top-color: var(--primary);
animation: spin 1s ease-in-out infinite;
}
@keyframes spin {
to {
transform: rotate(360deg);
}
}
/* Alert styles */
.alert {
padding: 15px;
margin-bottom: 20px;
border: 1px solid transparent;
border-radius: var(--border-radius);
}
.alert-danger {
background-color: #f8d7da;
border-color: #f5c6cb;
color: #721c24;
}
</style>
</head>
<body>
<header>
<div class="container">
<div class="header-content">
<div class="logo">
<i class="fab fa-linkedin logo-icon"></i>
<span class="logo-text">LinkedIn Resume Builder</span>
</div>
<button id="loginBtn" class="auth-btn">
<i class="fab fa-linkedin"></i>
Connect with LinkedIn
</button>
</div>
</div>
</header>
<section class="hero" id="hero">
<div class="container">
<h1 class="hero-title">Create Your Perfect Resume in Minutes</h1>
<p class="hero-subtitle">
Import your LinkedIn profile to generate a professional resume. Choose
from our beautifully designed templates and land your dream job.
</p>
<button id="getStartedBtn" class="auth-btn">
Get Started
<i class="fas fa-arrow-right"></i>
</button>
</div>
</section>
<section class="templates hidden" id="templates">
<div class="container">
<h2 class="section-title">Choose Your Resume Template</h2>
<div id="authAlert" class="alert alert-danger hidden">
Please connect your LinkedIn account to continue.
</div>
<div class="progress-indicator">
<div class="progress-step step-active">
<div class="step-number">1</div>
<div class="step-label">Select Template</div>
</div>
<div class="progress-step">
<div class="step-number">2</div>
<div class="step-label">Review & Edit</div>
<div class="progress-connector"></div>
</div>
<div class="progress-step">
<div class="step-number">3</div>
<div class="step-label">Download</div>
<div class="progress-connector"></div>
</div>
</div>
<div class="template-grid">
<div class="template-card" data-template="professional">
<div class="template-preview">
<img
src="https://images.unsplash.com/photo-1517245386807-bb43f82c33c4?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=800&q=80"
alt="Professional Template"
/>
</div>
<div class="template-info">
<h3 class="template-name">Professional</h3>
<p class="template-desc">
Clean, traditional design that highlights your experience and
skills in a conventional format preferred by many employers.
</p>
<button class="select-btn">Select Template</button>
</div>
</div>
<div class="template-card" data-template="modern">
<div class="template-preview">
<img
src="https://images.unsplash.com/photo-1504868584819-f8e8b4b6d7e3?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=800&q=80"
alt="Modern Template"
/>
</div>
<div class="template-info">
<h3 class="template-name">Modern</h3>
<p class="template-desc">
Contemporary design with sleek typography and layout that
showcases your skills in a fresh, eye-catching format.
</p>
<button class="select-btn">Select Template</button>
</div>
</div>
<div class="template-card" data-template="minimalist">
<div class="template-preview">
<img
src="https://images.unsplash.com/photo-1522542550221-31fd19575a2d?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=800&q=80"
alt="Minimalist Template"
/>
</div>
<div class="template-info">
<h3 class="template-name">Minimalist</h3>
<p class="template-desc">
Ultra-clean, distraction-free design that puts the focus on your
content with ample white space and simple typography.
</p>
<button class="select-btn">Select Template</button>
</div>
</div>
</div>
</div>
</section>
<section class="form-section hidden" id="formSection">
<div class="container">
<div class="progress-indicator">
<div class="progress-step step-completed">
<div class="step-number"><i class="fas fa-check"></i></div>
<div class="step-label">Select Template</div>
</div>
<div class="progress-step step-active">
<div class="step-number">2</div>
<div class="step-label">Review & Edit</div>
<div class="progress-connector"></div>
</div>
<div class="progress-step">
<div class="step-number">3</div>
<div class="step-label">Download</div>
<div class="progress-connector"></div>
</div>
</div>
<div class="template-toggle">
<div class="template-tab active" data-template="professional">
Professional
</div>
<div class="template-tab" data-template="modern">Modern</div>
<div class="template-tab" data-template="minimalist">Minimalist</div>
</div>
<div class="resume-form">
<div class="form-group form-grid">
<div>
<label class="form-label">First Name</label>
<input
type="text"
class="form-control"
id="firstName"
value="John"
/>
</div>
<div>
<label class="form-label">Last Name</label>
<input
type="text"
class="form-control"
id="lastName"
value="Doe"
/>
</div>
</div>
<div class="form-group">
<label class="form-label">Professional Title</label>
<input
type="text"
class="form-control"
id="professionalTitle"
value="Senior Software Engineer"
/>
</div>
<div class="form-group form-grid">
<div>
<label class="form-label">Email</label>
<input
type="email"
class="form-control"
id="email"
value="[email protected]"
/>
</div>
<div>
<label class="form-label">Phone</label>
<input
type="tel"
class="form-control"
id="phone"
value="(123) 456-7890"
/>
</div>
</div>
<div class="form-group">
<label class="form-label">Summary</label>
<textarea class="form-control" id="summary" rows="4">
Experienced software engineer with 8+ years in full-stack development. Specialized in JavaScript frameworks and cloud architecture. Passionate about creating scalable and maintainable systems.</textarea
>
</div>
<h3>Experience</h3>
<div id="experienceSection">
<div class="experience-item">
<div class="form-group form-grid">
<div>
<label class="form-label">Job Title</label>
<input
type="text"
class="form-control"
value="Senior Software Engineer"
/>
</div>
<div>
<label class="form-label">Company</label>
<input type="text" class="form-control" value="TechCorp" />
</div>
</div>
<div class="form-group form-grid">
<div>
<label class="form-label">Start Date</label>
<input type="text" class="form-control" value="Jan 2018" />
</div>
<div>
<label class="form-label">End Date</label>
<input type="text" class="form-control" value="Present" />
</div>
</div>
<div class="form-group">
<label class="form-label">Description</label>
<textarea class="form-control" rows="3">
Lead developer for customer-facing web applications. Built and maintained React front-end with Node.js back-end. Implemented CI/CD pipeline reducing deployment time by 40%.</textarea
>
</div>
</div>
<div class="experience-item">
<div class="form-group form-grid">
<div>
<label class="form-label">Job Title</label>
<input
type="text"
class="form-control"
value="Software Engineer"
/>
</div>
<div>
<label class="form-label">Company</label>
<input
type="text"
class="form-control"
value="WebSolutions"
/>
</div>
</div>
<div class="form-group form-grid">
<div>
<label class="form-label">Start Date</label>
<input type="text" class="form-control" value="Mar 2015" />
</div>
<div>
<label class="form-label">End Date</label>
<input type="text" class="form-control" value="Dec 2017" />
</div>
</div>
<div class="form-group">
<label class="form-label">Description</label>
<textarea class="form-control" rows="3">
Developed and maintained web applications using AngularJS and PHP. Collaborated with UI/UX team to implement responsive designs. Optimized database queries improving performance by 25%.</textarea
>
</div>
</div>
</div>
<h3>Education</h3>
<div id="educationSection">
<div class="education-item">
<div class="form-group form-grid">
<div>
<label class="form-label">Degree</label>
<input
type="text"
class="form-control"
value="Master of Computer Science"
/>
</div>
<div>
<label class="form-label">Institution</label>
<input
type="text"
class="form-control"
value="University of Technology"
/>
</div>
</div>
<div class="form-group form-grid">
<div>
<label class="form-label">Year</label>
<input type="text" class="form-control" value="2014" />
</div>
</div>
</div>
</div>
<h3>Skills</h3>
<div class="form-group">
<label class="form-label">Skills (comma separated)</label>
<input
type="text"
class="form-control"
id="skills"
value="JavaScript, React, Node.js, Python, AWS, SQL, Agile Methodology"
/>
</div>
<div class="form-actions">
<button class="btn btn-secondary" id="backToTemplatesBtn">
Back
</button>
<button class="btn btn-primary" id="generateResumeBtn">
Generate Resume
</button>
</div>
</div>
</div>
</section>
<section class="preview-section hidden" id="previewSection">
<div class="container">
<div class="progress-indicator">
<div class="progress-step step-completed">
<div class="step-number"><i class="fas fa-check"></i></div>
<div class="step-label">Select Template</div>
</div>
<div class="progress-step step-completed">
<div class="step-number"><i class="fas fa-check"></i></div>
<div class="step-label">Review & Edit</div>
<div class="progress-connector"></div>
</div>
<div class="progress-step step-active">
<div class="step-number">3</div>
<div class="step-label">Download</div>
</div>
</div>
<div class="template-toggle">
<div class="template-tab active" data-template="professional">
Professional
</div>
<div class="template-tab" data-template="modern">Modern</div>
<div class="template-tab" data-template="minimalist">Minimalist</div>
</div>
<div class="resume-preview" id="resumePreview">
<div class="professional-resume">
<div class="professional-header">
<div>
<div class="professional-name" id="previewName">John Doe</div>
<div class="professional-title" id="previewTitle">
Senior Software Engineer
</div>
</div>
<div class="professional-contact">
<div id="previewEmail">[email protected]</div>
<div id="previewPhone">(123) 456-7890</div>
<div id="previewLocation">San Francisco, CA</div>
</div>
</div>
<div class="professional-section">
<div class="professional-section-title">Professional Summary</div>
<p id="previewSummary">
Experienced software engineer with 8+ years in full-stack
development. Specialized in JavaScript frameworks and cloud
architecture. Passionate about creating scalable and
maintainable systems.
</p>
</div>
<div class="professional-section">
<div class="professional-section-title">
Professional Experience
</div>
<div class="professional-experience-item">
<div class="professional-job-title">
Senior Software Engineer
</div>
<div class="professional-company">TechCorp</div>
<div class="professional-duration">Jan 2018 - Present</div>
<p>
Lead developer for customer-facing web applications. Built and
maintained React front-end with Node.js back-end. Implemented
CI/CD pipeline reducing deployment time by 40%.
</p>
</div>
<div class="professional-experience-item">
<div class="professional-job-title">Software Engineer</div>
<div class="professional-company">WebSolutions</div>
<div class="professional-duration">Mar 2015 - Dec 2017</div>
<p>
Developed and maintained web applications using AngularJS and
PHP. Collaborated with UI/UX team to implement responsive
designs. Optimized database queries improving performance by
25%.
</p>
</div>
</div>
<div class="professional-section">
<div class="professional-section-title">Education</div>
<div class="professional-experience-item">
<div class="professional-job-title">
Master of Computer Science
</div>
<div class="professional-company">University of Technology</div>
<div class="professional-duration">2014</div>
</div>
</div>
<div class="professional-section">
<div class="professional-section-title">Skills</div>
<div id="previewSkills">
JavaScript, React, Node.js, Python, AWS, SQL, Agile Methodology
</div>
</div>
</div>
</div>
<div class="download-actions">
<button class="btn btn-secondary" id="editResumeBtn">
<i class="fas fa-edit"></i> Edit Resume
</button>
<button class="btn btn-primary" id="downloadPdfBtn">
<i class="fas fa-file-pdf"></i> Download PDF
</button>
<button class="btn btn-primary" id="downloadDocBtn">
<i class="fas fa-file-word"></i> Download DOC
</button>
</div>
</div>
</section>
<footer>
<div class="container">
<div class="footer-content">
<div class="logo">
<i class="fab fa-linkedin logo-icon"></i>
<span class="logo-text">LinkedIn Resume Builder</span>
</div>
<div class="footer-links">
<a href="#" class="footer-link">About</a>
<a href="#" class="footer-link">Privacy Policy</a>
<a href="#" class="footer-link">Terms</a>
<a href="#" class="footer-link">Contact</a>
</div>
<div class="copyright">
&copy; 2025 LinkedIn Resume Builder. All rights reserved.
</div>
</div>
</div>
</footer>
<!-- LinkedIn OAuth Modal -->
<div class="modal" id="linkedinModal">
<div class="modal-content">
<div class="modal-header">
<h3 class="modal-title">Connect with LinkedIn</h3>
<button class="close-modal" id="closeLinkedinModal">&times;</button>
</div>
<p style="margin-bottom: 20px">
We'll import your profile information to create your resume. You can
edit all the details before generating the final version.
</p>
<button
class="auth-btn"
style="width: 100%; justify-content: center"
id="confirmLinkedinBtn"
>
<i class="fab fa-linkedin"></i> Continue with LinkedIn
</button>
</div>
</div>
<!-- Loading Overlay -->
<div class="loading-overlay" id="loadingOverlay">
<div class="spinner"></div>
</div>
<!-- LinkedIn SDK -->
<script type="text/javascript">
// Filter out LinkedIn's CSP warnings
const originalConsoleWarn = console.warn;
console.warn = function (msg) {
if (
msg &&
(msg.includes("Content Security Policy") ||
msg.includes("CSP") ||
msg.includes("report-only") ||
msg.includes("frame-ancestors"))
) {
// Suppress LinkedIn CSP warnings
return;
}
originalConsoleWarn.apply(console, arguments);
};
// Also filter error messages about CSP
const originalConsoleError = console.error;
console.error = function (msg) {
if (
msg &&
typeof msg === "string" &&
(msg.includes("Content Security Policy") ||
msg.includes("frame-ancestors") ||
msg.includes("report-only"))
) {
// Suppress CSP-related errors
return;
}
originalConsoleError.apply(console, arguments);
};
// Load the LinkedIn SDK asynchronously
window.onLinkedInLoad = function () {
console.log("LinkedIn SDK loaded");
};
// Don't try to load LinkedIn SDK in insecure context
if (
window.location.href.indexOf("about:srcdoc") !== -1 ||
window.location.protocol === "about:"
) {
console.log("Skipping LinkedIn SDK load in insecure context");
} else {
(function () {
try {
const script = document.createElement("script");
script.type = "text/javascript";
script.src = "https://platform.linkedin.com/in.js";
script.innerHTML = `
api_key: 86byo9bgki69bc
authorize: true
onLoad: onLinkedInLoad
scope: r_emailaddress,r_liteprofile
`;
document.getElementsByTagName("head")[0].appendChild(script);
} catch (e) {
console.error("Failed to load LinkedIn SDK:", e);
}
})();
}
</script>
<script>
// Global variables
let currentTemplate = "professional";
let linkedinData = {};
let isAuthenticated = false;
// DOM elements
const heroSection = document.getElementById("hero");
const templatesSection = document.getElementById("templates");
const formSection = document.getElementById("formSection");
const previewSection = document.getElementById("previewSection");
const authAlert = document.getElementById("authAlert");
// Buttons
const getStartedBtn = document.getElementById("getStartedBtn");
const loginBtn = document.getElementById("loginBtn");
const templateCards = document.querySelectorAll(".template-card");
const backToTemplatesBtn = document.getElementById("backToTemplatesBtn");
const generateResumeBtn = document.getElementById("generateResumeBtn");
const editResumeBtn = document.getElementById("editResumeBtn");
const downloadPdfBtn = document.getElementById("downloadPdfBtn");
const downloadDocBtn = document.getElementById("downloadDocBtn");
// Modal elements
const linkedinModal = document.getElementById("linkedinModal");
const closeLinkedinModal = document.getElementById("closeLinkedinModal");
const confirmLinkedinBtn = document.getElementById("confirmLinkedinBtn");
// Loading overlay
const loadingOverlay = document.getElementById("loadingOverlay");
// Event listeners
document.addEventListener("DOMContentLoaded", () => {
// Show hero section by default
heroSection.classList.remove("hidden");
});
getStartedBtn.addEventListener("click", () => {
heroSection.classList.add("hidden");
templatesSection.classList.remove("hidden");
});
loginBtn.addEventListener("click", () => {
linkedinModal.style.display = "flex";
});
closeLinkedinModal.addEventListener("click", () => {
linkedinModal.style.display = "none";
});
confirmLinkedinBtn.addEventListener("click", () => {
// Trigger LinkedIn OAuth flow
loginWithLinkedIn();
});
templateCards.forEach((card) => {
card.addEventListener("click", (e) => {
if (
e.target.classList.contains("select-btn") ||
e.target.closest(".select-btn")
) {
if (!isAuthenticated) {
authAlert.classList.remove("hidden");
return;
}
currentTemplate = card.dataset.template;
showFormSection();
}
});
});
backToTemplatesBtn.addEventListener("click", () => {
formSection.classList.add("hidden");
templatesSection.classList.remove("hidden");
});
generateResumeBtn.addEventListener("click", () => {
// Update preview with current form values
updatePreview();
// Show preview section
formSection.classList.add("hidden");
previewSection.classList.remove("hidden");
});
editResumeBtn.addEventListener("click", () => {
previewSection.classList.add("hidden");
formSection.classList.remove("hidden");
});
downloadPdfBtn.addEventListener("click", () => {
alert(
"PDF download functionality would be implemented here in a production app"
);
});
downloadDocBtn.addEventListener("click", () => {
alert(
"DOC download functionality would be implemented here in a production app"
);
});
// Template tab switching
const templateTabs = document.querySelectorAll(".template-tab");
templateTabs.forEach((tab) => {
tab.addEventListener("click", () => {
templateTabs.forEach((t) => t.classList.remove("active"));
tab.classList.add("active");
currentTemplate = tab.dataset.template;
if (previewSection.classList.contains("hidden")) {
// If we're in the form section, just update the template variable
} else {
// If we're in preview, update the preview
updatePreview();
}
});
});
// LinkedIn SDK Loaded
function onLinkedInLoad() {
// SDK is loaded, we can now use the IN namespace
console.log("LinkedIn SDK loaded");
}
// LinkedIn OAuth login function
function loginWithLinkedIn() {
loadingOverlay.style.display = "flex";
linkedinModal.style.display = "none";
// Check if we're in a secure context (not iframe/srcdoc)
if (
window.location.href.indexOf("about:srcdoc") !== -1 ||
window.location.protocol === "about:"
) {
console.error(
"LinkedIn SDK cannot run in this context (iframe/srcdoc)"
);
loadingOverlay.style.display = "none";
alert(
"LinkedIn authentication is not available in preview mode. Please open the page directly in a browser window."
);
// For demo purposes, simulate successful login
simulateLinkedInLogin();
return;
}
// Request authentication and get profile data
try {
IN.User.authorize(
function () {
// After successful authentication, get profile data
getLinkedInProfileData();
},
(error) => {
console.error("LinkedIn auth error:", error);
loadingOverlay.style.display = "none";
alert("Error connecting to LinkedIn. Please try again.");
}
);
} catch (error) {
console.error("LinkedIn SDK error:", error);
loadingOverlay.style.display = "none";
alert("LinkedIn authentication failed. Using demo data instead.");
// For demo purposes, simulate successful login
simulateLinkedInLogin();
}
}
// Simulate LinkedIn login with mock data for testing/demo
function simulateLinkedInLogin() {
// Create mock profile data
const mockData = {
firstName: "John",
lastName: "Doe",
headline: "Senior Software Engineer",
emailAddress: "[email protected]",
location: {
name: "San Francisco Bay Area",
},
summary:
"Experienced software engineer with 8+ years in full-stack development. Specialized in JavaScript frameworks and cloud architecture.",
positions: {
values: [
{
title: "Senior Software Engineer",
company: { name: "TechCorp" },
startDate: { month: 1, year: 2018 },
isCurrent: true,
summary:
"Lead developer for customer-facing web applications. Built and maintained React front-end with Node.js back-end.",
},
{
title: "Software Engineer",
company: { name: "WebSolutions" },
startDate: { month: 3, year: 2015 },
endDate: { month: 12, year: 2017 },
isCurrent: false,
summary:
"Developed and maintained web applications using AngularJS and PHP.",
},
],
},
educations: {
values: [
{
degree: "Master of Computer Science",
schoolName: "University of Technology",
endDate: { year: 2014 },
},
],
},
skills: {
values: [
{ skill: { name: "JavaScript" } },
{ skill: { name: "React" } },
{ skill: { name: "Node.js" } },
{ skill: { name: "Python" } },
{ skill: { name: "AWS" } },
],
},
};
// Process the mock data
processLinkedInData(mockData);
// Update UI to show successful connection
loginBtn.innerHTML =
'<i class="fas fa-user-check"></i> Profile Imported';
isAuthenticated = true;
authAlert.classList.add("hidden");
}
// Function to get LinkedIn profile data
function getLinkedInProfileData() {
// Get basic profile data including email
IN.API.Raw(
"/people/~:(id,first-name,last-name,headline,picture-url,email-address,location,summary,positions,educations,skills)?format=json"
)
.result(function (data) {
// Process the LinkedIn data
processLinkedInData(data);
// Update UI to show successful connection
loginBtn.innerHTML =
'<i class="fas fa-user-check"></i> Profile Imported';
isAuthenticated = true;
authAlert.classList.add("hidden");
loadingOverlay.style.display = "none";
})
.error(function (error) {
console.error("Error fetching LinkedIn data:", error);
loadingOverlay.style.display = "none";
alert(
"Error fetching profile data from LinkedIn. Please try again."
);
});
}
// Function to process LinkedIn API response
function processLinkedInData(data) {
linkedinData = {
firstName: data.firstName,
lastName: data.lastName,
headline: data.headline,
email: data.emailAddress,
location: data.location ? data.location.name : "",
summary: data.summary,
profilePicture: data.pictureUrl,
positions: [],
educations: [],
skills: [],
};
// Process positions (work experience)
if (data.positions && data.positions.values) {
linkedinData.positions = data.positions.values.map((position) => ({
title: position.title,
companyName: position.company ? position.company.name : "",
startDate: position.startDate,
endDate: position.endDate,
isCurrent: position.isCurrent,
summary: position.summary,
}));
}
// Process education
if (data.educations && data.educations.values) {
linkedinData.educations = data.educations.values.map((edu) => ({
degree: edu.degree || "",
schoolName: edu.schoolName,
fieldOfStudy: edu.fieldOfStudy || "",
startDate: edu.startDate,
endDate: edu.endDate,
}));
}
// Process skills
if (data.skills && data.skills.values) {
linkedinData.skills = data.skills.values.map(
(skill) => skill.skill.name
);
}
// Update form fields with LinkedIn data
populateFormWithLinkedInData();
}
// Function to populate form fields with LinkedIn data
function populateFormWithLinkedInData() {
if (!linkedinData) return;
// Basic info
document.getElementById("firstName").value =
linkedinData.firstName || "";
document.getElementById("lastName").value = linkedinData.lastName || "";
document.getElementById("professionalTitle").value =
linkedinData.headline || "";
document.getElementById("email").value = linkedinData.email || "";
document.getElementById("summary").value = linkedinData.summary || "";
document.getElementById("skills").value = linkedinData.skills
? linkedinData.skills.join(", ")
: "";
// Experience
const experienceSection = document.getElementById("experienceSection");
experienceSection.innerHTML = "";
if (linkedinData.positions && linkedinData.positions.length > 0) {
linkedinData.positions.forEach((position) => {
const startDate = position.startDate
? `${getMonthName(position.startDate.month)} ${
position.startDate.year
}`
: "";
const endDate = position.isCurrent
? "Present"
: position.endDate
? `${getMonthName(position.endDate.month)} ${
position.endDate.year
}`
: "";
const experienceItem = document.createElement("div");
experienceItem.classList.add("experience-item");
experienceItem.innerHTML = `
<div class="form-group form-grid">
<div>
<label class="form-label">Job Title</label>
<input type="text" class="form-control" value="${
position.title || ""
}">
</div>
<div>
<label class="form-label">Company</label>
<input type="text" class="form-control" value="${
position.companyName || ""
}">
</div>
</div>
<div class="form-group form-grid">
<div>
<label class="form-label">Start Date</label>
<input type="text" class="form-control" value="${startDate}">
</div>
<div>
<label class="form-label">End Date</label>
<input type="text" class="form-control" value="${endDate}">
</div>
</div>
<div class="form-group">
<label class="form-label">Description</label>
<textarea class="form-control" rows="3">${
position.summary || ""
}</textarea>
</div>
`;
experienceSection.appendChild(experienceItem);
});
}
// Education
const educationSection = document.getElementById("educationSection");
educationSection.innerHTML = "";
if (linkedinData.educations && linkedinData.educations.length > 0) {
linkedinData.educations.forEach((edu) => {
const year = edu.endDate ? edu.endDate.year : "";
const educationItem = document.createElement("div");
educationItem.classList.add("education-item");
educationItem.innerHTML = `
<div class="form-group form-grid">
<div>
<label class="form-label">Degree</label>
<input type="text" class="form-control" value="${
edu.degree || ""
}">
</div>
<div>
<label class="form-label">Institution</label>
<input type="text" class="form-control" value="${
edu.schoolName || ""
}">
</div>
</div>
<div class="form-group form-grid">
<div>
<label class="form-label">Year</label>
<input type="text" class="form-control" value="${year}">
</div>
</div>
`;
educationSection.appendChild(educationItem);
});
}
}
// Helper function to get month name from number
function getMonthName(monthNum) {
const months = [
"Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
"Jul",
"Aug",
"Sep",
"Oct",
"Nov",
"Dec",
];
return months[monthNum - 1] || "";
}
// Functions
function showFormSection() {
templatesSection.classList.add("hidden");
formSection.classList.remove("hidden");
}
function updatePreview() {
// Update name and title
const firstName = document.getElementById("firstName").value;
const lastName = document.getElementById("lastName").value;
document.getElementById(
"previewName"
).textContent = `${firstName} ${lastName}`;
document.getElementById("previewTitle").textContent =
document.getElementById("professionalTitle").value;
// Update contact info
document.getElementById("previewEmail").textContent =
document.getElementById("email").value;
document.getElementById("previewPhone").textContent =
document.getElementById("phone").value;
// Update summary
document.getElementById("previewSummary").textContent =
document.getElementById("summary").value;
// Update skills
document.getElementById("previewSkills").textContent =
document.getElementById("skills").value;
// Template-specific updates
updateTemplatePreview();
}
function updateTemplatePreview() {
const previewContainer = document.getElementById("resumePreview");
if (currentTemplate === "professional") {
previewContainer.innerHTML = `
<div class="professional-resume">
<div class="professional-header">
<div>
<div class="professional-name">${
document.getElementById("firstName").value
} ${
document.getElementById("lastName").value
}</div>
<div class="professional-title">${
document.getElementById("professionalTitle")
.value
}</div>
</div>
<div class="professional-contact">
<div>${
document.getElementById("email").value
}</div>
<div>${
document.getElementById("phone").value
}</div>
<div>${linkedinData.location || ""}</div>
</div>
</div>
<div class="professional-section">
<div class="professional-section-title">Professional Summary</div>
<p>${document.getElementById("summary").value}</p>
</div>
<div class="professional-section">
<div class="professional-section-title">Professional Experience</div>
${Array.from(
document.querySelectorAll(
"#experienceSection .experience-item"
)
)
.map((item) => {
const title = item.querySelector(
"input:nth-of-type(1)"
).value;
const company = item.querySelector(
"input:nth-of-type(2)"
).value;
const startDate = item.querySelector(
"input:nth-of-type(3)"
).value;
const endDate = item.querySelector(
"input:nth-of-type(4)"
).value;
const description =
item.querySelector("textarea").value;
return `
<div class="professional-experience-item">
<div class="professional-job-title">${title}</div>
<div class="professional-company">${company}</div>
<div class="professional-duration">${startDate} - ${endDate}</div>
<p>${description}</p>
</div>
`;
})
.join("")}
</div>
<div class="professional-section">
<div class="professional-section-title">Education</div>
${Array.from(
document.querySelectorAll(
"#educationSection .education-item"
)
)
.map((item) => {
const degree = item.querySelector(
"input:nth-of-type(1)"
).value;
const school = item.querySelector(
"input:nth-of-type(2)"
).value;
const year = item.querySelector(
"input:nth-of-type(3)"
).value;
return `
<div class="professional-experience-item">
<div class="professional-job-title">${degree}</div>
<div class="professional-company">${school}</div>
<div class="professional-duration">${year}</div>
</div>
`;
})
.join("")}
</div>
<div class="professional-section">
<div class="professional-section-title">Skills</div>
<div>${document.getElementById("skills").value}</div>
</div>
</div>
`;
} else if (currentTemplate === "modern") {
previewContainer.innerHTML = `
<div class="modern-resume">
<div class="modern-header">
<div>
<div class="modern-name">${
document.getElementById("firstName").value
} ${
document.getElementById("lastName").value
}</div>
<div class="modern-title">${
document.getElementById("professionalTitle")
.value
}</div>
</div>
<div class="modern-contact">
<div class="modern-contact-item">
<i class="fas fa-envelope"></i> ${
document.getElementById("email").value
}
</div>
<div class="modern-contact-item">
<i class="fas fa-phone"></i> ${
document.getElementById("phone").value
}
</div>
<div class="modern-contact-item">
<i class="fas fa-map-marker-alt"></i> ${
linkedinData.location || ""
}
</div>
</div>
</div>
<div class="modern-section">
<div class="modern-section-title">About</div>
<p>${document.getElementById("summary").value}</p>
</div>
<div class="modern-section">
<div class="modern-section-title">Experience</div>
${Array.from(
document.querySelectorAll(
"#experienceSection .experience-item"
)
)
.map((item) => {
const title = item.querySelector(
"input:nth-of-type(1)"
).value;
const company = item.querySelector(
"input:nth-of-type(2)"
).value;
const startDate = item.querySelector(
"input:nth-of-type(3)"
).value;
const endDate = item.querySelector(
"input:nth-of-type(4)"
).value;
const description =
item.querySelector("textarea").value;
return `
<div class="modern-experience-item">
<div class="modern-job-header">
<div>
<span class="modern-job-title">${title}</span>
<span class="modern-company">${company}</span>
</div>
<div class="modern-duration">${startDate} - ${endDate}</div>
</div>
<p>${description}</p>
</div>
`;
})
.join("")}
</div>
<div class="modern-section">
<div class="modern-section-title">Education</div>
${Array.from(
document.querySelectorAll(
"#educationSection .education-item"
)
)
.map((item) => {
const degree = item.querySelector(
"input:nth-of-type(1)"
).value;
const school = item.querySelector(
"input:nth-of-type(2)"
).value;
const year = item.querySelector(
"input:nth-of-type(3)"
).value;
return `
<div class="modern-experience-item">
<div class="modern-job-header">
<div>
<span class="modern-job-title">${degree}</span>
<span class="modern-company">${school}</span>
</div>
<div class="modern-duration">${year}</div>
</div>
</div>
`;
})
.join("")}
</div>
<div class="modern-section">
<div class="modern-section-title">Skills</div>
<div class="modern-skills">
${document
.getElementById("skills")
.value.split(",")
.map(
(skill) =>
`<span class="modern-skill-tag">${skill.trim()}</span>`
)
.join("")}
</div>
</div>
</div>
`;
} else if (currentTemplate === "minimalist") {
previewContainer.innerHTML = `
<div class="minimalist-resume">
<div class="minimalist-header">
<div class="minimalist-name">${
document.getElementById("firstName").value
} ${document.getElementById("lastName").value}</div>
<div class="minimalist-title">${
document.getElementById("professionalTitle").value
}</div>
<div class="minimalist-divider"></div>
<div class="minimalist-contact">
${document.getElementById("email").value} | ${
document.getElementById("phone").value
}
</div>
</div>
<div class="minimalist-section">
<div class="minimalist-section-title">Profile</div>
<p>${document.getElementById("summary").value}</p>
</div>
<div class="minimalist-section">
<div class="minimalist-section-title">Experience</div>
${Array.from(
document.querySelectorAll(
"#experienceSection .experience-item"
)
)
.map((item) => {
const title = item.querySelector(
"input:nth-of-type(1)"
).value;
const company = item.querySelector(
"input:nth-of-type(2)"
).value;
const startDate = item.querySelector(
"input:nth-of-type(3)"
).value;
const endDate = item.querySelector(
"input:nth-of-type(4)"
).value;
const description =
item.querySelector("textarea").value;
return `
<div class="minimalist-experience-item">
<div class="minimalist-job-header">
<div>
<span class="minimalist-job-title">${title}</span>
<span class="minimalist-company">${company}</span>
</div>
<div class="minimalist-duration">${startDate} - ${endDate}</div>
</div>
<p>${description}</p>
</div>
`;
})
.join("")}
</div>
<div class="minimalist-section">
<div class="minimalist-section-title">Education</div>
${Array.from(
document.querySelectorAll(
"#educationSection .education-item"
)
)
.map((item) => {
const degree = item.querySelector(
"input:nth-of-type(1)"
).value;
const school = item.querySelector(
"input:nth-of-type(2)"
).value;
const year = item.querySelector(
"input:nth-of-type(3)"
).value;
return `
<div class="minimalist-experience-item">
<div class="minimalist-job-header">
<div>
<span class="minimalist-job-title">${degree}</span>
<span class="minimalist-company">${school}</span>
</div>
<div class="minimalist-duration">${year}</div>
</div>
</div>
`;
})
.join("")}
</div>
<div class="minimalist-section">
<div class="minimalist-section-title">Skills</div>
<p>${document.getElementById("skills").value}</p>
</div>
</div>
`;
}
}
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment