├── 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 | 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 | 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 | 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 |

137 | 138 | My First Project 139 | 140 |

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 |

151 | 152 | My Second Project 153 | 154 |

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 | 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 | 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 | 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 %}{% 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 | 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 | 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 |

209 | 210 | My First Project 211 | 212 |

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 | 247 | 248 |
249 | 250 |
251 |

252 | 253 | My Second Project 254 | 255 |

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 | 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 | 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 |

319 | 320 | Position Two at Previous Organization 321 | 322 |

323 | 324 | 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 | 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 | 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 | --------------------------------------------------------------------------------