├── .editorconfig ├── .github └── workflows │ ├── pulls.yml │ └── release.yml ├── .gitignore ├── .npmignore ├── LICENSE ├── README.md ├── assets └── preview.png ├── index.js ├── package-lock.json ├── package.json ├── resume.handlebars ├── style.css └── test └── fixture.resume.json /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 2 6 | end_of_line = lf 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | curly_bracket_next_line = false 11 | spaces_around_operators = true 12 | 13 | [*.bat] 14 | end_of_line = crlf 15 | 16 | [*.cs] 17 | curly_bracket_next_line = true 18 | 19 | [*.{cpp,cs,gradle,java,kt,py,rs}] 20 | indent_size = 4 21 | 22 | [*.{js,ts}] 23 | quote_type = single 24 | 25 | [*.{markdown,md}] 26 | trim_trailing_whitespace = false 27 | 28 | [*.tsv] 29 | indent_style = tab 30 | -------------------------------------------------------------------------------- /.github/workflows/pulls.yml: -------------------------------------------------------------------------------- 1 | name: Test Run 2 | 3 | on: 4 | pull_request: 5 | branches: 6 | - main 7 | 8 | permissions: 9 | contents: read 10 | 11 | jobs: 12 | build: 13 | runs-on: ubuntu-latest 14 | steps: 15 | - uses: actions/checkout@v4 16 | - uses: actions/setup-node@v3 17 | with: 18 | node-version: 20 19 | - run: npm ci 20 | - run: npx resume export --theme . --resume ./test/fixture.resume.json /tmp/resume.html 21 | - run: npx resume export --theme . --resume ./test/fixture.resume.json /tmp/resume.pdf 22 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Node.js Package 2 | 3 | on: 4 | release: 5 | types: [created] 6 | 7 | jobs: 8 | publish-npm: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@v4 12 | - uses: actions/setup-node@v3 13 | with: 14 | node-version: 20 15 | registry-url: https://registry.npmjs.org/ 16 | - run: npm publish --access public 17 | env: 18 | NODE_AUTH_TOKEN: ${{secrets.npm_token}} 19 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | npm-debug.log 3 | resume.json 4 | *.pdf 5 | *.html 6 | 7 | .vscode/ 8 | *.code-workspace 9 | .history/ 10 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .github/ 2 | assets/ 3 | test/ 4 | .editorconfig 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014-2014 James Spencer 4 | Copyright (c) 2022-2023 JSON Resume and Contributors 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Class Theme for JSON Resume 2 | 3 | [![matrix](https://img.shields.io/badge/matrix-join%20chat-%230dbd8b)](https://matrix.to/#/#json-resume:one.ems.host) 4 | [![npm package](https://img.shields.io/npm/v/@jsonresume/jsonresume-theme-class)](https://www.npmjs.com/package/@jsonresume/jsonresume-theme-class) 5 | 6 | A modern theme for [JSON Resume](http://jsonresume.org/) which is self-contained. The content of the résumé will work offline and can be hosted without depending on or making requests to third-party servers. 7 | 8 | ## Usage 9 | 10 | ```sh 11 | # Install resume-cli via npm, yarn, pnpm, or whatever package manager you want 12 | npm install --global resume-cli 13 | 14 | # Install @jsonresume/jsonresume-theme-class in the directory resume.json is in 15 | npm install @jsonresume/jsonresume-theme-class 16 | 17 | # Export as an HTML page, ready to be served by any web server 18 | resume export --theme @jsonresume/jsonresume-theme-class index.html 19 | 20 | # Export a PDF document, it's recommended to use your name as the file name 21 | resume export --theme @jsonresume/jsonresume-theme-class your-name.pdf 22 | ``` 23 | 24 | ### Notes 25 | 26 | * It's recommended to declare the `meta.language` property in your JSON Resume for accessibility. This is the [BCP47 tag](https://developer.mozilla.org/docs/Web/HTML/Global_attributes/lang#language_tag_syntax) for the language your your résumé is written in. For example, `en` for English. 27 | 28 | ## Features 29 | 30 | ### JSON Resume 1.0.0 31 | 32 | This supports the JSON Resume 1.0.0 spec, and is backward compatible with earlier versions. 33 | 34 | ### Application Tracking System (ATS) Friendly 35 | 36 | Many companies and recruiters use [ATS](https://en.wikipedia.org/wiki/Applicant_tracking_system) systems that [parse CV's](https://en.wikipedia.org/wiki/R%C3%A9sum%C3%A9_parsing) and extract the information into a standard format. Part of maintaining this theme includes reviewing this and adhering to standard practices when building the résumé. 37 | 38 | ### Markdown 39 | 40 | You can use inline Markdown on properties to make text bold, italic, or link them to external pages. This namely applies to the `summary` and `highlights` properties in the JSON Resume schema. 41 | 42 | ### Open Graph Protocol 43 | 44 | Populates the `head` of the HTML document with [Open Graph](https://ogp.me/) tags. This allows social media platforms and instant messengers to create embeds when your résumé is shared. 45 | 46 | ### Dark Mode 47 | 48 | Includes a dark mode, and uses the [`prefers-color-scheme`](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-color-scheme) CSS property to provide a positive user-experience. 49 | 50 | ### Optimized 51 | 52 | This theme makes no external connections, doesn't embed scripts, and is lightweight by design. Both HTML and PDF exports will be minimal. 53 | 54 | ## Preview 55 | 56 | ![Preview of Class theme for JSON Resume.](./assets/preview.png) 57 | -------------------------------------------------------------------------------- /assets/preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsonresume/jsonresume-theme-class/b7cc0ad149ab0ecdd08f6916b43eac0ca88b0e62/assets/preview.png -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | const fs = require("fs"); 2 | const Handlebars = require("handlebars"); 3 | const { marked } = require("marked"); 4 | const { minify } = require('html-minifier'); 5 | 6 | /** 7 | * Custom renderer for marked, namely to disable unwanted features. 8 | * We only want to allow basic inline elements, like links, bold, or inline-code. 9 | * 10 | * @type {object} 11 | */ 12 | const renderer = { 13 | heading(text) { 14 | return text; 15 | }, 16 | html(html) { 17 | return html; 18 | }, 19 | hr() { 20 | return ''; 21 | }, 22 | list(body) { 23 | return body; 24 | }, 25 | listitem(text) { 26 | return text; 27 | }, 28 | br() { 29 | return ''; 30 | }, 31 | paragraph(text) { 32 | return text; 33 | } 34 | } 35 | 36 | marked.use({ renderer }); 37 | 38 | /** 39 | * Plugins to enable to minify HTML after generating from the template. 40 | */ 41 | const minifyOptions = { 42 | collapseBooleanAttributes: true, 43 | collapseWhitespace: true, 44 | decodeEntities: true, 45 | minifyCSS: true, 46 | removeComments: true, 47 | removeRedundantAttributes: true, 48 | sortAttributes: true, 49 | sortClassName: true, 50 | }; 51 | 52 | Handlebars.registerHelper("date", (body) => { 53 | if (!body) { 54 | return "Present" 55 | } 56 | 57 | const date = new Date(body); 58 | 59 | const datetime = date.toISOString(); 60 | const localeString = date.toLocaleDateString('en-US', { 61 | month: "short", 62 | year: "numeric" 63 | }); 64 | 65 | return ``; 66 | }); 67 | 68 | Handlebars.registerHelper("markdown", (body) => { 69 | return marked.parse(body); 70 | }); 71 | 72 | Handlebars.registerHelper("link", (body) => { 73 | const parsed = new URL(body); 74 | const host = (parsed.host.startsWith('www.')) ? parsed.host.substring(4) : parsed.host; 75 | return `${host}`; 76 | }); 77 | 78 | /** 79 | * @param {Object} resume 80 | * @returns {string} 81 | */ 82 | function render(resume) { 83 | const css = fs.readFileSync(__dirname + "/style.css", "utf-8"); 84 | const template = fs.readFileSync(__dirname + "/resume.handlebars", "utf-8"); 85 | const { profiles } = resume.basics; 86 | 87 | if (Array.isArray(profiles)) { 88 | const xTwitter = profiles.find((profile) => { 89 | const name = profile.network.toLowerCase(); 90 | return name === 'x' || name === 'twitter'; 91 | }); 92 | 93 | if (xTwitter) { 94 | let { username, url } = xTwitter; 95 | 96 | if (!username && url) { 97 | const match = url.match(/https?:\/\/.+?\/(\w{1,15})/); 98 | 99 | if (match.length == 2) { 100 | username = match[1]; 101 | } 102 | } 103 | 104 | if (username && !username.startsWith('@')) { 105 | username = `@${username}`; 106 | } 107 | 108 | resume.custom = { 109 | xTwitterHandle: username 110 | } 111 | } 112 | } 113 | 114 | const html = Handlebars.compile(template)({ 115 | css, 116 | resume 117 | }); 118 | 119 | return minify(html, minifyOptions); 120 | } 121 | 122 | module.exports = { 123 | render 124 | }; 125 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@jsonresume/jsonresume-theme-class", 3 | "version": "0.4.2", 4 | "description": "Class Theme for JSON Resume", 5 | "author": "Seth Falco", 6 | "license": "MIT", 7 | "private": false, 8 | "keywords": [ 9 | "resume", 10 | "cv", 11 | "handlebars", 12 | "jsonresume", 13 | "jsonresume-theme", 14 | "jsonresume-theme-class" 15 | ], 16 | "repository": { 17 | "type": "git", 18 | "url": "https://github.com/jsonresume/jsonresume-theme-class" 19 | }, 20 | "scripts": { 21 | "serve": "resume serve --theme . --resume ./test/fixture.resume.json", 22 | "build:pdf": "resume export --theme . --resume ./test/fixture.resume.json resume.pdf", 23 | "build:html": "resume export --theme . --resume ./test/fixture.resume.json resume.html" 24 | }, 25 | "dependencies": { 26 | "handlebars": "^4.7.8", 27 | "html-minifier": "^4.0.0", 28 | "marked": "^11.1.1" 29 | }, 30 | "devDependencies": { 31 | "resume-cli": "^3.0.8" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /resume.handlebars: -------------------------------------------------------------------------------- 1 | 2 | {{#if resume.meta.language}} 3 | 4 | {{else}} 5 | 6 | {{/if}} 7 | 8 | {{#if resume.basics.name}} 9 | {{resume.basics.name}} - CV 10 | 11 | {{else}} 12 | CV 13 | {{/if}} 14 | 15 | {{#if resume.basics.summary}} 16 | 17 | 18 | {{/if}} 19 | 20 | {{#if resume.basics.label}} 21 | 22 | {{/if}} 23 | 24 | {{#if resume.basics.image}} 25 | 26 | 27 | {{#if resume.basics.name}} 28 | 29 | {{/if}} 30 | {{/if}} 31 | 32 | {{#if resume.custom.xTwitterHandle}} 33 | 34 | {{/if}} 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | {{#resume.basics}} 46 |
47 |

