Compare commits

..

No commits in common. "master" and "next" have entirely different histories.
master ... next

14 changed files with 2634 additions and 716 deletions

View File

@ -1,31 +0,0 @@
name: Build Site
run-name: ${{ github.actor }} is building Resume
on: [push]
jobs:
Build-Site:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [18.x]
steps:
- run: echo "Starting build job"
- uses: actions/checkout@v3
- name: Install Dependencies
run: |
apt update
apt install -y libnss3 libx11-xcb1 libxcomposite1 libasound2 libatk1.0-0 libatk-bridge2.0-0 libcairo2 libcups2 libdbus-1-3 libexpat1 libfontconfig1 libgbm1 libgcc1 libglib2.0-0 libgtk-3-0 libnspr4 libpango-1.0-0 libpangocairo-1.0-0 libstdc++6 libx11-6 libx11-xcb1 libxcb1 libxcomposite1 libxcursor1 libxdamage1 libxext6 libxfixes3 libxi6 libxrandr2 libxrender1 libxss1 libxtst6
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node-version }}
- run: npm ci
- run: npm run cibuild
# - name: setup go
# uses: https://github.com/actions/setup-go@v4
# with:
# go-version: '>=1.20.1'
# - name: Create Release
# uses: actions/release-action@main
# with:
# files: |-
# build/*.pdf

4
.gitignore vendored
View File

@ -1,4 +1,4 @@
node_modules
dev/
build/
public/
out/
.DS_Store

View File

@ -1,60 +1,37 @@
const { src, dest, watch, series, pipe } = require("gulp");
const bs = require("browser-sync").create();
const fs = require("fs");
const path = require("path");
const resumePath = path.join(__dirname, "resume.json");
const templateFile = path.join(__dirname, "theme/template.ejs");
//const sass = require("gulp-sass")(require("sass"));
const sass = require("sass");
const ejs = require('ejs');
const { src, dest, watch, series } = require('gulp')
const pug = require('gulp-pug')
const sass = require('gulp-sass')(require('sass'))
const bs = require('browser-sync').create()
const fs = require('fs')
function setup(cb) {
let dir = path.join(__dirname, "dev");
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir);
}
cb();
function css () {
return src('./theme/styles.scss')
.pipe(sass())
.pipe(dest('./theme'))
}
function css(cb) {
// src("./theme/**/*.scss")
// .pipe(sass().on("error", sass.logError))
// .pipe(dest("./dev"));
function html () {
const resume = JSON.parse(fs.readFileSync('./resume.json', 'utf-8'))
cb();
return src('./theme/template.pug')
.pipe(pug({ data: { resume } }))
.pipe(dest('./public'))
}
function html(cb) {
const resume = JSON.parse(fs.readFileSync("./resume.json", "utf-8"));
let css = sass.compile("./theme/style.scss");
let devBKG = sass.compile("./theme/devbkg.scss");
css.tagOpen = "<style>"
css.tagClose = "</style>"
css.devBKG = devBKG.css;
fs.writeFileSync(
path.join(__dirname, "dev/template.html"),
ejs.render(fs.readFileSync(templateFile, {encoding: "utf-8"}), {resume: resume, css: css})
);
cb();
}
function serve() {
function serve () {
bs.init({
server: {
baseDir: "./dev",
index: "template.html",
baseDir: './public',
index: 'template.html'
},
ui: false,
open: false,
});
open: false
})
watch(["./theme/**/*.ejs", "./resume.json"], html);
watch(["./theme/**/*.scss"], css);
bs.watch("./dev/*.html").on("change", bs.reload);
bs.watch("./dev/*.css").on("change", bs.reload);
watch('./theme/**/*.scss', series(css, html))
watch(['./theme/**/*.pug', './resume.json'], html)
bs.watch('./public/*.html').on('change', bs.reload)
}
exports.default = series(setup, css, html, serve);
exports.css = css
exports.default = series(css, html, serve)

View File

@ -1,18 +1,10 @@
const fs = require("fs");
const ejs = require('ejs');
const path = require("path");
const sass = (require("sass"));
const templateFile = path.join(__dirname, "theme/template.ejs");
const sassFile = path.join(__dirname, "theme/style.scss");
const pug = require('pug');
const path = require('path');
const render = (resume) => {
let css = sass.compile(sassFile);
css.tagOpen = "<style>"
css.tagClose = "</style>"
let redneredTemplate = ejs.render(fs.readFileSync(templateFile, {encoding: "utf-8"}), {resume: resume, css: css});
return redneredTemplate
};
const render = (resume) => pug.renderFile(path.join(__dirname, 'theme', 'template.pug'),{
resume
})
module.exports = {
render,
};
}

View File

