├── img
├── .gitkeep
├── default-image.png
├── substack.svg
├── tiktok.svg
├── twitter-x.svg
├── twitch.svg
├── facebook.svg
├── stack-overflow.svg
├── twitter.svg
├── linkedin.svg
├── github.svg
├── globe.svg
├── bluesky.svg
├── youtube.svg
├── threads.svg
├── mastodon.svg
├── slack.svg
├── threads-fill.svg
└── instagram.svg
├── js
└── app.js
├── requirements.txt
├── icon.png
├── favicon.ico
├── icon-192x192.png
├── icon-512x512.png
├── portfolio_media
├── ww1.jpg
├── ww2.jpg
├── yt1.png
├── yt2.png
├── yt3.png
└── profile.jpg
├── robots.txt
├── site.webmanifest
├── LICENSE
├── generate_portfolio.py
├── css
├── resume.css
├── modern_normalize.css
├── html5bp.css
└── main.css
├── portfolio-corey.json
├── portfolio.json
├── .gitignore
├── resume_template.html
├── resume.html
├── index_template.html
└── index.html
/img/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/js/app.js:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | Jinja2==3.1.4
2 | MarkupSafe==3.0.2
--------------------------------------------------------------------------------
/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CoreyMSchafer/portfolio_generator/HEAD/icon.png
--------------------------------------------------------------------------------
/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CoreyMSchafer/portfolio_generator/HEAD/favicon.ico
--------------------------------------------------------------------------------
/icon-192x192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CoreyMSchafer/portfolio_generator/HEAD/icon-192x192.png
--------------------------------------------------------------------------------
/icon-512x512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CoreyMSchafer/portfolio_generator/HEAD/icon-512x512.png
--------------------------------------------------------------------------------
/img/default-image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CoreyMSchafer/portfolio_generator/HEAD/img/default-image.png
--------------------------------------------------------------------------------
/portfolio_media/ww1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CoreyMSchafer/portfolio_generator/HEAD/portfolio_media/ww1.jpg
--------------------------------------------------------------------------------
/portfolio_media/ww2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CoreyMSchafer/portfolio_generator/HEAD/portfolio_media/ww2.jpg
--------------------------------------------------------------------------------
/portfolio_media/yt1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CoreyMSchafer/portfolio_generator/HEAD/portfolio_media/yt1.png
--------------------------------------------------------------------------------
/portfolio_media/yt2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CoreyMSchafer/portfolio_generator/HEAD/portfolio_media/yt2.png
--------------------------------------------------------------------------------
/portfolio_media/yt3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CoreyMSchafer/portfolio_generator/HEAD/portfolio_media/yt3.png
--------------------------------------------------------------------------------
/robots.txt:
--------------------------------------------------------------------------------
1 | # https://www.robotstxt.org/
2 |
3 | # Allow crawling of all content
4 | User-agent: *
5 | Disallow:
6 |
--------------------------------------------------------------------------------
/portfolio_media/profile.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CoreyMSchafer/portfolio_generator/HEAD/portfolio_media/profile.jpg
--------------------------------------------------------------------------------
/img/substack.svg:
--------------------------------------------------------------------------------
1 |
11 |
--------------------------------------------------------------------------------
/img/tiktok.svg:
--------------------------------------------------------------------------------
1 |
11 |
--------------------------------------------------------------------------------
/img/twitter-x.svg:
--------------------------------------------------------------------------------
1 |
11 |
--------------------------------------------------------------------------------
/img/twitch.svg:
--------------------------------------------------------------------------------
1 |
12 |
--------------------------------------------------------------------------------
/site.webmanifest:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Portfolio",
3 | "short_name": "Portfolio",
4 | "icons": [
5 | {
6 | "src": "/icon-192x192.png",
7 | "sizes": "192x192",
8 | "type": "image/png",
9 | "purpose": "any"
10 | },
11 | {
12 | "src": "/icon-512x512.png",
13 | "sizes": "512x512",
14 | "type": "image/png",
15 | "purpose": "any"
16 | }
17 | ],
18 | "theme_color": "#ffffff",
19 | "background_color": "#ffffff",
20 | "display": "standalone"
21 | }
22 |
--------------------------------------------------------------------------------
/img/facebook.svg:
--------------------------------------------------------------------------------
1 |
11 |
--------------------------------------------------------------------------------
/img/stack-overflow.svg:
--------------------------------------------------------------------------------
1 |
12 |
--------------------------------------------------------------------------------
/img/twitter.svg:
--------------------------------------------------------------------------------
1 |
11 |
--------------------------------------------------------------------------------
/img/linkedin.svg:
--------------------------------------------------------------------------------
1 |
11 |
--------------------------------------------------------------------------------
/img/github.svg:
--------------------------------------------------------------------------------
1 |
11 |
--------------------------------------------------------------------------------
/img/globe.svg:
--------------------------------------------------------------------------------
1 |
11 |
--------------------------------------------------------------------------------
/img/bluesky.svg:
--------------------------------------------------------------------------------
1 |
10 |
--------------------------------------------------------------------------------
/img/youtube.svg:
--------------------------------------------------------------------------------
1 |
11 |
--------------------------------------------------------------------------------
/img/threads.svg:
--------------------------------------------------------------------------------
1 |
11 |
--------------------------------------------------------------------------------
/img/mastodon.svg:
--------------------------------------------------------------------------------
1 |
11 |
--------------------------------------------------------------------------------
/img/slack.svg:
--------------------------------------------------------------------------------
1 |
11 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2025 Corey Schafer
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/img/threads-fill.svg:
--------------------------------------------------------------------------------
1 |
12 |
--------------------------------------------------------------------------------
/generate_portfolio.py:
--------------------------------------------------------------------------------
1 | import json
2 | from datetime import UTC, datetime
3 | from pathlib import Path
4 |
5 | from jinja2 import Environment, FileSystemLoader
6 |
7 | # Load JSON data
8 | with Path("portfolio.json").open(encoding="utf-8") as f:
9 | data = json.load(f)
10 |
11 | # Add any extra context if needed
12 | data["current_year"] = datetime.now(tz=UTC).year
13 |
14 | if "social_links" in data:
15 | for link in data["social_links"]:
16 | if link.get("svg_path"):
17 | with Path(link["svg_path"]).open(encoding="utf-8") as svg_file:
18 | link["svg_data"] = svg_file.read()
19 |
20 | # Set up Jinja environment
21 | env = Environment(loader=FileSystemLoader("."), autoescape=True)
22 | index_template = env.get_template("index_template.html")
23 | resume_template = env.get_template("resume_template.html")
24 |
25 | # Render the template with the data
26 | html_output = index_template.render(**data)
27 | resume_output = resume_template.render(**data)
28 |
29 | # This is equivalent to...
30 | # html_output = index_template.render(name=data["name"], label=data["label"]...)
31 | # resume_output = resume_template.render(name=data["name"], label=data["label"]...)
32 |
33 | # Write the output to an HTML file
34 | with Path("index.html").open("w", encoding="utf-8") as f:
35 | f.write(html_output)
36 |
37 | with Path("resume.html").open("w", encoding="utf-8") as f:
38 | f.write(resume_output)
39 |
40 | print("HTML file generated successfully!")
41 |
--------------------------------------------------------------------------------
/img/instagram.svg:
--------------------------------------------------------------------------------
1 |
11 |
--------------------------------------------------------------------------------
/css/resume.css:
--------------------------------------------------------------------------------
1 | @page {
2 | size: letter;
3 | margin: 0in;
4 | }
5 |
6 | html {
7 | font-size: 11pt;
8 | }
9 |
10 | a[href]::after {
11 | content: "";
12 | }
13 |
14 | section {
15 | page-break-inside: avoid;
16 | }
17 |
18 | header {
19 | padding: 0.5in;
20 | }
21 |
22 | header {
23 | padding-bottom: 0.5rem;
24 | }
25 |
26 | .header-info {
27 | margin-top: 0;
28 | }
29 |
30 | main,
31 | aside,
32 | footer {
33 | padding: 2rem;
34 | }
35 |
36 | main {
37 | padding-left: 0.5in;
38 | padding-bottom: 0.5in;
39 | }
40 |
41 | aside {
42 | padding-right: 0.5in;
43 | padding-bottom: 0.5in;
44 | }
45 |
46 | .page-header,
47 | .page-footer {
48 | background: #fff;
49 | }
50 |
51 | .flex-responsive {
52 | display: flex;
53 | flex-direction: column;
54 | align-items: center;
55 | text-align: center;
56 | }
57 |
58 | aside {
59 | border-top: none;
60 | border-left: 1px solid #ccc;
61 | }
62 |
63 | aside h1 {
64 | font-size: 1.4rem;
65 | }
66 |
67 | aside h2 {
68 | font-size: 1.1rem;
69 | }
70 |
71 | aside h3 {
72 | font-size: 1rem;
73 | }
74 |
75 | aside h4 {
76 | font-size: 1rem;
77 | }
78 |
79 | aside h5 {
80 | font-size: 1rem;
81 | }
82 |
83 | aside h6 {
84 | font-size: 1rem;
85 | }
86 |
87 | .page-content .container {
88 | grid-template-columns: 2fr 1fr;
89 | }
90 |
91 | .header-top {
92 | gap: 2rem;
93 | }
94 |
95 | .page-header ul {
96 | margin: 0.5rem 0;
97 | }
98 |
99 | .inline-list {
100 | flex-direction: row;
101 | justify-content: center;
102 | gap: var(--spacing-inline);
103 | }
104 |
105 | .inline-list li:not(:last-child)::after {
106 | content: "|";
107 | margin-left: var(--spacing-inline);
108 | color: #ccc;
109 | }
110 |
--------------------------------------------------------------------------------
/css/modern_normalize.css:
--------------------------------------------------------------------------------
1 | /*! modern-normalize v3.0.1 | MIT License | https://github.com/sindresorhus/modern-normalize */
2 |
3 | /*
4 | Document
5 | ========
6 | */
7 |
8 | /**
9 | Use a better box model (opinionated).
10 | */
11 |
12 | *,
13 | ::before,
14 | ::after {
15 | box-sizing: border-box;
16 | }
17 |
18 | html {
19 | /* Improve consistency of default fonts in all browsers. (https://github.com/sindresorhus/modern-normalize/issues/3) */
20 | font-family: system-ui, "Segoe UI", Roboto, Helvetica, Arial, sans-serif,
21 | "Apple Color Emoji", "Segoe UI Emoji";
22 | line-height: 1.15; /* 1. Correct the line height in all browsers. */
23 | -webkit-text-size-adjust: 100%; /* 2. Prevent adjustments of font size after orientation changes in iOS. */
24 | tab-size: 4; /* 3. Use a more readable tab size (opinionated). */
25 | }
26 |
27 | /*
28 | Sections
29 | ========
30 | */
31 |
32 | body {
33 | margin: 0; /* Remove the margin in all browsers. */
34 | }
35 |
36 | /*
37 | Text-level semantics
38 | ====================
39 | */
40 |
41 | /**
42 | Add the correct font weight in Chrome and Safari.
43 | */
44 |
45 | b,
46 | strong {
47 | font-weight: bolder;
48 | }
49 |
50 | /**
51 | 1. Improve consistency of default fonts in all browsers. (https://github.com/sindresorhus/modern-normalize/issues/3)
52 | 2. Correct the odd 'em' font sizing in all browsers.
53 | */
54 |
55 | code,
56 | kbd,
57 | samp,
58 | pre {
59 | font-family: ui-monospace, SFMono-Regular, Consolas, "Liberation Mono", Menlo,
60 | monospace; /* 1 */
61 | font-size: 1em; /* 2 */
62 | }
63 |
64 | /**
65 | Add the correct font size in all browsers.
66 | */
67 |
68 | small {
69 | font-size: 80%;
70 | }
71 |
72 | /**
73 | Prevent 'sub' and 'sup' elements from affecting the line height in all browsers.
74 | */
75 |
76 | sub,
77 | sup {
78 | font-size: 75%;
79 | line-height: 0;
80 | position: relative;
81 | vertical-align: baseline;
82 | }
83 |
84 | sub {
85 | bottom: -0.25em;
86 | }
87 |
88 | sup {
89 | top: -0.5em;
90 | }
91 |
92 | /*
93 | Tabular data
94 | ============
95 | */
96 |
97 | /**
98 | Correct table border color inheritance in Chrome and Safari. (https://issues.chromium.org/issues/40615503, https://bugs.webkit.org/show_bug.cgi?id=195016)
99 | */
100 |
101 | table {
102 | border-color: currentcolor;
103 | }
104 |
105 | /*
106 | Forms
107 | =====
108 | */
109 |
110 | /**
111 | 1. Change the font styles in all browsers.
112 | 2. Remove the margin in Firefox and Safari.
113 | */
114 |
115 | button,
116 | input,
117 | optgroup,
118 | select,
119 | textarea {
120 | font-family: inherit; /* 1 */
121 | font-size: 100%; /* 1 */
122 | line-height: 1.15; /* 1 */
123 | margin: 0; /* 2 */
124 | }
125 |
126 | /**
127 | Correct the inability to style clickable types in iOS and Safari.
128 | */
129 |
130 | button,
131 | [type="button"],
132 | [type="reset"],
133 | [type="submit"] {
134 | -webkit-appearance: button;
135 | }
136 |
137 | /**
138 | Remove the padding so developers are not caught out when they zero out 'fieldset' elements in all browsers.
139 | */
140 |
141 | legend {
142 | padding: 0;
143 | }
144 |
145 | /**
146 | Add the correct vertical alignment in Chrome and Firefox.
147 | */
148 |
149 | progress {
150 | vertical-align: baseline;
151 | }
152 |
153 | /**
154 | Correct the cursor style of increment and decrement buttons in Safari.
155 | */
156 |
157 | ::-webkit-inner-spin-button,
158 | ::-webkit-outer-spin-button {
159 | height: auto;
160 | }
161 |
162 | /**
163 | 1. Correct the odd appearance in Chrome and Safari.
164 | 2. Correct the outline style in Safari.
165 | */
166 |
167 | [type="search"] {
168 | -webkit-appearance: textfield; /* 1 */
169 | outline-offset: -2px; /* 2 */
170 | }
171 |
172 | /**
173 | Remove the inner padding in Chrome and Safari on macOS.
174 | */
175 |
176 | ::-webkit-search-decoration {
177 | -webkit-appearance: none;
178 | }
179 |
180 | /**
181 | 1. Correct the inability to style clickable types in iOS and Safari.
182 | 2. Change font properties to 'inherit' in Safari.
183 | */
184 |
185 | ::-webkit-file-upload-button {
186 | -webkit-appearance: button; /* 1 */
187 | font: inherit; /* 2 */
188 | }
189 |
190 | /*
191 | Interactive
192 | ===========
193 | */
194 |
195 | /*
196 | Add the correct display in Chrome and Safari.
197 | */
198 |
199 | summary {
200 | display: list-item;
201 | }
202 |
--------------------------------------------------------------------------------
/portfolio-corey.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Corey Schafer",
3 | "label": "Software Engineer",
4 | "image_path": "portfolio_media/profile.jpg",
5 | "contact": {
6 | "email": "CoreyMSchafer@gmail.com",
7 | "phone": "",
8 | "location": "Charleston, WV"
9 | },
10 | "summary": "Programming educator on YouTube. Simplifying complex concepts into manageable steps to help learners digest material at their own pace.",
11 | "url": "https://coreyms.com",
12 | "social_links": [
13 | {
14 | "label": "Coreyms.com",
15 | "url": "https://coreyms.com",
16 | "svg_path": "img/globe.svg"
17 | },
18 | {
19 | "label": "YouTube",
20 | "url": "https://youtube.com/c/coreyms",
21 | "svg_path": "img/youtube.svg"
22 | },
23 | {
24 | "label": "Instagram",
25 | "url": "https://www.instagram.com/coreymschafer",
26 | "svg_path": "img/instagram.svg"
27 | },
28 | {
29 | "label": "Github",
30 | "url": "https://github.com/CoreyMSchafer",
31 | "svg_path": "img/github.svg"
32 | }
33 | ],
34 | "work_experience": [
35 | {
36 | "company": "LASP (Labratory for Atmospheric and Space Physics)",
37 | "position": "Software Engineer",
38 | "url": "https://lasp.colorado.edu/",
39 | "start_date": "2015",
40 | "end_date": "2019",
41 | "summary": "",
42 | "highlights": [
43 | "Created and maintained back-end API services using Flask.",
44 | "Created system administration scripts using Python to automate the processing and deployment of mission-critical data.",
45 | "Tasked with migrating in-house data pipelines to a cloud-based solution using AWS."
46 | ]
47 | },
48 | {
49 | "company": "WVU GIS Technical Center",
50 | "position": "Software Engineer",
51 | "url": "https://wvgis.wvu.edu/",
52 | "start_date": "2012",
53 | "end_date": "2015",
54 | "summary": "",
55 | "highlights": [
56 | "Developed and designed GIS web applications with the ArcGIS JavaScript API",
57 | "Wrote and published geoprocessing services using Python and ArcPy",
58 | "Created backend user authentication systems with PHP and MySQL"
59 | ]
60 | },
61 | {
62 | "company": "MATRIC (Mid-Atlantic Technology, Research, and Innovation Center)",
63 | "position": "Software Engineer",
64 | "url": "https://www.matricinnovates.com/",
65 | "start_date": "2010",
66 | "end_date": "2011",
67 | "summary": "",
68 | "highlights": [
69 | "Created GIS web applications with ActionScript and the ArcGIS API for Flex.",
70 | "Developed custom widgets for routing, wind data visualization, and simulations.",
71 | "Wrote and maintained SQL-based queries to efficiently retrieve and analyze data from GIS REST services."
72 | ]
73 | }
74 | ],
75 | "projects": [
76 | {
77 | "title": "Educational Content Creator on YouTube",
78 | "summary": "Channel focused on creating tutorials and walkthroughs for software developers, programmers, and engineers.",
79 | "url": "https://youtube.com/c/coreyms",
80 | "highlights": ["Over 1 million subscribers", "Over 100 million views"],
81 | "images": [
82 | {
83 | "img_path": "portfolio_media/yt1.png",
84 | "caption": "Main Channel"
85 | },
86 | {
87 | "img_path": "portfolio_media/yt2.png",
88 | "caption": "Tutorials"
89 | },
90 | {
91 | "img_path": "portfolio_media/yt3.png",
92 | "caption": "Live Streams"
93 | }
94 | ]
95 | }
96 | ],
97 | "volunteer_experience": [
98 | {
99 | "organization": "Heritage Point Assisted Living",
100 | "position": "Computer Assistance",
101 | "url": "https://www.heritage-point.com/",
102 | "start_date": "2012",
103 | "end_date": "2015",
104 | "summary": "Helped residents with any computer problems for two hours each week. Mainly helped with networking, typing, basic instruction, and troubleshooting.",
105 | "highlights": []
106 | },
107 | {
108 | "organization": "Marshall University",
109 | "position": "Student Ambassador",
110 | "url": "https://marshall.edu",
111 | "start_date": "2007",
112 | "end_date": "2008",
113 | "summary": "Gave campus tours, organized promotional events, and ran summer orientation.",
114 | "highlights": []
115 | }
116 | ],
117 | "education": [
118 | {
119 | "institution": "Marshall University",
120 | "location": "Hungington, WV, USA",
121 | "url": "https://marshall.edu",
122 | "degrees": [
123 | "Bachelor of Science in Computer Science",
124 | "Minor in Mathematics"
125 | ],
126 | "honors": [
127 | "2010 Outstanding Student Award",
128 | "2005 R.L. “Buck” Woodall Student-Athlete scholarship",
129 | "Placed in a District ACM ICPC Team Programming Contest"
130 | ],
131 | "gpa_cumulative": "3.29",
132 | "gpa_major": "3.93",
133 | "graduation_date": "2010"
134 | }
135 | ],
136 | "skills": [
137 | {
138 | "name": "Python, Flask, Django",
139 | "proficiency": 100,
140 | "proficiency_label": "Expert"
141 | },
142 | {
143 | "name": "System Administration, Linux",
144 | "proficiency": 90,
145 | "proficiency_label": "Advanced"
146 | },
147 | {
148 | "name": "JavaScript, HTML, CSS",
149 | "proficiency": 75,
150 | "proficiency_label": "Comfortable"
151 | }
152 | ],
153 | "interests": [
154 | {
155 | "name": "Woodworking",
156 | "summary": "",
157 | "images": [
158 | {
159 | "img_path": "portfolio_media/ww1.jpg",
160 | "caption": "Chess Board made from Walnut and Maple"
161 | },
162 | {
163 | "img_path": "portfolio_media/ww2.jpg",
164 | "caption": "Wooden Necklace from Walnut Scrap"
165 | }
166 | ]
167 | }
168 | ],
169 | "languages": [],
170 | "references": []
171 | }
172 |
--------------------------------------------------------------------------------
/css/html5bp.css:
--------------------------------------------------------------------------------
1 | /*! HTML5 Boilerplate v9.0.1 | MIT License | https://html5boilerplate.com/ */
2 |
3 | /* main.css 3.0.0 | MIT License | https://github.com/h5bp/main.css#readme */
4 | /*
5 | * What follows is the result of much research on cross-browser styling.
6 | * Credit left inline and big thanks to Nicolas Gallagher, Jonathan Neal,
7 | * Kroc Camen, and the H5BP dev community and team.
8 | */
9 |
10 | /* ==========================================================================
11 | Base styles: opinionated defaults
12 | ========================================================================== */
13 |
14 | html {
15 | color: #222;
16 | font-size: 1em;
17 | line-height: 1.4;
18 | }
19 |
20 | /*
21 | * Remove text-shadow in selection highlight:
22 | * https://twitter.com/miketaylr/status/12228805301
23 | *
24 | * Customize the background color to match your design.
25 | */
26 |
27 | ::-moz-selection {
28 | background: #b3d4fc;
29 | text-shadow: none;
30 | }
31 |
32 | ::selection {
33 | background: #b3d4fc;
34 | text-shadow: none;
35 | }
36 |
37 | /*
38 | * A better looking default horizontal rule
39 | */
40 |
41 | hr {
42 | display: block;
43 | height: 1px;
44 | border: 0;
45 | border-top: 1px solid #ccc;
46 | margin: 1em 0;
47 | padding: 0;
48 | }
49 |
50 | /*
51 | * Remove the gap between audio, canvas, iframes,
52 | * images, videos and the bottom of their containers:
53 | * https://github.com/h5bp/html5-boilerplate/issues/440
54 | */
55 |
56 | audio,
57 | canvas,
58 | iframe,
59 | img,
60 | svg,
61 | video {
62 | vertical-align: middle;
63 | }
64 |
65 | /*
66 | * Remove default fieldset styles.
67 | */
68 |
69 | fieldset {
70 | border: 0;
71 | margin: 0;
72 | padding: 0;
73 | }
74 |
75 | /*
76 | * Allow only vertical resizing of textareas.
77 | */
78 |
79 | textarea {
80 | resize: vertical;
81 | }
82 |
83 | /* ==========================================================================
84 | Author's custom styles
85 | ========================================================================== */
86 |
87 | /* ==========================================================================
88 | Helper classes
89 | ========================================================================== */
90 |
91 | /*
92 | * Hide visually and from screen readers
93 | */
94 |
95 | .hidden,
96 | [hidden] {
97 | display: none !important;
98 | }
99 |
100 | /*
101 | * Hide only visually, but have it available for screen readers:
102 | * https://snook.ca/archives/html_and_css/hiding-content-for-accessibility
103 | *
104 | * 1. For long content, line feeds are not interpreted as spaces and small width
105 | * causes content to wrap 1 word per line:
106 | * https://medium.com/@jessebeach/beware-smushed-off-screen-accessible-text-5952a4c2cbfe
107 | */
108 |
109 | .visually-hidden {
110 | border: 0;
111 | clip: rect(0, 0, 0, 0);
112 | height: 1px;
113 | margin: -1px;
114 | overflow: hidden;
115 | padding: 0;
116 | position: absolute;
117 | white-space: nowrap;
118 | width: 1px;
119 | /* 1 */
120 | }
121 |
122 | /*
123 | * Extends the .visually-hidden class to allow the element
124 | * to be focusable when navigated to via the keyboard:
125 | * https://www.drupal.org/node/897638
126 | */
127 |
128 | .visually-hidden.focusable:active,
129 | .visually-hidden.focusable:focus {
130 | clip: auto;
131 | height: auto;
132 | margin: 0;
133 | overflow: visible;
134 | position: static;
135 | white-space: inherit;
136 | width: auto;
137 | }
138 |
139 | /*
140 | * Hide visually and from screen readers, but maintain layout
141 | */
142 |
143 | .invisible {
144 | visibility: hidden;
145 | }
146 |
147 | /*
148 | * Clearfix: contain floats
149 | *
150 | * The use of `table` rather than `block` is only necessary if using
151 | * `::before` to contain the top-margins of child elements.
152 | */
153 |
154 | .clearfix::before,
155 | .clearfix::after {
156 | content: "";
157 | display: table;
158 | }
159 |
160 | .clearfix::after {
161 | clear: both;
162 | }
163 |
164 | /* ==========================================================================
165 | EXAMPLE Media Queries for Responsive Design.
166 | These examples override the primary ('mobile first') styles.
167 | Modify as content requires.
168 | ========================================================================== */
169 |
170 | @media only screen and (min-width: 35em) {
171 | /* Style adjustments for viewports that meet the condition */
172 | }
173 |
174 | @media print,
175 | (-webkit-min-device-pixel-ratio: 1.25),
176 | (min-resolution: 1.25dppx),
177 | (min-resolution: 120dpi) {
178 | /* Style adjustments for high resolution devices */
179 | }
180 |
181 | /* ==========================================================================
182 | Print styles.
183 | Inlined to avoid the additional HTTP request:
184 | https://www.phpied.com/delay-loading-your-print-css/
185 | ========================================================================== */
186 |
187 | @media print {
188 | *,
189 | *::before,
190 | *::after {
191 | background: #fff !important;
192 | color: #000 !important;
193 | /* Black prints faster */
194 | box-shadow: none !important;
195 | text-shadow: none !important;
196 | }
197 |
198 | a,
199 | a:visited {
200 | text-decoration: underline;
201 | }
202 |
203 | a[href]::after {
204 | content: " (" attr(href) ")";
205 | }
206 |
207 | abbr[title]::after {
208 | content: " (" attr(title) ")";
209 | }
210 |
211 | /*
212 | * Don't show links that are fragment identifiers,
213 | * or use the `javascript:` pseudo protocol
214 | */
215 | a[href^="#"]::after,
216 | a[href^="javascript:"]::after {
217 | content: "";
218 | }
219 |
220 | pre {
221 | white-space: pre-wrap !important;
222 | }
223 |
224 | pre,
225 | blockquote {
226 | border: 1px solid #999;
227 | page-break-inside: avoid;
228 | }
229 |
230 | tr,
231 | img {
232 | page-break-inside: avoid;
233 | }
234 |
235 | p,
236 | h2,
237 | h3 {
238 | orphans: 3;
239 | widows: 3;
240 | }
241 |
242 | h2,
243 | h3 {
244 | page-break-after: avoid;
245 | }
246 | }
247 |
248 |
--------------------------------------------------------------------------------
/portfolio.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Your Name",
3 | "label": "Optional Label",
4 | "image_path": "img/default-image.png",
5 | "contact": {
6 | "email": "FirstLast@Sample.com",
7 | "phone": "123-456-7890",
8 | "location": "City, State, Country"
9 | },
10 | "summary": "A short summary of who you are, your background, experience, and interests to give visitors a quick introduction to you.",
11 | "base_url": "127.0.0.1:5500",
12 | "social_links": [
13 | {
14 | "label": "Personal Website",
15 | "url": "https://sample.com",
16 | "svg_path": "img/globe.svg"
17 | },
18 | {
19 | "label": "First Social",
20 | "url": "https://sample.com",
21 | "svg_path": "img/linkedin.svg"
22 | },
23 | {
24 | "label": "Second Social",
25 | "url": "https://sample.com",
26 | "svg_path": "img/github.svg"
27 | }
28 | ],
29 | "work_experience": [
30 | {
31 | "company": "Latest Job",
32 | "position": "Position One",
33 | "url": "https://sample.com",
34 | "start_date": "01/01/2020",
35 | "end_date": "Present",
36 | "summary": "Short summary about present job and what the position entails",
37 | "highlights": [
38 | "First Duty of Current Job",
39 | "Second Duty of Current Job",
40 | "Third Duty of Current Job"
41 | ]
42 | },
43 | {
44 | "company": "Previous Job",
45 | "position": "Position Two",
46 | "url": "https://sample.com",
47 | "start_date": "01/01/2010",
48 | "end_date": "01/01/2020",
49 | "summary": "Short summary about previous job and what that position entailed",
50 | "highlights": [
51 | "First Duty of Previous Job",
52 | "Second Duty of Previous Job",
53 | "Third Duty of Previous Job"
54 | ]
55 | }
56 | ],
57 | "projects": [
58 | {
59 | "title": "My First Project",
60 | "summary": "Short summary about my first project",
61 | "url": "https://sample.com",
62 | "highlights": [
63 | "First Highlight of Project One",
64 | "Second Highlight of Project One",
65 | "Third Highlight of Project One"
66 | ],
67 | "images": [
68 | {
69 | "img_path": "https://picsum.photos/600/338?random=1",
70 | "caption": "Image Caption 1"
71 | },
72 | {
73 | "img_path": "https://picsum.photos/600/338?random=2",
74 | "caption": "Image Caption 2"
75 | },
76 | {
77 | "img_path": "https://picsum.photos/600/338?random=3",
78 | "caption": "Image Caption 3"
79 | }
80 | ]
81 | },
82 | {
83 | "title": "My Second Project",
84 | "summary": "Short summary about my second project",
85 | "url": "https://sample.com",
86 | "highlights": [
87 | "First Highlight of Project Two",
88 | "Second Highlight of Project Two",
89 | "Third Highlight of Project Two"
90 | ],
91 | "images": [
92 | {
93 | "img_path": "https://picsum.photos/600/338?random=4",
94 | "caption": "Image Caption 4"
95 | },
96 | {
97 | "img_path": "https://picsum.photos/600/338?random=5",
98 | "caption": "Image Caption 5"
99 | },
100 | {
101 | "img_path": "https://picsum.photos/600/338?random=6",
102 | "caption": "Image Caption 6"
103 | }
104 | ]
105 | }
106 | ],
107 | "volunteer_experience": [
108 | {
109 | "organization": "Latest Organization",
110 | "position": "Position One",
111 | "url": "https://sample.com",
112 | "start_date": "01/01/2020",
113 | "end_date": "Present",
114 | "summary": "Short summary about present volunteer work",
115 | "highlights": [
116 | "First Duty of Current Organization",
117 | "Second Duty of Current Organization",
118 | "Third Duty of Current Organization"
119 | ]
120 | },
121 | {
122 | "organization": "Previous Organization",
123 | "position": "Position Two",
124 | "url": "https://sample.com",
125 | "start_date": "01/01/2010",
126 | "end_date": "01/01/2020",
127 | "summary": "Short summary about previous volunteer work",
128 | "highlights": [
129 | "First Duty of Previous Organization",
130 | "Second Duty of Previous Organization",
131 | "Third Duty of Previous Organization"
132 | ]
133 | }
134 | ],
135 | "education": [
136 | {
137 | "institution": "Institution One",
138 | "location": "Institution One Location",
139 | "url": "https://sample.com",
140 | "degrees": [
141 | "Master of Science in Computer Science",
142 | "Minor in Mathematics"
143 | ],
144 | "honors": ["Outstanding Student Award", "Dean's List"],
145 | "gpa_cumulative": "3.5",
146 | "gpa_major": "4.0",
147 | "graduation_date": "01/01/2005"
148 | },
149 | {
150 | "institution": "Institution Two",
151 | "location": "Institution Two Location",
152 | "url": "https://sample.com",
153 | "degrees": ["Bachelor of Science in Physics"],
154 | "honors": ["Scholarship Recipient"],
155 | "gpa_cumulative": "3.2",
156 | "gpa_major": "3.9",
157 | "graduation_date": "01/01/2000"
158 | }
159 | ],
160 | "skills": [
161 | {
162 | "name": "My First Skill",
163 | "proficiency": 100,
164 | "proficiency_label": "Proficiency Level"
165 | },
166 | {
167 | "name": "My Second Skill",
168 | "proficiency": 80,
169 | "proficiency_label": "Proficiency Level"
170 | }
171 | ],
172 | "interests": [
173 | {
174 | "name": "My First Hobby",
175 | "summary": "Short summary about my first Hobby",
176 | "images": [
177 | {
178 | "img_path": "https://picsum.photos/600/338?random=7",
179 | "caption": "Image Caption 7"
180 | },
181 | {
182 | "img_path": "https://picsum.photos/600/338?random=8",
183 | "caption": "Image Caption 8"
184 | }
185 | ]
186 | },
187 | {
188 | "name": "My Second Hobby",
189 | "summary": "Short summary about my second hobby",
190 | "images": [
191 | {
192 | "img_path": "https://picsum.photos/600/338?random=9",
193 | "caption": "Image Caption 9"
194 | },
195 | {
196 | "img_path": "https://picsum.photos/600/338?random=10",
197 | "caption": "Image Caption 10"
198 | }
199 | ]
200 | }
201 | ],
202 | "languages": [
203 | {
204 | "language": "English",
205 | "fluency": "Native speaker"
206 | },
207 | {
208 | "language": "American Sign Language",
209 | "fluency": "Professional Working Proficiency"
210 | }
211 | ],
212 | "references": [
213 | {
214 | "name": "Person One",
215 | "relation": "Previous Boss",
216 | "reference": "Some nice things that Person One said about you, your work ethic, and how you provided value to their team."
217 | },
218 | {
219 | "name": "Person Two",
220 | "relation": "Previous Coworker",
221 | "reference": "More kind things that Person Two said about you, what it was like working with you, and things you've accomplished."
222 | }
223 | ]
224 | }
225 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Created by https://www.toptal.com/developers/gitignore/api/macos,python,node
2 | # Edit at https://www.toptal.com/developers/gitignore?templates=macos,python,node
3 |
4 | # Personal
5 | Script.gdoc
6 | TODO.txt
7 |
8 | ### macOS ###
9 | # General
10 | .DS_Store
11 | .AppleDouble
12 | .LSOverride
13 |
14 | # Icon must end with two \r
15 | Icon
16 |
17 |
18 | # Thumbnails
19 | ._*
20 |
21 | # Files that might appear in the root of a volume
22 | .DocumentRevisions-V100
23 | .fseventsd
24 | .Spotlight-V100
25 | .TemporaryItems
26 | .Trashes
27 | .VolumeIcon.icns
28 | .com.apple.timemachine.donotpresent
29 |
30 | # Directories potentially created on remote AFP share
31 | .AppleDB
32 | .AppleDesktop
33 | Network Trash Folder
34 | Temporary Items
35 | .apdisk
36 |
37 | ### macOS Patch ###
38 | # iCloud generated files
39 | *.icloud
40 |
41 | ### Node ###
42 | # Logs
43 | logs
44 | *.log
45 | npm-debug.log*
46 | yarn-debug.log*
47 | yarn-error.log*
48 | lerna-debug.log*
49 | .pnpm-debug.log*
50 |
51 | # Diagnostic reports (https://nodejs.org/api/report.html)
52 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
53 |
54 | # Runtime data
55 | pids
56 | *.pid
57 | *.seed
58 | *.pid.lock
59 |
60 | # Directory for instrumented libs generated by jscoverage/JSCover
61 | lib-cov
62 |
63 | # Coverage directory used by tools like istanbul
64 | coverage
65 | *.lcov
66 |
67 | # nyc test coverage
68 | .nyc_output
69 |
70 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
71 | .grunt
72 |
73 | # Bower dependency directory (https://bower.io/)
74 | bower_components
75 |
76 | # node-waf configuration
77 | .lock-wscript
78 |
79 | # Compiled binary addons (https://nodejs.org/api/addons.html)
80 | build/Release
81 |
82 | # Dependency directories
83 | node_modules/
84 | jspm_packages/
85 |
86 | # Snowpack dependency directory (https://snowpack.dev/)
87 | web_modules/
88 |
89 | # TypeScript cache
90 | *.tsbuildinfo
91 |
92 | # Optional npm cache directory
93 | .npm
94 |
95 | # Optional eslint cache
96 | .eslintcache
97 |
98 | # Optional stylelint cache
99 | .stylelintcache
100 |
101 | # Microbundle cache
102 | .rpt2_cache/
103 | .rts2_cache_cjs/
104 | .rts2_cache_es/
105 | .rts2_cache_umd/
106 |
107 | # Optional REPL history
108 | .node_repl_history
109 |
110 | # Output of 'npm pack'
111 | *.tgz
112 |
113 | # Yarn Integrity file
114 | .yarn-integrity
115 |
116 | # dotenv environment variable files
117 | .env
118 | .env.development.local
119 | .env.test.local
120 | .env.production.local
121 | .env.local
122 |
123 | # parcel-bundler cache (https://parceljs.org/)
124 | .cache
125 | .parcel-cache
126 |
127 | # Next.js build output
128 | .next
129 | out
130 |
131 | # Nuxt.js build / generate output
132 | .nuxt
133 | dist
134 |
135 | # Gatsby files
136 | .cache/
137 | # Comment in the public line in if your project uses Gatsby and not Next.js
138 | # https://nextjs.org/blog/next-9-1#public-directory-support
139 | # public
140 |
141 | # vuepress build output
142 | .vuepress/dist
143 |
144 | # vuepress v2.x temp and cache directory
145 | .temp
146 |
147 | # Docusaurus cache and generated files
148 | .docusaurus
149 |
150 | # Serverless directories
151 | .serverless/
152 |
153 | # FuseBox cache
154 | .fusebox/
155 |
156 | # DynamoDB Local files
157 | .dynamodb/
158 |
159 | # TernJS port file
160 | .tern-port
161 |
162 | # Stores VSCode versions used for testing VSCode extensions
163 | .vscode-test
164 |
165 | # yarn v2
166 | .yarn/cache
167 | .yarn/unplugged
168 | .yarn/build-state.yml
169 | .yarn/install-state.gz
170 | .pnp.*
171 |
172 | ### Node Patch ###
173 | # Serverless Webpack directories
174 | .webpack/
175 |
176 | # Optional stylelint cache
177 |
178 | # SvelteKit build / generate output
179 | .svelte-kit
180 |
181 | ### Python ###
182 | # Byte-compiled / optimized / DLL files
183 | __pycache__/
184 | *.py[cod]
185 | *$py.class
186 |
187 | # C extensions
188 | *.so
189 |
190 | # Distribution / packaging
191 | .Python
192 | build/
193 | develop-eggs/
194 | dist/
195 | downloads/
196 | eggs/
197 | .eggs/
198 | lib/
199 | lib64/
200 | parts/
201 | sdist/
202 | var/
203 | wheels/
204 | share/python-wheels/
205 | *.egg-info/
206 | .installed.cfg
207 | *.egg
208 | MANIFEST
209 |
210 | # PyInstaller
211 | # Usually these files are written by a python script from a template
212 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
213 | *.manifest
214 | *.spec
215 |
216 | # Installer logs
217 | pip-log.txt
218 | pip-delete-this-directory.txt
219 |
220 | # Unit test / coverage reports
221 | htmlcov/
222 | .tox/
223 | .nox/
224 | .coverage
225 | .coverage.*
226 | nosetests.xml
227 | coverage.xml
228 | *.cover
229 | *.py,cover
230 | .hypothesis/
231 | .pytest_cache/
232 | cover/
233 |
234 | # Translations
235 | *.mo
236 | *.pot
237 |
238 | # Django stuff:
239 | local_settings.py
240 | db.sqlite3
241 | db.sqlite3-journal
242 |
243 | # Flask stuff:
244 | instance/
245 | .webassets-cache
246 |
247 | # Scrapy stuff:
248 | .scrapy
249 |
250 | # Sphinx documentation
251 | docs/_build/
252 |
253 | # PyBuilder
254 | .pybuilder/
255 | target/
256 |
257 | # Jupyter Notebook
258 | .ipynb_checkpoints
259 |
260 | # IPython
261 | profile_default/
262 | ipython_config.py
263 |
264 | # pyenv
265 | # For a library or package, you might want to ignore these files since the code is
266 | # intended to run in multiple environments; otherwise, check them in:
267 | # .python-version
268 |
269 | # pipenv
270 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
271 | # However, in case of collaboration, if having platform-specific dependencies or dependencies
272 | # having no cross-platform support, pipenv may install dependencies that don't work, or not
273 | # install all needed dependencies.
274 | #Pipfile.lock
275 |
276 | # poetry
277 | # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
278 | # This is especially recommended for binary packages to ensure reproducibility, and is more
279 | # commonly ignored for libraries.
280 | # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
281 | #poetry.lock
282 |
283 | # pdm
284 | # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
285 | #pdm.lock
286 | # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
287 | # in version control.
288 | # https://pdm.fming.dev/#use-with-ide
289 | .pdm.toml
290 |
291 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
292 | __pypackages__/
293 |
294 | # Celery stuff
295 | celerybeat-schedule
296 | celerybeat.pid
297 |
298 | # SageMath parsed files
299 | *.sage.py
300 |
301 | # Environments
302 | .venv
303 | env/
304 | venv/
305 | ENV/
306 | env.bak/
307 | venv.bak/
308 |
309 | # Spyder project settings
310 | .spyderproject
311 | .spyproject
312 |
313 | # Rope project settings
314 | .ropeproject
315 |
316 | # mkdocs documentation
317 | /site
318 |
319 | # mypy
320 | .mypy_cache/
321 | .dmypy.json
322 | dmypy.json
323 |
324 | # Pyre type checker
325 | .pyre/
326 |
327 | # pytype static type analyzer
328 | .pytype/
329 |
330 | # Cython debug symbols
331 | cython_debug/
332 |
333 | # PyCharm
334 | # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
335 | # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
336 | # and can be added to the global gitignore or merged into this file. For a more nuclear
337 | # option (not recommended) you can uncomment the following to ignore the entire idea folder.
338 | #.idea/
339 |
340 | ### Python Patch ###
341 | # Poetry local configuration file - https://python-poetry.org/docs/configuration/#local-configuration
342 | poetry.toml
343 |
344 | # ruff
345 | .ruff_cache/
346 |
347 | # LSP config files
348 | pyrightconfig.json
349 |
350 | # End of https://www.toptal.com/developers/gitignore/api/macos,python,node
--------------------------------------------------------------------------------
/resume_template.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | {{ name }} - Resume
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
86 |
87 |
88 |
89 |
90 | {% if work_experience %}
91 |
92 | Work Experience
93 | {% for job in work_experience %}
94 |
95 |
96 | {% if job.url %}
97 | {{ job.position }} at {{ job.company }}
98 | {% else %}
99 | {{ job.position }} at {{ job.company }}
100 | {% endif %}
101 |
102 | {% if job.start_date and job.end_date %}
103 | {{ job.start_date }} - {{ job.end_date }}
104 | {% endif %}
105 | {% if job.summary %}{{ job.summary }}
{% endif %}
106 | {% if job.highlights %}
107 |
108 | {% for highlight in job.highlights %}- {{ highlight }}
{% endfor %}
109 |
110 | {% endif %}
111 |
112 | {% endfor %}
113 |
114 | {% endif %}
115 |
116 | {% if projects %}
117 |
118 | Projects
119 | {% for project in projects %}
120 |
121 |
122 | {% if project.url %}
123 | {{ project.title }}
124 | {% else %}
125 | {{ project.title }}
126 | {% endif %}
127 |
128 | {% if project.summary %}{{ project.summary }}
{% endif %}
129 | {% if project.highlights %}
130 |
131 | {% for highlight in project.highlights %}- {{ highlight }}
{% endfor %}
132 |
133 | {% endif %}
134 |
135 | {% endfor %}
136 |
137 | {% endif %}
138 |
139 |
140 |
141 |
182 |
183 |
184 |
185 |
186 |
187 |
--------------------------------------------------------------------------------
/css/main.css:
--------------------------------------------------------------------------------
1 | :root {
2 | --link-color: #0077cc;
3 | --link-color-hover: #00487c;
4 | --header-footer-bg-color: #f0f0f0;
5 | --aside-accent-color: #9d836b;
6 | --skill-bar-fill-color: #f3e4c6;
7 | --blockquote-bg-color: #f7fafc;
8 | --blockquote-accent-color: #4a5568;
9 | --blockquote-text-color: #4a5568;
10 | --spacing-inline: 0.5rem;
11 | }
12 |
13 | /* Base Styles */
14 | body {
15 | font-family: "Nunito", "Segoe UI", "Helvetica Neue", Helvetica, Arial,
16 | sans-serif;
17 | font-weight: 400;
18 | display: grid;
19 | grid-template-rows: auto 1fr auto;
20 | min-height: 100vh;
21 | }
22 |
23 | h1,
24 | h2,
25 | h3,
26 | h4,
27 | h5,
28 | h6 {
29 | margin: 0;
30 | font-family: "Montserrat", "Segoe UI", "Helvetica Neue", Helvetica, Arial,
31 | sans-serif;
32 | font-weight: 400;
33 | line-height: 1.2;
34 | }
35 |
36 | h1 {
37 | font-size: 2rem;
38 | font-weight: 600;
39 | text-transform: uppercase;
40 | }
41 |
42 | h2 {
43 | font-size: 1.4rem;
44 | font-weight: 500;
45 | text-transform: uppercase;
46 | }
47 |
48 | h3 {
49 | font-size: 1.1rem;
50 | font-weight: 500;
51 | }
52 |
53 | h4 {
54 | font-size: 1rem;
55 | font-weight: 500;
56 | }
57 |
58 | h5 {
59 | font-size: 1rem;
60 | font-weight: 500;
61 | }
62 |
63 | h6 {
64 | font-size: 1rem;
65 | font-weight: 500;
66 | }
67 |
68 | p {
69 | margin: 0.75rem 0;
70 | }
71 |
72 | a {
73 | color: var(--link-color) !important;
74 | text-decoration: none;
75 | }
76 |
77 | a:hover {
78 | color: var(--link-color-hover);
79 | text-decoration: underline;
80 | }
81 |
82 | address {
83 | font-style: normal;
84 | }
85 |
86 | figure,
87 | ul {
88 | margin: 0;
89 | padding: 0;
90 | }
91 |
92 | header,
93 | main,
94 | aside,
95 | footer {
96 | padding: 2rem;
97 | }
98 |
99 | header {
100 | padding-bottom: 0.5rem;
101 | }
102 |
103 | aside {
104 | border-top: 1px solid #ccc;
105 | }
106 |
107 | footer {
108 | text-align: center;
109 | }
110 |
111 | section {
112 | margin-bottom: 1.5rem;
113 | }
114 |
115 | /* Utility */
116 | .block {
117 | display: block;
118 | margin: 0.25rem 0;
119 | }
120 |
121 | .flex-responsive {
122 | display: flex;
123 | flex-direction: column;
124 | align-items: center;
125 | text-align: center;
126 | }
127 |
128 | /* Main Layout */
129 | .container {
130 | width: 100%;
131 | max-width: 1200px;
132 | margin: 0 auto;
133 | }
134 |
135 | .page-content .container {
136 | display: grid;
137 | grid-template-columns: 1fr;
138 | }
139 |
140 | .page-header,
141 | .page-footer {
142 | background: var(--header-footer-bg-color);
143 | }
144 |
145 | .page-header {
146 | border-bottom: 1px solid #ccc;
147 | }
148 |
149 | .page-header .container {
150 | display: flex;
151 | flex-direction: column;
152 | }
153 |
154 | .header-top {
155 | gap: 1rem;
156 | }
157 |
158 | .header-image {
159 | width: 100%;
160 | max-width: 256px;
161 | aspect-ratio: 1 / 1;
162 | border-radius: 50%;
163 | object-fit: cover;
164 | border: 1px solid #999;
165 | }
166 |
167 | .header-info ul {
168 | margin: 1rem 0;
169 | }
170 |
171 | .link-with-icon {
172 | display: flex;
173 | align-items: center;
174 | gap: 0.25rem;
175 | }
176 |
177 | .header-label {
178 | font-size: 1.3rem;
179 | color: #444;
180 | margin-top: 0.2rem;
181 | margin-bottom: 0.8rem;
182 | }
183 |
184 | .header-summary {
185 | margin: 1.25rem 0;
186 | }
187 |
188 | .page-footer {
189 | border-top: 1px solid #ccc;
190 | }
191 |
192 | .section-heading {
193 | display: flex;
194 | align-items: center;
195 | text-align: center;
196 | margin-bottom: 1rem;
197 | }
198 |
199 | .section-heading::before,
200 | .section-heading::after {
201 | content: "";
202 | flex: 1;
203 | border-bottom: 1px solid #ccc;
204 | margin: 0 1rem;
205 | }
206 |
207 | aside .section-heading {
208 | align-items: flex-start;
209 | text-align: left;
210 | border-left: 4px solid var(--aside-accent-color);
211 | padding-left: 0.5rem;
212 | margin-bottom: 0.75rem;
213 | }
214 |
215 | aside .section-heading::before,
216 | aside .section-heading::after {
217 | content: none;
218 | }
219 |
220 | .section-label {
221 | font-size: 0.9rem;
222 | color: #444;
223 | margin-top: 0.25rem;
224 | margin-bottom: 0.5rem;
225 | }
226 |
227 | /* Images */
228 | img {
229 | max-width: 100%;
230 | height: auto;
231 | }
232 |
233 | .gallery {
234 | display: grid;
235 | gap: 1rem;
236 | justify-items: center;
237 | margin: 0.5rem 0;
238 | }
239 |
240 | .main-gallery {
241 | grid-template-columns: 1fr;
242 | }
243 |
244 | .side-gallery {
245 | grid-template-columns: 1fr;
246 | }
247 |
248 | figcaption {
249 | text-align: center;
250 | color: #666;
251 | font-size: 0.9rem;
252 | margin-top: 0.5rem;
253 | font-style: italic;
254 | }
255 |
256 | /* Lists */
257 | main ul,
258 | aside ul {
259 | list-style-type: disc;
260 | list-style-position: inside;
261 | padding-left: 0;
262 | margin: 0.75rem 0;
263 | }
264 |
265 | main li,
266 | aside li {
267 | margin-bottom: 0.5rem;
268 | }
269 |
270 | .unstyled-list {
271 | list-style: none;
272 | }
273 |
274 | .inline-list {
275 | list-style: none;
276 | gap: 0.25rem;
277 | }
278 |
279 | .inline-list li {
280 | display: flex; /* This is for HTML Whitespace Issues */
281 | }
282 |
283 | /* Skillbars */
284 | .skill-bar {
285 | width: 100%;
286 | height: 1.5rem;
287 | margin-top: 0.25rem;
288 | margin-bottom: 1rem;
289 | background: #eee;
290 | border: 1px solid #848484;
291 | border-radius: 2px;
292 | overflow: hidden;
293 | }
294 |
295 | .skill-bar-fill {
296 | height: 100%;
297 | background: var(--skill-bar-fill-color) !important;
298 | border-right: 1px solid #848484;
299 | border-radius: 2px;
300 | display: flex;
301 | align-items: center;
302 | padding-left: 0.5rem;
303 | }
304 |
305 | .skill-bar-label {
306 | color: #333;
307 | font-size: 0.9rem;
308 | white-space: nowrap;
309 | }
310 |
311 | .w-0 {
312 | width: 0%;
313 | }
314 |
315 | .w-10 {
316 | width: 10%;
317 | }
318 |
319 | .w-20 {
320 | width: 20%;
321 | }
322 |
323 | .w-25 {
324 | width: 25%;
325 | }
326 |
327 | .w-30 {
328 | width: 30%;
329 | }
330 |
331 | .w-40 {
332 | width: 40%;
333 | }
334 |
335 | .w-50 {
336 | width: 50%;
337 | }
338 |
339 | .w-60 {
340 | width: 60%;
341 | }
342 |
343 | .w-70 {
344 | width: 70%;
345 | }
346 |
347 | .w-75 {
348 | width: 75%;
349 | }
350 |
351 | .w-80 {
352 | width: 80%;
353 | }
354 |
355 | .w-90 {
356 | width: 90%;
357 | }
358 |
359 | .w-100 {
360 | width: 100%;
361 | border-right: none;
362 | }
363 |
364 | /* Blockquotes */
365 | blockquote {
366 | margin: 1rem 2rem;
367 | padding: 1.5rem 2rem;
368 | background-color: var(--blockquote-bg-color);
369 | border-left: 4px solid var(--blockquote-accent-color);
370 | font-style: italic;
371 | color: var(--blockquote-text-color);
372 | line-height: 1.6;
373 | border-radius: 0 4px 4px 0;
374 | box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
375 | }
376 |
377 | @media (min-width: 37.5rem) {
378 | .main-gallery {
379 | grid-template-columns: repeat(3, 1fr);
380 | }
381 |
382 | .side-gallery {
383 | grid-template-columns: repeat(2, 1fr);
384 | }
385 | }
386 |
387 | @media (min-width: 48rem) {
388 | aside {
389 | border-top: none;
390 | border-left: 1px solid #ccc;
391 | }
392 |
393 | aside h1 {
394 | font-size: 1.4rem;
395 | }
396 |
397 | aside h2 {
398 | font-size: 1.1rem;
399 | }
400 |
401 | aside h3 {
402 | font-size: 1rem;
403 | }
404 |
405 | aside h4 {
406 | font-size: 1rem;
407 | }
408 |
409 | aside h5 {
410 | font-size: 1rem;
411 | }
412 |
413 | aside h6 {
414 | font-size: 1rem;
415 | }
416 |
417 | header {
418 | padding-bottom: 1.5rem;
419 | }
420 |
421 | .flex-responsive {
422 | flex-direction: row;
423 | align-items: flex-start;
424 | text-align: left;
425 | }
426 |
427 | .page-content .container {
428 | grid-template-columns: 2fr 1fr;
429 | }
430 |
431 | .header-top {
432 | gap: 2rem;
433 | }
434 |
435 | .header-image {
436 | max-width: 192px;
437 | }
438 |
439 | .header-info {
440 | margin-top: 0.5rem;
441 | }
442 |
443 | .page-header ul {
444 | margin: 0.5rem 0;
445 | }
446 |
447 | .inline-list {
448 | gap: var(--spacing-inline);
449 | }
450 |
451 | .inline-list li:not(:last-child)::after {
452 | content: "|";
453 | margin-left: var(--spacing-inline);
454 | color: #ccc;
455 | }
456 |
457 | .side-gallery {
458 | grid-template-columns: 1fr;
459 | }
460 | }
461 |
462 | @media print {
463 | .skill-bar-label {
464 | background: transparent !important;
465 | background-color: transparent !important;
466 | mix-blend-mode: darken;
467 | }
468 |
469 | body {
470 | -webkit-print-color-adjust: exact !important;
471 | print-color-adjust: exact !important;
472 | }
473 | }
474 |
--------------------------------------------------------------------------------
/resume.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Your Name - Resume
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
86 |
87 |
88 |
89 |
90 |
91 |
92 | Work Experience
93 |
94 |
95 |
96 |
97 | Position One at Latest Job
98 |
99 |
100 |
101 | 01/01/2020 - Present
102 |
103 | Short summary about present job and what the position entails
104 |
105 |
106 | - First Duty of Current Job
- Second Duty of Current Job
- Third Duty of Current Job
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 | Position Two at Previous Job
115 |
116 |
117 |
118 | 01/01/2010 - 01/01/2020
119 |
120 | Short summary about previous job and what that position entailed
121 |
122 |
123 | - First Duty of Previous Job
- Second Duty of Previous Job
- Third Duty of Previous Job
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 | Projects
134 |
135 |
136 |
141 | Short summary about my first project
142 |
143 |
144 | - First Highlight of Project One
- Second Highlight of Project One
- Third Highlight of Project One
145 |
146 |
147 |
148 |
149 |
150 |
155 | Short summary about my second project
156 |
157 |
158 | - First Highlight of Project Two
- Second Highlight of Project Two
- Third Highlight of Project Two
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
229 |
230 |
231 |
232 |
233 |
--------------------------------------------------------------------------------
/index_template.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | {{ name }} - Portfolio
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
108 |
109 |
110 |
111 |
112 | {% if work_experience %}
113 |
114 | Work Experience
115 | {% for job in work_experience %}
116 |
117 |
118 | {% if job.url %}
119 | {{ job.position }} at {{ job.company }}
120 | {% else %}
121 | {{ job.position }} at {{ job.company }}
122 | {% endif %}
123 |
124 | {% if job.start_date and job.end_date %}
125 | {{ job.start_date }} - {{ job.end_date }}
126 | {% endif %}
127 | {% if job.summary %}{{ job.summary }}
{% endif %}
128 | {% if job.highlights %}
129 |
130 | {% for highlight in job.highlights %}- {{ highlight }}
{% endfor %}
131 |
132 | {% endif %}
133 |
134 | {% endfor %}
135 |
136 | {% endif %}
137 |
138 | {% if projects %}
139 |
140 | Projects
141 | {% for project in projects %}
142 |
143 |
144 | {% if project.url %}
145 | {{ project.title }}
146 | {% else %}
147 | {{ project.title }}
148 | {% endif %}
149 |
150 | {% if project.summary %}{{ project.summary }}
{% endif %}
151 | {% if project.highlights %}
152 |
153 | {% for highlight in project.highlights %}- {{ highlight }}
{% endfor %}
154 |
155 | {% endif %}
156 | {% if project.images %}
157 |
158 | {% for img in project.images %}
159 |
160 |
164 | {{ img.caption }}
165 |
166 | {% endfor %}
167 |
168 | {% endif %}
169 |
170 | {% endfor %}
171 |
172 | {% endif %}
173 |
174 | {% if volunteer_experience %}
175 |
176 | Volunteer Experience
177 | {% for vol in volunteer_experience %}
178 |
179 |
180 | {% if vol.url %}
181 | {{ vol.position }} at {{ vol.organization }}
182 | {% else %}
183 | {{ vol.position }} at {{ vol.organization }}
184 | {% endif %}
185 |
186 | {% if vol.start_date and vol.end_date %}
187 | {{ vol.start_date }} - {{ vol.end_date }}
188 | {% endif %}
189 | {% if vol.summary %}{{ vol.summary }}
{% endif %}
190 | {% if vol.highlights %}
191 |
192 | {% for highlight in vol.highlights %}- {{ highlight }}
{% endfor %}
193 |
194 | {% endif %}
195 |
196 | {% endfor %}
197 |
198 | {% endif %}
199 |
200 | {% if references %}
201 |
202 | References
203 | {% for ref in references %}
204 |
205 | {% if ref.name %}{{ ref.name }}
{% endif %}
206 | {% if ref.relation %}{{ ref.relation }}
{% endif %}
207 | {% if ref.reference %}
208 |
209 | {{ ref.reference }}
210 |
211 | {% endif %}
212 |
213 | {% endfor %}
214 |
215 | {% endif %}
216 |
217 |
218 |
219 |
318 |
319 |
320 |
321 |
326 |
327 |
328 |
329 |
330 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Your Name - Portfolio
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
158 |
159 |
160 |
161 |
162 |
163 |
164 | Work Experience
165 |
166 |
167 |
168 |
169 | Position One at Latest Job
170 |
171 |
172 |
173 | 01/01/2020 - Present
174 |
175 | Short summary about present job and what the position entails
176 |
177 |
178 | - First Duty of Current Job
- Second Duty of Current Job
- Third Duty of Current Job
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 | Position Two at Previous Job
187 |
188 |
189 |
190 | 01/01/2010 - 01/01/2020
191 |
192 | Short summary about previous job and what that position entailed
193 |
194 |
195 | - First Duty of Previous Job
- Second Duty of Previous Job
- Third Duty of Previous Job
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 | Projects
206 |
207 |
208 |
213 | Short summary about my first project
214 |
215 |
216 | - First Highlight of Project One
- Second Highlight of Project One
- Third Highlight of Project One
217 |
218 |
219 |
220 |
221 |
222 |
223 |
227 | Image Caption 1
228 |
229 |
230 |
231 |
235 | Image Caption 2
236 |
237 |
238 |
239 |
243 | Image Caption 3
244 |
245 |
246 |
247 |
248 |
249 |
250 |
251 |
256 | Short summary about my second project
257 |
258 |
259 | - First Highlight of Project Two
- Second Highlight of Project Two
- Third Highlight of Project Two
260 |
261 |
262 |
263 |
264 |
265 |
266 |
270 | Image Caption 4
271 |
272 |
273 |
274 |
278 | Image Caption 5
279 |
280 |
281 |
282 |
286 | Image Caption 6
287 |
288 |
289 |
290 |
291 |
292 |
293 |
294 |
295 |
296 |
297 |
298 | Volunteer Experience
299 |
300 |
301 |
302 |
303 | Position One at Latest Organization
304 |
305 |
306 |
307 | 01/01/2020 - Present
308 |
309 | Short summary about present volunteer work
310 |
311 |
312 | - First Duty of Current Organization
- Second Duty of Current Organization
- Third Duty of Current Organization
313 |
314 |
315 |
316 |
317 |
318 |
323 |
324 | 01/01/2010 - 01/01/2020
325 |
326 | Short summary about previous volunteer work
327 |
328 |
329 | - First Duty of Previous Organization
- Second Duty of Previous Organization
- Third Duty of Previous Organization
330 |
331 |
332 |
333 |
334 |
335 |
336 |
337 |
338 |
339 | References
340 |
341 |
342 | Person One
343 | Previous Boss
344 |
345 |
346 | Some nice things that Person One said about you, your work ethic, and how you provided value to their team.
347 |
348 |
349 |
350 |
351 |
352 | Person Two
353 | Previous Coworker
354 |
355 |
356 | More kind things that Person Two said about you, what it was like working with you, and things you've accomplished.
357 |
358 |
359 |
360 |
361 |
362 |
363 |
364 |
365 |
366 |
543 |
544 |
545 |
546 |
551 |
552 |
553 |
554 |
--------------------------------------------------------------------------------