{{name}}

48 | {{#if label}} 49 |

{{label}}

50 | {{/if}} 51 |
52 | 53 |
54 |
55 |
56 |

Contact

57 |
58 | {{#if url}} 59 |
60 | Website 61 | 62 | {{{link url}}} 63 |
64 | {{else if website}} 65 |
66 | Website 67 | {{website}} 68 |
69 | {{/if}} 70 | {{#if email}} 71 | 75 | {{/if}} 76 | {{#if phone}} 77 |
78 | Phone 79 | {{phone}} 80 |
81 | {{/if}} 82 |
83 |
84 | {{#if summary}} 85 |
86 |

About

87 |

{{{markdown summary}}}

88 |
89 | {{/if}} 90 | {{#if profiles.length}} 91 |
92 | {{#each profiles}} 93 |
94 | {{#if network}} 95 | 96 | {{network}} 97 | 98 | {{/if}} 99 |
100 | {{#if url}} 101 | 102 | {{#if username}} 103 | {{username}} 104 | {{else}} 105 | {{url}} 106 | {{/if}} 107 | 108 | {{else}} 109 | {{username}} 110 | {{/if}} 111 |
112 |
113 | {{/each}} 114 |
115 | {{/if}} 116 |
117 | {{/resume.basics}} 118 | 119 | {{#if resume.work.length}} 120 |
121 |

Work Experience

122 | {{#each resume.work}} 123 |
124 | {{#if name}} 125 |

126 | {{name}} 127 |

128 | {{else if company}} 129 |

130 | {{company}} 131 |

132 | {{/if}} 133 | 134 |
135 | {{#if position}} 136 |
137 | {{position}} 138 |
139 | {{/if}} 140 | 141 |
142 | {{#if startDate}} 143 | {{{date startDate}}} - {{{date endDate}}} 144 | {{/if}} 145 |
146 | 147 | {{#if url}} 148 |
149 | {{{link url}}} 150 |
151 | {{else if website}} 152 |
153 | {{website}} 154 |
155 | {{/if}} 156 |
157 | 158 | {{#if summary}} 159 |
160 |

{{{markdown summary}}}

161 |
162 | {{/if}} 163 | {{#if highlights.length}} 164 |
    165 | {{#each highlights}} 166 |
  • {{{markdown .}}}
  • 167 | {{/each}} 168 |
169 | {{/if}} 170 |
171 | {{/each}} 172 |
173 | {{/if}} 174 | 175 | {{#if resume.volunteer.length}} 176 |
177 |

Volunteer

178 | {{#each resume.volunteer}} 179 |
180 | {{#if organization}} 181 |

182 | {{organization}} 183 |

184 | {{/if}} 185 | 186 |
187 | {{#if position}} 188 |
189 | {{position}} 190 |
191 | {{/if}} 192 | 193 |
194 | {{#if startDate}} 195 | 196 | {{{date startDate}}} 197 | 198 | 199 | - {{{date endDate}}} 200 | 201 | {{/if}} 202 |
203 | 204 | {{#if url}} 205 |
206 | {{{link url}}} 207 |
208 | {{else if website}} 209 |
210 | {{website}} 211 |
212 | {{/if}} 213 |
214 | 215 | {{#if summary}} 216 |
217 |

{{{markdown summary}}}

218 |
219 | {{/if}} 220 | {{#if highlights.length}} 221 |
    222 | {{#each highlights}} 223 |
  • {{{markdown .}}}
  • 224 | {{/each}} 225 |
226 | {{/if}} 227 |
228 | {{/each}} 229 |
230 | {{/if}} 231 | 232 | {{#if resume.education.length}} 233 |
234 |

Education

235 | {{#each resume.education}} 236 |
237 | 238 |
239 | {{#if institution}} 240 |
241 | {{institution}} 242 |
243 | {{/if}} 244 | 245 |
246 | {{#if startDate}} 247 | 248 | {{{date startDate}}} 249 | 250 | 251 | - {{{date endDate}}} 252 | 253 | {{/if}} 254 |
255 | 256 | {{#if url}} 257 |
258 | {{{link url}}} 259 |
260 | {{/if}} 261 |
262 | 263 | {{#if qualification}} 264 |
265 | {{qualification}} 266 |
267 | {{/if}} 268 | 269 | {{#if courses.length}} 270 |
    271 | {{#each courses}} 272 |
  • {{.}}
  • 273 | {{/each}} 274 |
275 | {{/if}} 276 | 277 | {{#if dissertation}} 278 |
279 | Dissertation: {{dissertation}} 280 |
281 | {{/if}} 282 |
283 | {{/each}} 284 |
285 | {{/if}} 286 | 287 | {{#if resume.skills.length}} 288 |
289 |

Skills

290 | {{#each resume.skills}} 291 |
292 | {{#if name}} 293 |
294 | {{name}} 295 |
296 | {{/if}} 297 | {{#if level}} 298 |
299 | {{level}} 300 |
301 | {{/if}} 302 | {{#if keywords.length}} 303 |
    304 | {{#each keywords}} 305 |
  • {{.}}
  • 306 | {{/each}} 307 |
308 | {{/if}} 309 |
310 | {{/each}} 311 |
312 | {{/if}} 313 | 314 | {{#if resume.languages.length}} 315 |
316 |

Languages

317 | {{#each resume.languages}} 318 |
319 | {{#if language}} 320 |
{{language}}
321 | {{/if}} 322 | {{#if fluency}} 323 |
324 | {{fluency}} 325 |
326 | {{/if}} 327 |
328 | {{/each}} 329 |
330 | {{/if}} 331 | 332 | {{#if resume.interests.length}} 333 |
334 |

Interests

335 | {{#each resume.interests}} 336 |
337 | {{#if name}} 338 |
339 | {{name}} 340 |
341 | {{/if}} 342 | {{#if keywords.length}} 343 |
    344 | {{#each keywords}} 345 |
  • {{.}}
  • 346 | {{/each}} 347 |
348 | {{/if}} 349 |
350 | {{/each}} 351 |
352 | {{/if}} 353 | 354 | {{#if resume.references.length}} 355 |
356 |

References

357 | {{#each resume.references}} 358 |
359 | {{#if reference}} 360 |
361 | {{reference}} 362 |
363 | {{/if}} 364 | {{#if name}} 365 |
366 | — {{name}} 367 |
368 | {{/if}} 369 |
370 | {{/each}} 371 |
372 | {{/if}} 373 |
374 | 375 | 376 | -------------------------------------------------------------------------------- /style.css: -------------------------------------------------------------------------------- 1 | body { 2 | --fg-color: black; 3 | --bg-color: #fff; 4 | --header-h1-fg-color: #fff; 5 | --header-h2-fg-color: #f3f3f3; 6 | --header-bg-color: #1866c3; 7 | --link-color: #3061a5; 8 | --separator-color: #e2e2e2; 9 | 10 | margin: 0; 11 | color: var(--fg-color); 12 | background: var(--bg-color); 13 | font-size: 15px; 14 | font-family: Roboto, 'Helvetica Neue', 'Arial Nova', 'Liberation Sans', Arial, sans-serif; 15 | } 16 | 17 | @media (prefers-color-scheme: dark) { 18 | body { 19 | --fg-color: #eee; 20 | --bg-color: #2c2c2c; 21 | --header-h1-fg-color: #ddd; 22 | --header-h2-fg-color: #eee; 23 | --header-bg-color: #1b1b1b; 24 | --link-color: #70a1e5; 25 | --separator-color: #939393 26 | } 27 | } 28 | 29 | em { 30 | color: #999; 31 | } 32 | 33 | a { 34 | color: var(--link-color); 35 | text-decoration: none; 36 | } 37 | 38 | section { 39 | margin-bottom: 2em; 40 | } 41 | 42 | .item { 43 | break-inside: avoid; 44 | } 45 | 46 | header { 47 | background: var(--header-bg-color); 48 | padding: 50px; 49 | margin-bottom: 50px; 50 | } 51 | 52 | header h1 { 53 | color: var(--header-h1-fg-color); 54 | max-width: 772px; 55 | margin: 0 auto; 56 | } 57 | 58 | header h2 { 59 | color: var(--header-h2-fg-color); 60 | font-size: 1em; 61 | max-width: 772px; 62 | margin: 0 auto; 63 | } 64 | 65 | .container { 66 | max-width: 772px; 67 | padding: 0 50px; 68 | margin: 0 auto; 69 | } 70 | 71 | #basics { 72 | margin-bottom: 10px; 73 | border-bottom: 1px var(--separator-color) solid; 74 | } 75 | 76 | .split { 77 | display: flex; 78 | flex-wrap: wrap; 79 | } 80 | 81 | .split strong { 82 | margin-right: 2em; 83 | } 84 | 85 | .website, 86 | .email, 87 | .phone, 88 | #profiles .item, 89 | #languages .item, 90 | #interests .item, 91 | #skills .item { 92 | width: 50%; 93 | } 94 | 95 | .username { 96 | margin-top: .5em; 97 | } 98 | 99 | .work_date, 100 | .work_position, 101 | .work_website, 102 | .institution, 103 | .study_date, 104 | .qualification { 105 | margin-bottom: 10px; 106 | width: 30%; 107 | } 108 | 109 | .courses, 110 | #references, 111 | #interests { 112 | clear: both; 113 | } 114 | 115 | .dissertation { 116 | margin-top: 10px; 117 | } 118 | 119 | #work, 120 | #volunteer { 121 | padding-bottom: 5px; 122 | border-bottom: 1px var(--separator-color) solid; 123 | } 124 | 125 | #work .item, 126 | #volunteer .item { 127 | margin: 25px 0; 128 | } 129 | 130 | #skills { 131 | margin-bottom: 10px; 132 | border-bottom: 1px var(--separator-color) solid; 133 | padding-bottom: 5px; 134 | overflow: hidden; 135 | } 136 | 137 | #skills .item, 138 | #languages .item, 139 | #interests .item { 140 | margin: 0 0 25px 0; 141 | } 142 | 143 | @page { 144 | margin: 2em 0 0 0; 145 | } 146 | 147 | @page :first { 148 | margin: 0; 149 | } 150 | -------------------------------------------------------------------------------- /test/fixture.resume.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://raw.githubusercontent.com/jsonresume/resume-schema/v1.0.0/schema.json", 3 | "meta": { 4 | "language": "en" 5 | }, 6 | "basics": { 7 | "name": "Seth Falco", 8 | "label": "Open-Sourcerer 🧙‍♂️", 9 | "email": "seth@example.org", 10 | "phone": "+00 0694201337", 11 | "summary": "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Sollicitudin nibh sit amet commodo nulla facilisi nullam.", 12 | "location": { 13 | "countryCode": "GB" 14 | }, 15 | "profiles": [ 16 | { 17 | "network": "GitHub", 18 | "username": "SethFalco", 19 | "url": "https://github.com/SethFalco" 20 | }, 21 | { 22 | "network": "LinkedIn", 23 | "username": "sethfalco", 24 | "url": "https://www.linkedin.com/in/sethfalco/" 25 | } 26 | ] 27 | }, 28 | "work": [ 29 | { 30 | "name": "JSON Resume", 31 | "location": "Remote", 32 | "position": "Open-Sourcerer 🧙‍♂️", 33 | "url": "https://jsonresume.org/", 34 | "startDate": "2021-10", 35 | "summary": "Facilisis volutpat est velit egestas dui id ornare.", 36 | "highlights": [ 37 | "Sollicitudin nibh sit amet commodo nulla facilisi nullam.", 38 | "A scelerisque purus semper eget.", 39 | "Sed egestas egestas fringilla phasellus faucibus scelerisque.", 40 | "Purus semper eget duis at tellus at urna condimentum mattis." 41 | ] 42 | } 43 | ], 44 | "volunteer": [ 45 | { 46 | "organization": "SVGO", 47 | "position": "Open-Sourcerer 🧙‍♂️", 48 | "url": "https://svgo.dev/", 49 | "startDate": "2023-09", 50 | "summary": "Cursus risus at ultrices mi tempus imperdiet nulla.", 51 | "highlights": [ 52 | "Sed odio morbi quis commodo odio aenean sed adipiscing.", 53 | "Diam sollicitudin tempor id eu nisl nunc mi." 54 | ] 55 | } 56 | ], 57 | "education": [ 58 | { 59 | "institution": "freeCodeCamp", 60 | "url": "https://www.freecodecamp.org/", 61 | "area": "Information Technology", 62 | "studyType": "Community-Study" 63 | } 64 | ], 65 | "certificates": [ 66 | { 67 | "name": "edX Verified Certificate for Introduction to Web Accessibility", 68 | "date": "2023-04-17", 69 | "issuer": "edX" 70 | } 71 | ], 72 | "publications": [ 73 | { 74 | "name": "What are Bookmarklets? How to Use JavaScript to Make a Bookmarklet in Chromium and Firefox", 75 | "publisher": "freeCodeCamp", 76 | "releaseDate": "2021-06-17", 77 | "url": "https://www.freecodecamp.org/news/what-are-bookmarklets/" 78 | } 79 | ], 80 | "languages": [ 81 | { 82 | "language": "English", 83 | "fluency": "Native" 84 | }, 85 | { 86 | "language": "French", 87 | "fluency": "Elementary" 88 | } 89 | ] 90 | } 91 | --------------------------------------------------------------------------------