@ -1,3 +0,0 @@
TLDR on theme generation.
In short, if you want to add a theme to the official list, you need to publish an NPM module named `jsonresume-theme-{name}`. That module needs to export a function called `render` that takes a `resume.json` and returns a plain HTML string.

2788
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,23 +1,22 @@
{
"name": "jsonresume-theme-thomaspcole",
"name": "resume",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"dev": "gulp",
"validate": "resume validate",
"dev": "resume serve --theme .",
"resume": "resume",
"cibuild": "mkdir -p build && env RESUME_PUPPETEER_NO_SANDBOX=true resume export build/resume.pdf --theme .",
"build": "mkdir -p build && resume export build/resume.pdf --theme ."
"build": "mkdir -p out && resume export out/resume.pdf && resume export out/resume.html"
},
"author": "Thomas Cole",
"license": "MIT",
"dependencies": {
"browser-sync": "^2.29.1",
"ejs": "^3.1.9",
"gulp": "^4.0.2",
"gulp-pug": "^5.0.0",
"gulp-sass": "^5.1.0",
"jsonresume-theme-elegant": "^1.16.1",
"pug": "^3.0.2",
"resume-cli": "^3.0.8",
"sass": "^1.64.1"
"sass": "^1.60.0"
}
}

View File

@ -2,7 +2,7 @@
"$schema": "https://raw.githubusercontent.com/jsonresume/resume-schema/v1.0.0/schema.json",
"basics": {
"name": "Thomas Cole",
"label": "System & Network Administrator",
"label": "",
"image": "https://avatars.githubusercontent.com/u/4421560",
"email": "thomas.patrick.cole@gmail.com",
"phone": "704-771-2453",
@ -37,7 +37,7 @@
"url": "https://christelca.org",
"startDate": "2020-12-02",
"endDate": "",
"summary": "Responsible for overseeing and enhancing the essential network infrastructure across multiple campuses. Managed backups to ensure data integrity and collaborated with action teams to create effective technology plans. Implemented cost-efficient software and hardware solutions, resulting in an annual cost reduction of $50,000.",
"summary": "",
"highlights": [
"Maintain and upgrade critical network infrastructure for a multi-campus environment",
"Facilitate backups and ensure their integrity",
@ -53,7 +53,7 @@
"url": "https://christelca.org",
"startDate": "2019-08-02",
"endDate": "2020-12-02",
"summary": "Spearheaded the development and implementation of innovative strategies aimed at enhancing live stream services and expanding audience outreach. Oversaw the building and installation of advanced computer systems, significantly improving the recording and streaming capabilities of worship services. Managed the graphics for both in-house worship and live-streamed services to create engaging and visually appealing experiences.",
"summary": "",
"highlights": [
"Developed and implemented new strategies in collaboration with the Christ Providence Tech team to improve live stream services and reach a broader audience",
"Facilitated building and installation of new computer systems to improve recording and streaming capabilities of worship services",
@ -68,7 +68,7 @@
"url": "https://scanonline.com/",
"startDate": "2019-06-02",
"endDate": "2020-12-02",
"summary": "Responsible for administering the Office 365 and Windows Active Directory infrastructure. Managed the VOIP phone system and maintained extension listings. Deployed and configured virtual machines to meet specific business requirements and maintained legacy Windows Mobile applications for existing clientele. Performed extensive configuration and maintenance of both customer hardware and software to ensure optimal performance.",
"summary": "",
"highlights": [
"Administer Office 365 and Windows Active Directory infrastructure",
"Manage company VOIP phone system and extension listings",
@ -86,7 +86,7 @@
"url": "https://www.uncg.edu/",
"startDate": "2018-02-02",
"endDate": "2019-05-02",
"summary": "Conducted assessments of helpdesk tickets, ensuring timely resolution of issues while maintaining accurate documentation. Maintained and troubleshot enterprise network systems. Actively collaborated with other network engineers to support the University's goals and objectives.",
"summary": "",
"highlights": [
"Assessed helpdesk tickets to ensure timely resolution of issues and proper documentation",
"Assisted in maintenance and troubleshooting of enterprise network systems",
@ -113,10 +113,10 @@
{
"institution": "University of North Carolina at Greensboro",
"url": "https://www.uncg.edu/",
"area": "Information Systems and Supply Chain Management",
"studyType": "Bachelor of Science",
"area": "Bachelor of Science Information Systems and Supply Chain Management",
"studyType": "",
"startDate": "2015-08-02",
"endDate": "2019-05-02",
"endDate": "2019-08-02",
"score": ""
}
],
@ -132,12 +132,12 @@
{
"name": "Web Development",
"level": "",
"keywords": ["HTML", "CSS", "Javascript", "Svelte", "Tailwind", "Static Site Generation", "REST", "Back End As A Service", "Typescript", "JQuery"]
"keywords": ["HTML", "CSS", "Javascript", "Svelte", "Tailwind", "Static Site Generation", "REST", "Back end as a service", "Typescript", "JQuery"]
},
{
"name": "Systems Administration",
"level": "",
"keywords": ["Linux", "Office 365", "Azure AD", "Microsoft Active Directory", "VMware ESXI", "Microsoft Exchange", "Docker", "Windows Server"]
"keywords": ["Linux", "Microsoft Active Directory", "Office 365", "Azure AD", "VMware ESXI", "Microsoft Exchange", "Docker", "Windows Server"]
},
{
"name": "Network Administration",
@ -149,6 +149,6 @@
"canonical": "https://raw.githubusercontent.com/jsonresume/resume-schema/master/resume.json",
"version": "v1.0.0",
"lastModified": "2017-12-24T15:53:00",
"theme": ""
"theme": "elegant"
}
}

View File

@ -1,15 +0,0 @@
body {
/* 'Danger' zone. Highlights content that would not print on the page */
width: 8.5in;
height: 11in;
margin: 0;
padding: 0;
background: repeating-linear-gradient(
45deg,
var(--error-container-alt),
var(--error-container-alt) 10px,
var(--error-container) 10px,
var(--error-container) 20px
)
fixed !important;
}

View File

@ -1,232 +0,0 @@
:root {
font-family: "Noto Sans", sans-serif;
--primary: #006494;
--on-primary: #ffffff;
--primary-container: #c8e6ff;
--on-primary-container: #001e31;
--secondary: #50606e;
--on-secondary: #ffffff;
--secondary-container: #d3e4f5;
--on-secondary-container: #0c1d29;
--tertiary: #65597b;
--on-tertiary: #ffffff;
--tertiary-container: #ecdcff;
--on-tertiary-container: #201634;
--error: #ba1b1b;
--error-container: #ffdad4;
--on-error: #ffffff;
--on-error-container: #410001;
--background: #fcfcff;
--on-background: #1a1c1e;
--surface: #fcfcff;
--on-surface: #1a1c1e;
--surface-variant: #dee3ea;
--on-surface-variant: #41474d;
--outline: #72787e;
--inverse-on-surface: #f0f0f3;
--inverse-surface: #2f3032;
--inverse-primary: #8bceff;
--error-container-alt: #ffd3cc;
}
body {
width: 8.5in;
height: 11in;
margin: 0;
padding: 0;
background-color: var(--background);
}
p {
margin: 0;
}
.page {
page-break-after: always;
position: relative;
width: 8.5in;
height: 11in;
}
.page-content {
position: absolute;
width: 8.125in;
height: 10.625in;
left: 0.1875in;
top: 0.1875in;
color: var(--on-background);
background-color: var(--background);
}
.resumehead {
width: 100%;
padding: 16px;
h1 {
font-weight: 500;
text-transform: uppercase;
margin: 0;
font-size: 2.5rem;
line-height: 2.5rem;
}
h5 {
font-weight: 300;
text-transform: uppercase;
margin: 0;
}
.divider {
display: flex;
background-color: var(--on-background);
width: 100%;
height: 1px;
}
.resumehead-name {
float: right;
text-align: right;
}
.resumehead-contactinfo {
float: right;
text-align: right;
display: flex;
padding-top: 4px;
font-size: 13px;
.material-symbols-outlined {
font-variation-settings: "FILL" 1, "wght" 400, "GRAD" 0, "opsz" 24;
font-size: 16px;
}
:last-child {
margin-right: 0;
}
}
// Weird values but the picture midline is the divider line
.profile-image {
width: 17%;
border-radius: 50%;
position: absolute;
transform: translate(0, -5.75%);
margin-left: 2em;
border: 8px solid var(--background);
}
}
.contactinfo {
display: flex;
justify-content: center;
align-items: center;
gap: 4px;
margin-right: 16px;
p {
font-weight: 300;
}
}
.resumebody {
margin-top: 3rem;
width: 100%;
display: grid;
grid-auto-columns: 1fr;
grid-template-columns: 30% 1fr;
grid-template-rows: 1fr;
gap: 0px 2em;
grid-template-areas: ". .";
h1,h2,h3,h4,h5,h6{
margin: 0;
margin-bottom: .5em;
}
p{
font-size: 12px;
}
.l{
margin-left: 16px;
}
.r{
margin-right: 16px;
}
}
.space{
height: 1em;
&-small{
height: .25em;
}
}
.timelineitem{
border-bottom: 1px solid var(--on-background);
border-left: 1px solid var(--on-background);
margin-bottom: .75rem;
margin-left: .25rem;
padding-left: 1rem;
padding-bottom: .25rem;
position: relative;
h1,h2,h3,h4,h5,h6{
margin: 0;
}
.date{
background-color: var(--background);
position: absolute;
padding-right: 5px;
padding-left: 2px;
top: 0;
left: 0;
transform-origin: 0 0;
transform: rotate(-90deg) translate(-99%, -55%);
}
}
.skill-container{
margin-bottom: .75rem;
border-bottom: 1px solid var(--on-background);
border-left: 1px solid var(--on-background);
padding-left: .5rem;
padding-bottom: .5rem;
}
.chip{
color: var(--background);
background-color: var(--on-background);
display: inline-flex;
flex-direction: row;
border: none;
outline: none;
padding: 0;
white-space: nowrap;
align-items: center;
border-radius: 16px;
vertical-align: middle;
text-decoration: none;
justify-content: center;
font-size: .75em;
}
.chip-content{
display: flex;
align-items: center;
user-select: none;
white-space: nowrap;
padding-left: .5rem;
padding-right: .5rem;
}
@media print {
body {
background: unset;
background-color: var(--background);
}
}

0
theme/styles.css Normal file
View File

1
theme/styles.scss Normal file
View File

@ -0,0 +1 @@
@charset "UTF-8";

View File

@ -1,136 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Resume - <%= resume.basics.name %></title>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=Open+Sans:ital,wght@0,300;0,400;0,500;0,600;0,700;0,800;1,300;1,400;1,500;1,600;1,700;1,800&display=swap" rel="stylesheet" />
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans:ital,wght@0,100;0,200;0,300;0,400;0,500;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap" rel="stylesheet" />
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200" />
<style>
.material-symbols-outlined {
font-variation-settings: "FILL"0, "wght"400, "GRAD"0, "opsz"48;
}
*,
*:before,
*:after {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
</style>
<% if (css.devBKG) { %>
<%- css.tagOpen + css.css + css.devBKG + css.tagClose %>
<% } else { %>
<%- css.tagOpen + css.css + css.tagClose %>
<% } %>
</head>
<body>
<div class="page">
<div class="page-content">
<div class="resumehead">
<img class="profile-image" src=<%= resume.basics.image %> alt="">
<div class="resumehead-name">
<h5><%= resume.basics.label %></h5>
<h1><%= resume.basics.name %></h1>
</div>
<span class="divider"></span>
<div class="resumehead-contactinfo">
<div class="contactinfo">
<span class="material-symbols-outlined">
phone
</span>
<p><%= resume.basics.phone %></p>
</div>
<div class="contactinfo">
<span class="material-symbols-outlined">
mail
</span>
<p><%= resume.basics.email %></p>
</div>
<div class="contactinfo">
<span class="material-symbols-outlined">
pin_drop
</span>
<p><%= resume.basics.location.address %> Matthews, NC</p>
</div>
</div>
</div>
<div class="resumebody">
<div class="l">
<h3>Profile</h3>
<p><%= resume.basics.summary %></p>
<br>
<h3>Skills</h3>
<% resume.skills.forEach(element => { %>
<!-- Timeline component -->
<div class="skill-container">
<h5><%= element.name %></h5>
<div class="chip-container">
<% element.keywords.forEach(word => { %>
<div class="chip"><div class="chip-content"><%= word %></div></div>
<% }) %>
</div>
</div>
<% }) %>
</div>
<div class="r">
<h3>Experience</h3>
<% resume.work.forEach(element => { %>
<!-- Timeline component -->
<div class="timelineitem">
<h4><%= element.position %></h4>
<p><i><%= element.name %></i></p>
<div class="space-small"></div>
<p><%= element.summary %></p>
<% if (element.endDate) { %>
<p class="date"><%= new Date(element.startDate).getFullYear() %> - <%= new Date(element.endDate).getFullYear() %></p>
<% } else { %>
<p class="date"><%= new Date(element.startDate).getFullYear() %> - Now</p>
<% } %>
</div>
<% }) %>
<div class="space"></div>
<h3>Education</h3>
<% resume.education.forEach(element => { %>
<!-- Timeline component -->
<div class="timelineitem">
<h4><%= element.area %></h4>
<p><i><%= element.studyType %></i></p>
<div class="space-small"></div>
<p><%= element.institution %></p>
<p class="date"><%= new Date(element.endDate).getFullYear() %> </p>
</div>
<% }) %>
<div class="space"></div>
<h3>Certifications</h3>
<% resume.certificates.forEach(element => { %>
<!-- Timeline component -->
<div class="timelineitem">
<h4><%= element.name %></h4>
<p><i><%= element.issuer %></i></p>
<p class="date"><%= new Date(element.date).getFullYear() %> </p>
</div>
<% }) %>
</div>
</div>
</div>
</div>
</body>
</html>

8
theme/template.pug Normal file
View File

@ -0,0 +1,8 @@
doctype html
html(lang="en")
head
meta(charset="utf-8")
style
include styles.css
title=`Resume ${resume.basics.name}`
body