faj-cli
Version:
FAJ - A powerful CLI resume builder with AI enhancement and multi-format export
432 lines (389 loc) • 11.2 kB
JavaScript
"use strict";
/**
* Compact Resume Templates optimized for A4 single-page printing
* These templates are designed to fit all content within one A4 page (210mm x 297mm)
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.compactCSS = void 0;
exports.generateCompactHTMLResume = generateCompactHTMLResume;
exports.compactCSS = `
/* Reset and base styles */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
/* A4 page setup */
@page {
size: A4;
margin: 10mm;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', 'Helvetica Neue', Helvetica, Arial, sans-serif;
font-size: 11pt;
line-height: 1.4;
color: #333;
background: white;
margin: 0;
padding: 0;
}
.resume-container {
max-width: 210mm;
min-height: 297mm;
margin: 0 auto;
padding: 15mm;
background: white;
}
/* Compact Header */
.header {
text-align: center;
padding-bottom: 8mm;
border-bottom: 2px solid #2c3e50;
margin-bottom: 6mm;
}
.name {
font-size: 20pt;
font-weight: bold;
color: #2c3e50;
margin-bottom: 3mm;
}
.contact-info {
font-size: 9pt;
color: #666;
display: flex;
justify-content: center;
gap: 10mm;
flex-wrap: wrap;
}
.contact-item {
display: inline-block;
}
/* Compact Content */
.content {
padding: 0;
}
.section {
margin-bottom: 5mm;
}
.section-title {
font-size: 12pt;
font-weight: bold;
color: #2c3e50;
text-transform: uppercase;
border-bottom: 1px solid #e0e0e0;
padding-bottom: 1mm;
margin-bottom: 3mm;
}
/* Professional Summary - Compact */
.summary {
font-size: 10pt;
line-height: 1.4;
color: #444;
margin-bottom: 3mm;
text-align: justify;
}
/* Experience Items - Compact */
.experience-item, .project-item {
margin-bottom: 4mm;
}
.item-header {
display: flex;
justify-content: space-between;
align-items: baseline;
margin-bottom: 1mm;
}
.item-title {
font-size: 11pt;
font-weight: bold;
color: #2c3e50;
}
.item-subtitle {
font-size: 10pt;
color: #666;
font-style: italic;
}
.item-date {
font-size: 9pt;
color: #888;
font-style: italic;
}
.item-description {
font-size: 10pt;
line-height: 1.3;
color: #444;
margin: 1mm 0;
}
/* Compact Highlights */
.highlights {
list-style: none;
margin: 2mm 0 0 3mm;
}
.highlights li {
font-size: 9pt;
line-height: 1.3;
margin-bottom: 1mm;
position: relative;
padding-left: 4mm;
}
.highlights li:before {
content: "•";
position: absolute;
left: 0;
color: #2c3e50;
}
/* Skills - Compact inline display */
.skills-container {
font-size: 10pt;
}
.skill-category {
margin-bottom: 2mm;
}
.skill-category-title {
font-weight: bold;
color: #666;
display: inline;
}
.skill-list {
display: inline;
}
.skill-item {
display: inline;
margin-right: 2mm;
}
.skill-item:after {
content: ",";
}
.skill-item:last-child:after {
content: "";
}
/* Education - Compact */
.education-item {
margin-bottom: 3mm;
}
/* Print specific optimizations */
@media print {
body {
-webkit-print-color-adjust: exact !important;
print-color-adjust: exact !important;
color-adjust: exact !important;
}
.resume-container {
padding: 0;
page-break-after: auto;
}
.header {
page-break-after: avoid;
}
.section {
page-break-inside: avoid;
}
.experience-item, .project-item, .education-item {
page-break-inside: avoid;
}
/* Remove all unnecessary spacing for print */
.section {
margin-bottom: 4mm;
}
.experience-item, .project-item {
margin-bottom: 3mm;
}
.highlights li {
margin-bottom: 0.5mm;
}
}
/* Hide elements that shouldn't print */
@media print {
.no-print, .print-notice {
display: none !important;
}
}
`;
function generateCompactHTMLResume(content, themeName = 'modern') {
// Get theme colors
const themes = {
modern: {
primary: '#667eea',
secondary: '#764ba2',
accent: '#3498db'
},
professional: {
primary: '#2c3e50',
secondary: '#34495e',
accent: '#3498db'
},
minimalist: {
primary: '#000000',
secondary: '#666666',
accent: '#000000'
}
};
const colors = themes[themeName] || themes.modern;
// Apply theme colors to CSS
const themedCSS = exports.compactCSS
.replace(/#2c3e50/g, colors.primary)
.replace(/#666/g, colors.secondary);
return `
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>${content.basicInfo?.name || 'Resume'} - Resume</title>
<style>${themedCSS}</style>
</head>
<body>
<div class="resume-container">
<!-- Compact Header -->
<div class="header">
<div class="name">${content.basicInfo?.name || ''}</div>
<div class="contact-info">
${content.basicInfo?.email ? `<span class="contact-item">${content.basicInfo.email}</span>` : ''}
${content.basicInfo?.phone ? `<span class="contact-item">${content.basicInfo.phone}</span>` : ''}
${content.basicInfo?.location ? `<span class="contact-item">${content.basicInfo.location}</span>` : ''}
${content.basicInfo?.github ? `<span class="contact-item">${content.basicInfo.github}</span>` : ''}
</div>
</div>
<div class="content">
<!-- Work Experience -->
${content.content?.experience && content.content.experience.length > 0 ? `
<div class="section">
<div class="section-title">Work Experience</div>
${content.content.experience.map((exp) => `
<div class="experience-item">
<div class="item-header">
<div>
<span class="item-title">${exp.title}</span>
<span class="item-subtitle"> at ${exp.company}</span>
</div>
<div class="item-date">${exp.startDate} - ${exp.current ? 'Present' : exp.endDate}</div>
</div>
${exp.description ? `<div class="item-description">${exp.description}</div>` : ''}
${exp.highlights && exp.highlights.length > 0 ? `
<ul class="highlights">
${exp.highlights.slice(0, 3).map((h) => `<li>${h}</li>`).join('')}
</ul>
` : ''}
</div>
`).join('')}
</div>
` : ''}
<!-- Projects (limit to top 2-3) -->
${content.content?.projects && content.content.projects.length > 0 ? `
<div class="section">
<div class="section-title">Key Projects</div>
${content.content.projects.slice(0, 2).map((proj) => `
<div class="project-item">
<div class="item-header">
<div>
<span class="item-title">${proj.name}</span>
${proj.role ? `<span class="item-subtitle"> - ${proj.role}</span>` : ''}
</div>
</div>
${proj.description ? `<div class="item-description">${proj.description}</div>` : ''}
${proj.highlights && proj.highlights.length > 0 ? `
<ul class="highlights">
${proj.highlights.slice(0, 2).map((h) => `<li>${h}</li>`).join('')}
</ul>
` : ''}
</div>
`).join('')}
</div>
` : ''}
<!-- Skills (inline format to save space) -->
${content.content?.skills && content.content.skills.length > 0 ? `
<div class="section">
<div class="section-title">Technical Skills</div>
<div class="skills-container">
${(() => {
const skillsByCategory = {};
content.content.skills.forEach((skill) => {
const cat = skill.category || 'Other';
if (!skillsByCategory[cat])
skillsByCategory[cat] = [];
skillsByCategory[cat].push(skill.name);
});
const categoryLabels = {
'programming_languages': 'Languages',
'frameworks': 'Frameworks',
'databases': 'Databases',
'tools': 'Tools',
'cloud': 'Cloud',
'Other': 'Other'
};
return Object.entries(skillsByCategory).slice(0, 4).map(([cat, skills]) => `
<div class="skill-category">
<span class="skill-category-title">${categoryLabels[cat] || cat}:</span>
<span class="skill-list">
${skills.slice(0, 8).map((s) => `<span class="skill-item">${s}</span>`).join('')}
</span>
</div>
`).join('');
})()}
</div>
</div>
` : ''}
<!-- Education (compact) -->
${content.content?.education && content.content.education.length > 0 ? `
<div class="section">
<div class="section-title">Education</div>
${content.content.education.map((edu) => `
<div class="education-item">
<div class="item-header">
<div>
<span class="item-title">${edu.degree}(${edu.field})</span>
<span class="item-subtitle"> - ${edu.institution}</span>
</div>
<div class="item-date">${edu.startDate} - ${edu.endDate}</div>
</div>
${edu.gpa ? `<div style="font-size: 9pt; color: #666;">GPA: ${edu.gpa}</div>` : ''}
</div>
`).join('')}
</div>
` : ''}
</div>
</div>
<!-- Print instructions (will not show in print) -->
<div class="print-notice no-print" style="
position: fixed;
top: 20px;
right: 20px;
background: #4CAF50;
color: white;
padding: 15px;
border-radius: 5px;
z-index: 10000;
font-family: Arial, sans-serif;
box-shadow: 0 2px 10px rgba(0,0,0,0.2);
">
<h3 style="margin: 0 0 10px 0;">📄 Save as PDF</h3>
<ol style="margin: 5px 0; padding-left: 20px; font-size: 12px;">
<li>Press Ctrl+P (Windows/Linux) or Cmd+P (Mac)</li>
<li>Destination: Save as PDF</li>
<li>Layout: Portrait</li>
<li>Paper size: A4</li>
<li>Margins: Default</li>
<li>Options: Check "Background graphics"</li>
</ol>
<button onclick="window.print(); return false;" style="
background: white;
color: #4CAF50;
border: none;
padding: 8px 16px;
border-radius: 3px;
cursor: pointer;
font-weight: bold;
margin-top: 10px;
">Print Now</button>
<button onclick="this.parentElement.style.display='none'" style="
background: transparent;
color: white;
border: 1px solid white;
padding: 8px 16px;
border-radius: 3px;
cursor: pointer;
margin-left: 10px;
">Close</button>
</div>
</body>
</html>`;
}
//# sourceMappingURL=CompactResumeTemplates.js.map