@bluesialia/jsonresume-theme-bluetime
Version:
A modern, clean TypeScript-based theme for JSON Resume with responsive design and professional styling
654 lines (629 loc) • 24.4 kB
JavaScript
var HTMLUtils;
(function (HTMLUtils) {
function escapeHtml(text) {
return text
.replace(/&/g, "&")
.replace(/</g, "<")
.replace(/>/g, ">")
.replace(/"/g, """)
.replace(/'/g, "'");
}
HTMLUtils.escapeHtml = escapeHtml;
function safeText(text) {
return text ? escapeHtml(text) : "";
}
HTMLUtils.safeText = safeText;
function createElement(tagName, className = "", textContent = "", attributes = {}) {
let element = `<${tagName}`;
if (className)
element += ` class="${escapeHtml(className)}"`;
for (const [key, value] of Object.entries(attributes)) {
element += ` ${escapeHtml(key)}="${escapeHtml(value)}"`;
}
element += `>${textContent}</${tagName}>`;
return element;
}
HTMLUtils.createElement = createElement;
function createSection(title) {
let sectionDiv = `<div class="section">`;
if (title) {
sectionDiv += createElement("h2", "", safeText(title));
}
return sectionDiv;
}
HTMLUtils.createSection = createSection;
})(HTMLUtils || (HTMLUtils = {}));
var ContentUtils;
(function (ContentUtils) {
function addContactInfo(email, phone, url, profiles = []) {
let contactInfo = `<div class="contact-info">`;
if (email) {
contactInfo += HTMLUtils.createElement("span", "contact-item", `<i class="fas fa-envelope"></i> ${HTMLUtils.createElement("a", "", HTMLUtils.safeText(email), { href: "mailto:" + email })}`);
}
if (phone) {
contactInfo += HTMLUtils.createElement("span", "contact-item", `<i class="fas fa-phone"></i> ${HTMLUtils.createElement("a", "", HTMLUtils.safeText(phone), { href: "tel:" + phone })}`);
}
if (url) {
contactInfo += HTMLUtils.createElement("span", "contact-item", `<i class="fas fa-globe"></i> ${HTMLUtils.createElement("a", "", HTMLUtils.safeText(url.replace(/^https?:\/\//i, "")), { href: url })}`);
}
for (const profile of profiles) {
if (profile.network && profile.url) {
contactInfo += HTMLUtils.createElement("span", "contact-item", `<i class="fa-brands fa-${HTMLUtils.escapeHtml(profile.network.toLowerCase())}"></i> ${HTMLUtils.createElement("a", "", HTMLUtils.safeText(profile.url.replace(/^https?:\/\//i, "")), { href: profile.url })}`);
}
}
contactInfo += `</div>`;
return contactInfo;
}
ContentUtils.addContactInfo = addContactInfo;
function addLocation(location) {
let locationLine = `<div class="location">`;
const locationParts = [];
if (location.address)
locationParts.push(HTMLUtils.safeText(location.address));
if (location.city)
locationParts.push(HTMLUtils.safeText(location.city));
if (location.region)
locationParts.push(HTMLUtils.safeText(location.region));
if (location.postalCode)
locationParts.push(HTMLUtils.safeText(location.postalCode));
if (location.countryCode)
locationParts.push(HTMLUtils.safeText(location.countryCode));
locationLine += locationParts.join(", ");
locationLine += `</div>`;
return locationLine;
}
ContentUtils.addLocation = addLocation;
function addChips(keywords) {
let keywordChips = `<div class="chips">`;
for (const keyword of keywords) {
keywordChips += HTMLUtils.createElement("span", "chip", HTMLUtils.safeText(keyword));
}
keywordChips += `</div>`;
return keywordChips;
}
ContentUtils.addChips = addChips;
function addHighlights(highlights) {
if (!highlights || !highlights.length)
return ``;
let highlightList = `<ul class="highlights">`;
for (const highlight of highlights) {
highlightList += HTMLUtils.createElement("li", "", HTMLUtils.safeText(highlight));
}
highlightList += `</ul>`;
return highlightList;
}
ContentUtils.addHighlights = addHighlights;
})(ContentUtils || (ContentUtils = {}));
const THEME_STYLES = `
<style>
@import url('https://fonts.googleapis.com/css2?family=Lato:ital,wght@0,100;0,300;0,400;0,700;0,900;1,100;1,300;1,400;1,700;1,900&display=swap');
@import url('https://cdnjs.cloudflare.com/ajax/libs/font-awesome/7.0.0/css/all.min.css');
.resume-container {
display: flex;
padding: 20px;
max-width: 1600px;
margin: auto;
font-family: "Lato", sans-serif;
font-size: 14px;
h1, h2, h3, h4 {
margin-top: 0;
margin-bottom: 10px;
}
p {
margin: 5px 0 0 0;
}
.left-column {
flex: 1;
padding: 10px;
background-color: #f4f4f9;
border-radius: 12px;
}
.right-column {
flex: 2;
padding: 10px 10px 10px 0;
}
.section {
position: relative;
margin: 10px;
break-inside: avoid;
.section-item {
margin: 5px;
break-inside: avoid;
h3 {
display: inline-block;
margin-right: 10px;
}
h4 {
display: inline-block;
color: #666;
}
}
.timeline-section-item {
position: relative;
display: flex;
align-items: flex-start;
margin-top: 10px;
break-inside: avoid;
h3 {
display: inline-block;
margin: 0;
}
h4 {
margin: 10px 0;
}
.timeline {
position: absolute;
width: 65px;
text-align: right;
font-size: 12px;
}
.timeline::before {
content: "";
position: absolute;
left: 70px; /* Adjusted to align with the timeline */
top: 5px;
width: 16px;
height: 16px;
background-color: #007BFF;
border-radius: 50%;
}
.timeline-section-details {
position: relative;
margin-left: 92px;
}
.description {
color: #666;
font-size: 12px;
display: inline-block;
margin-left: 5px;
}
.title-anex {
color: #666;
font-size: 12px;
margin-top: 5px;
}
}
.timeline-section-item::before {
content: "";
position: absolute;
left: 75px; /* Adjusted to align with the timeline */
top: 30px;
width: 6px;
height: calc(100% - 30px);
background-color: #ccc;
border-radius: 3px;
}
.highlights, .courses {
padding-left: 15px;
margin-top: 5px;
margin-bottom: 5px;
}
.highlights li, .courses li {
margin-bottom: 5px;
}
.chips {
display: flex;
flex-wrap: wrap;
gap: 5px;
margin-bottom: 10px;
}
.chip {
background-color: #007BFF;
color: white;
padding: 4px 8px;
border-radius: 20px;
font-size: 12px;
}
}
.profile-picture {
float: left;
margin-right: 20px;
width: 100px;
height: 100px;
border-radius: 50%;
object-fit: cover;
}
@media only screen and (max-width: 1000px) {
.profile-picture {
display: none;
}
}
@media only print {
.profile-picture {
display: none;
}
}
.contact-info {
display: flex;
flex-wrap: wrap;
gap: 10px;
margin-top: 10px;
}
.contact-item {
text-decoration: none;
color: #007BFF;
}
}
</style>
`;
var SectionCreators;
(function (SectionCreators) {
function createBasicsSection(basics) {
if (!basics)
return "";
const { name, label, image, email, phone, url, location = {}, profiles = [], summary, } = basics;
let basicsSection = HTMLUtils.createSection();
if (image) {
basicsSection += HTMLUtils.createElement("img", "", "", {
class: "profile-picture",
src: image,
alt: "Profile Picture",
});
}
if (name) {
basicsSection += HTMLUtils.createElement("h1", "resume-name", HTMLUtils.safeText(name));
}
if (label) {
basicsSection += HTMLUtils.createElement("h2", "job-title", HTMLUtils.safeText(label));
}
basicsSection += ContentUtils.addLocation(location);
basicsSection += ContentUtils.addContactInfo(email, phone, url, profiles);
if (summary) {
basicsSection += HTMLUtils.createElement("p", "", HTMLUtils.safeText(summary));
}
basicsSection += `</div>`;
return basicsSection;
}
SectionCreators.createBasicsSection = createBasicsSection;
function createLanguagesSection(languages) {
if (!languages || languages.length === 0)
return "";
let languagesSection = HTMLUtils.createSection("Languages");
for (const language of languages) {
const { language: lang, fluency } = language;
let languageItem = `<div class="section-item">`;
if (lang) {
languageItem += HTMLUtils.createElement("h3", "", HTMLUtils.safeText(lang));
}
if (fluency) {
languageItem += HTMLUtils.createElement("h4", "subtitle", HTMLUtils.safeText(fluency));
}
languageItem += `</div>`;
languagesSection += languageItem;
}
languagesSection += `</div>`;
return languagesSection;
}
SectionCreators.createLanguagesSection = createLanguagesSection;
function createSkillsSection(skills) {
if (!skills || skills.length === 0)
return "";
let skillsSection = HTMLUtils.createSection("Skills");
for (const skill of skills) {
const { name, level, keywords } = skill;
let skillItem = `<div class="section-item">`;
if (name) {
skillItem += HTMLUtils.createElement("h3", "", HTMLUtils.safeText(name));
}
if (level) {
skillItem += HTMLUtils.createElement("h4", "subtitle", HTMLUtils.safeText(level));
}
if (keywords && keywords.length > 0) {
skillItem += ContentUtils.addChips(keywords);
}
skillItem += `</div>`;
skillsSection += skillItem;
}
skillsSection += `</div>`;
return skillsSection;
}
SectionCreators.createSkillsSection = createSkillsSection;
function createInterestsSection(interests) {
if (!interests || interests.length === 0)
return "";
let interestsSection = HTMLUtils.createSection("Interests");
for (const interest of interests) {
const { name, keywords } = interest;
let interestItem = `<div class="section-item">`;
if (name) {
interestItem += HTMLUtils.createElement("h3", "", HTMLUtils.safeText(name));
}
if (keywords && keywords.length > 0) {
interestItem += ContentUtils.addChips(keywords);
}
interestItem += `</div>`;
interestsSection += interestItem;
}
interestsSection += `</div>`;
return interestsSection;
}
SectionCreators.createInterestsSection = createInterestsSection;
function createReferencesSection(references) {
if (!references || references.length === 0)
return "";
let referencesSection = `<div class="section references">`;
referencesSection += HTMLUtils.createElement("h2", "", "References");
for (const ref of references) {
const { name, reference } = ref;
let referenceItem = `<div class="section-item">`;
if (name) {
referenceItem += HTMLUtils.createElement("h3", "", HTMLUtils.safeText(name));
}
if (reference) {
try {
new URL(reference);
referenceItem += HTMLUtils.createElement("a", "reference-link", HTMLUtils.safeText(reference.replace(/^https?:\/\//i, "")), { href: reference });
}
catch (e) {
referenceItem += HTMLUtils.createElement("p", "", HTMLUtils.safeText(reference));
}
}
referenceItem += `</div>`;
referencesSection += referenceItem;
}
referencesSection += `</div>`;
return referencesSection;
}
SectionCreators.createReferencesSection = createReferencesSection;
function createExperienceSection(experiences) {
if (!experiences || experiences.length === 0)
return "";
let experienceSection = HTMLUtils.createSection("Experience");
for (const experience of experiences) {
const { name, description, location, url, position, summary, highlights, startDate, endDate, } = experience;
let experienceItem = `<div class="timeline-section-item">`;
if (startDate || endDate) {
let timeline = `<div class="timeline">`;
if (endDate) {
timeline += HTMLUtils.createElement("span", "date", HTMLUtils.safeText(endDate));
}
else {
timeline += HTMLUtils.createElement("span", "date", "Present");
}
if (startDate) {
timeline += ` <br> `;
timeline += HTMLUtils.createElement("span", "date", HTMLUtils.safeText(startDate));
}
timeline += `</div>`;
experienceItem += timeline;
}
experienceItem += `<div class="timeline-section-details">`;
if (name) {
experienceItem += HTMLUtils.createElement("h3", "", HTMLUtils.safeText(name));
}
if (description) {
experienceItem += HTMLUtils.createElement("span", "description", HTMLUtils.safeText(description));
}
if (location || url) {
let locationUrl = `<div class="title-anex">`;
if (location) {
locationUrl += HTMLUtils.createElement("span", "", HTMLUtils.safeText(location));
}
if (url) {
locationUrl += ` • `;
locationUrl += HTMLUtils.createElement("a", "url", HTMLUtils.safeText(url.replace(/^https?:\/\//i, "")), { href: url });
}
locationUrl += `</div>`;
experienceItem += locationUrl;
}
if (position) {
experienceItem += HTMLUtils.createElement("h4", "subtitle", HTMLUtils.safeText(position));
}
if (summary) {
experienceItem += HTMLUtils.createElement("p", "", HTMLUtils.safeText(summary));
}
if (highlights && highlights.length > 0) {
experienceItem += ContentUtils.addHighlights(highlights);
}
experienceItem += `</div>`;
experienceItem += `</div>`;
experienceSection += experienceItem;
}
experienceSection += `</div>`;
return experienceSection;
}
SectionCreators.createExperienceSection = createExperienceSection;
function createProjectsSection(projects) {
if (!projects || projects.length === 0)
return "";
let projectsSection = `<div class="section">`;
projectsSection += HTMLUtils.createElement("h2", "", "Projects");
for (const project of projects) {
const { name, url, description, highlights, keywords, startDate, endDate, } = project;
let projectItem = `<div class="timeline-section-item">`;
if (startDate || endDate) {
let timeline = `<div class="timeline">`;
if (endDate) {
timeline += HTMLUtils.createElement("span", "date", HTMLUtils.safeText(endDate));
}
else {
timeline += HTMLUtils.createElement("span", "date", "Present");
}
if (startDate) {
timeline += ` <br> `;
timeline += HTMLUtils.createElement("span", "date", HTMLUtils.safeText(startDate));
}
timeline += `</div>`;
projectItem += timeline;
}
projectItem += `<div class="timeline-section-details">`;
if (name) {
projectItem += HTMLUtils.createElement("h3", "", HTMLUtils.safeText(name));
}
if (url) {
projectItem += ` • `;
projectItem += HTMLUtils.createElement("a", "description", HTMLUtils.safeText(url.replace(/^https?:\/\//i, "")), {
href: url,
});
}
if (description) {
projectItem += HTMLUtils.createElement("p", "", HTMLUtils.safeText(description));
}
if (highlights && highlights.length > 0) {
let highlightList = `<ul class="highlights">`;
for (const highlight of highlights) {
highlightList += HTMLUtils.createElement("li", "", HTMLUtils.safeText(highlight));
}
highlightList += `</ul>`;
projectItem += highlightList;
}
if (keywords && keywords.length > 0) {
projectItem += ContentUtils.addChips(keywords);
}
projectItem += `</div>`;
projectItem += `</div>`;
projectsSection += projectItem;
}
projectsSection += `</div>`;
return projectsSection;
}
SectionCreators.createProjectsSection = createProjectsSection;
function createVolunteerSection(volunteer) {
if (!volunteer || volunteer.length === 0)
return "";
let volunteerSection = HTMLUtils.createSection("Volunteer");
for (const vol of volunteer) {
const { organization, url, position, summary, highlights, startDate, endDate, } = vol;
let volItem = `<div class="timeline-section-item">`;
if (startDate || endDate) {
let timeline = `<div class="timeline">`;
if (endDate) {
timeline += HTMLUtils.createElement("span", "date", HTMLUtils.safeText(endDate));
}
else {
timeline += HTMLUtils.createElement("span", "date", "Present");
}
if (startDate) {
timeline += ` <br> `;
timeline += HTMLUtils.createElement("span", "date", HTMLUtils.safeText(startDate));
}
timeline += `</div>`;
volItem += timeline;
}
volItem += `<div class="timeline-section-details">`;
if (organization) {
volItem += HTMLUtils.createElement("h3", "", HTMLUtils.safeText(organization));
}
if (url) {
volItem += HTMLUtils.createElement("a", "description", HTMLUtils.safeText(url.replace(/^https?:\/\//i, "")), { href: url });
}
if (position) {
volItem += HTMLUtils.createElement("div", "title-anex", HTMLUtils.safeText(position));
}
if (summary) {
volItem += HTMLUtils.createElement("p", "", HTMLUtils.safeText(summary));
}
if (highlights && highlights.length > 0) {
volItem += ContentUtils.addHighlights(highlights);
}
volItem += `</div>`;
volItem += `</div>`;
volunteerSection += volItem;
}
volunteerSection += `</div>`;
return volunteerSection;
}
SectionCreators.createVolunteerSection = createVolunteerSection;
function createEducationSection(education) {
if (!education || education.length === 0)
return "";
let educationSection = HTMLUtils.createSection("Education");
for (const edu of education) {
const { institution, url, area, studyType, courses, startDate, endDate } = edu;
let eduItem = `<div class="timeline-section-item">`;
if (startDate || endDate) {
let timeline = `<div class="timeline">`;
if (endDate) {
timeline += HTMLUtils.createElement("span", "date", HTMLUtils.safeText(endDate));
}
else {
timeline += HTMLUtils.createElement("span", "date", "Present");
}
if (startDate) {
timeline += ` <br> `;
timeline += HTMLUtils.createElement("span", "date", HTMLUtils.safeText(startDate));
}
timeline += `</div>`;
eduItem += timeline;
}
eduItem += `<div class="timeline-section-details">`;
if (institution) {
eduItem += HTMLUtils.createElement("h3", "", HTMLUtils.safeText(institution));
}
if (url) {
eduItem += HTMLUtils.createElement("a", "description", HTMLUtils.safeText(url.replace(/^https?:\/\//i, "")), { href: url });
}
if (area || studyType) {
let areaStudy = `<div class="title-anex">`;
if (area) {
areaStudy += HTMLUtils.createElement("span", "", HTMLUtils.safeText(area));
}
if (studyType) {
areaStudy += HTMLUtils.createElement("span", "description", HTMLUtils.safeText(studyType));
}
areaStudy += `</div>`;
eduItem += areaStudy;
}
if (courses && courses.length > 0) {
let courseList = `<ul class="courses">`;
for (const course of courses) {
courseList += HTMLUtils.createElement("li", "", HTMLUtils.safeText(course));
}
courseList += `</ul>`;
eduItem += courseList;
}
eduItem += `</div>`;
eduItem += `</div>`;
educationSection += eduItem;
}
educationSection += `</div>`;
return educationSection;
}
SectionCreators.createEducationSection = createEducationSection;
})(SectionCreators || (SectionCreators = {}));
function createLeftColumn(data) {
let leftColumn = `<div class="left-column">`;
if (data.basics) {
leftColumn += SectionCreators.createBasicsSection(data.basics);
}
if (data.languages) {
leftColumn += SectionCreators.createLanguagesSection(data.languages);
}
if (data.skills) {
leftColumn += SectionCreators.createSkillsSection(data.skills);
}
if (data.interests) {
leftColumn += SectionCreators.createInterestsSection(data.interests);
}
if (data.references) {
leftColumn += SectionCreators.createReferencesSection(data.references);
}
leftColumn += `</div>`;
return leftColumn;
}
function createRightColumn(data) {
let rightColumn = `<div class="right-column">`;
if (data.work) {
rightColumn += SectionCreators.createExperienceSection(data.work);
}
if (data.projects) {
rightColumn += SectionCreators.createProjectsSection(data.projects);
}
if (data.volunteer) {
rightColumn += SectionCreators.createVolunteerSection(data.volunteer);
}
if (data.education) {
rightColumn += SectionCreators.createEducationSection(data.education);
}
rightColumn += `</div>`;
return rightColumn;
}
export function render(data) {
let resumeContainer = `<div class="resume-container">`;
resumeContainer += THEME_STYLES;
resumeContainer += createLeftColumn(data);
resumeContainer += createRightColumn(data);
resumeContainer += `</div>`;
return resumeContainer;
}
//# sourceMappingURL=index.js.map