this repo has no description
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

🍱 Finish /resume

+597 -433
+7 -3
education.yaml
··· 4 4 name: Lycée D'Alzon 5 5 location: Nîmes 6 6 diploma: 7 - results: mention “very good” 16.26/20 8 7 name: Scientific Baccalaureate 8 + results: 9 + scores: 10 + mention “very good”: [16.26, / 20] 9 11 10 12 - time: 2020 11 13 title: Preparatory Classes, Mathematics & Physics ··· 16 18 diploma: 17 19 name: Entrance exams 18 20 results: 19 - CCINP: 1104th out of 7862 20 - Mines-Télécom: 1791st out of 5467 21 + location: Paris 22 + scores: 23 + CCINP: [1104th, of 7862] 24 + Mines-Télécom: [1791st, of 5467] 21 25 22 26 - time: 2022 23 27 title: Computer Science Engineering, Multimedia & Networks
+44 -18
experiences.yaml
··· 1 1 - time: 2017 2 2 title: Intern 3 + location: Montpellier 4 + skills: [premiere pro] 3 5 company: 4 6 name: Pages & Images 5 7 description: audiovisual agency 6 - location: Montpellier 7 - description: "" 8 - skills: [premiere pro] 8 + url: http://pagesimages.com/ 9 9 10 10 - time: 2018 11 11 title: Intern 12 + location: Montpellier 13 + skills: [premiere pro, html, css, js, php] 12 14 company: 13 15 name: Satellite 14 16 description: audiovisual agency 15 - location: Montpellier 16 - description: "" 17 - skills: [premiere pro, html, css, js, php] 17 + url: https://agence-satellite.com/ 18 18 19 19 - time: 2019 20 20 title: Intern 21 + location: Lunel 22 + skills: [photoshop, figma] 21 23 company: 22 24 name: l'Atelier 23 25 description: printing & graphic design 24 - location: Lunel 25 - description: "" 26 - skills: [photoshop, figma] 26 + url: https://latelier34.fr/ 27 27 28 28 - time: 2020 29 29 title: Intern 30 + location: Sophia 30 31 company: 31 32 name: Sophia Engineering 32 33 description: engineering consulting 33 - location: Sophia 34 - description: "" 34 + url: https://sophiaengineering.com/ 35 35 36 36 - time: 2024 37 37 title: Intern 38 + location: Toulouse 39 + description: research on intrinsic physical representation of sound data 40 + skills: [python, kivy, android] 38 41 company: 39 42 name: IRIT 40 43 description: computer science research lab 41 44 url: https://irit.fr 42 - location: Toulouse 43 - description: research on intrinsic physical representation of sound data 44 - skills: [python, kivy, android] 45 45 46 - - time: 2023-2024 46 + - time: [2023, 2024] 47 47 title: President 48 + location: Toulouse 49 + skills: [kubernetes, svelte, graphql, go] 48 50 company: 49 51 name: net7 50 52 description: student association 51 - url: https://net7.dev/equipe.html#:~:text=Pr%C3%A9sidente%20:%20Gwen-,Le%20Bihan,-Vice%2DPr%C3%A9sident%20:%20T%C3%A9o 52 - location: Toulouse 53 + url: https://net7.dev/equipe.html 53 54 description: | 54 55 web infrastructure & development 55 56 services used by ~2k students 56 - skills: [kubernetes, svelte, graphql, go] 57 + 58 + - time: [2023, 2024] 59 + title: Head of IT 60 + location: Toulouse 61 + company: 62 + name: TVn7 63 + description: Video production student association 64 + url: https://tvn7.fr/anciens-membres 65 + 66 + - time: 2025 67 + title: Contractor 68 + location: Toulouse 69 + links: 70 + - https://github.com/cigaleapp/cigale 71 + company: 72 + name: SETE-CNRS 73 + description: Theoretical and Experimental Ecology Station 74 + url: https://sete-moulis-cnrs.fr/en/ 75 + 76 + - time: 2025 77 + title: Paid intern 78 + location: Toulouse 79 + company: 80 + name: LAAS-CNRS 81 + description: NixOS in robotics research 82 + url: https://laas.fr/en/annuaire/1785
+15 -5
src/content.config.ts
··· 19 19 .optional() 20 20 .transform((value) => (value ? new Date(value) : null)); 21 21 22 + const year = z.number().min(2003).max(new Date().getFullYear()).int(); 23 + 22 24 export const collections = { 23 25 frenchMessages: gettextPoMessages("i18n/fr.po"), 24 26 englishMessages: gettextPoMessages("i18n/en.po"), ··· 133 135 experiences: yamlDataCollection( 134 136 "experiences.yaml", 135 137 z.object({ 136 - time: z.coerce.string(), 138 + time: z.union([year, z.tuple([year, year])]), 137 139 title: z.string(), 140 + links: z.array(z.string().url()).optional().default([]), 138 141 company: z.object({ 139 142 name: z.string(), 140 143 url: z.string().url().optional(), ··· 144 147 description: z.string(), 145 148 skills: z.array(z.string()).optional(), 146 149 }), 147 - (exp) => exp.time.toString(), 150 + (exp) => `${exp.company.name}, ${exp.time}`, 148 151 ), 149 152 education: yamlDataCollection( 150 153 "education.yaml", 151 154 z.object({ 152 - time: z.number().min(2003).max(new Date().getFullYear()).int(), 155 + time: year, 153 156 title: z.string(), 154 157 school: z.object({ 155 158 name: z.string(), ··· 157 160 }), 158 161 location: z.string(), 159 162 diploma: z.object({ 160 - results: z.union([z.string(), z.record(z.string())]).optional(), 163 + results: z 164 + .object({ 165 + location: z.string().optional(), 166 + scores: z.record(z.tuple([z.string(), z.string()])), 167 + }) 168 + .optional(), 161 169 name: z.string(), 162 170 }), 163 171 }), ··· 230 238 schema, 231 239 loader: { 232 240 name: "YAML Loader", 233 - async load({ renderMarkdown, store, generateDigest }) { 241 + async load({ renderMarkdown, store, generateDigest, watcher }) { 234 242 const raw = await readFile(filename); 235 243 const parsed: Array<z.infer<Schema>> | Record<string, z.infer<Schema>> = 236 244 YAML.parse(raw.toString()); 245 + 246 + watcher?.add(filename); 237 247 238 248 if (Array.isArray(parsed)) { 239 249 const entries = parsed
+531 -407
src/pages/resume/index.astro
··· 1 - --- 2 - import { getCollection } from "astro:content"; 3 - import Bare from "../../layouts/Bare.astro"; 4 - import Tech from "./Tech.astro"; 5 - import Reference from "./Reference.astro"; 6 - 7 - const wakatime = await getCollection("wakatime").then((entries) => 8 - Object.fromEntries( 9 - entries.map((entry) => [ 10 - entry.id, 11 - Math.floor(entry.data.total_seconds / 3600), 12 - ]), 13 - ), 14 - ); 15 - 16 - const timeSpent = { 17 - htmlcssjs: wakatime.html + wakatime.css + wakatime.javascript, 18 - python: wakatime.python, 19 - }; 20 - 21 - const education = await getCollection("education").then((entries) => 22 - entries.map(({ data }) => data), 23 - ); 24 - --- 25 - 26 - <Bare 27 - bodyStyles={{ 28 - color: "var(--gray)", 29 - background: "var(--void)", 30 - "--pad": "1.5em", 31 - }} 32 - > 33 - <header> 34 - <h1>Gwenn Le Bihan</h1> 35 - <p class="intro" i18n> 36 - I am interested in almost anything that is both creative &amp; digital. 37 - </p> 38 - <dl> 39 - <dt>Portfolio</dt> 40 - <dd><a href="https://gwen.works">gwen.works</a></dd> 41 - <dt>Email</dt> 42 - <dd> 43 - <a href="https://gwen.works/to/email">gwenn.lebihan7 (at) gmail.com</a> 44 - </dd> 45 - </dl> 46 - </header> 47 - 48 - <main> 49 - <h2>Skills</h2> 50 - <section class="skills"> 51 - <div class="language"> 52 - <h3>Language</h3> 53 - <h4>French</h4> 54 - <ul> 55 - <li>Native</li> 56 - </ul> 57 - <h4>English</h4> 58 - <ul> 59 - <li> 60 - <strong>950/990</strong> 61 - (<a href="https://www.etsglobal.org/fr/en">TOEIC</a>) 62 - </li> 63 - <li> 64 - <strong>176/180</strong> 65 - (<a 66 - href="https://www.etsglobal.org/fr/en/test-type-family/toeic-bridge-test" 67 - >TOEIC Bridge</a 68 - >) 69 - </li> 70 - <li> 71 - <strong>C1</strong> 72 - (<a 73 - href="https://www.cambridgeenglish.org/fr/exams-and-tests/linguaskill/" 74 - >Cambridge LinguaSkill</a 75 - >) 76 - </li> 77 - </ul> 78 - <h4>Japanese</h4> 79 - <ul> 80 - <li>Japanese</li> 81 - </ul> 82 - </div> 83 - <div class="programming"> 84 - <h3>Programming</h3> 85 - <h4>Web</h4> 86 - <ul> 87 - <li> 88 - <strong>{timeSpent.htmlcssjs}+</strong> hours of 89 - <Tech name="html" />, <Tech name="css" /> and <Tech 90 - name="javascript" 91 - /> 92 - </li> 93 - <li> 94 - Large platform in <Tech name="graphql" />+<Tech name="sveltekit" /> 95 - <Reference parens url="github.com/inp-net/churros" /> 96 - </li> 97 - <li> 98 - Technical GraphQL documentation site generator <Reference 99 - parens 100 - url="github.com/graphinx/graphinx" 101 - /> 102 - </li> 103 - <li> 104 - Deployment of several services on a <Tech name="Kubernetes" /> cluster 105 - </li> 106 - </ul> 107 - <h4>Data science</h4> 108 - <ul> 109 - <li> 110 - <strong>{timeSpent.python}+</strong> hours of <Tech name="python" /> 111 - </li> 112 - <li> 113 - Detection &amp; classification webapp to help entomoly research 114 - using <strong><a href="/neural networks">neural networks</a></strong 115 - > 116 - <Reference parens url="github.com/cigaleapp/cigale" /> 117 - </li> 118 - </ul> 119 - <h4>Miscelleanous</h4> 120 - <ul> 121 - <li> 122 - CLI programs in Python, <Tech name="Ruby" /> or <Tech name="Go" /> 123 - <Reference parens url="gwen.works/terminal" /> 124 - </li> 125 - <li> 126 - Homework and class notes taken in <Tech name="LaTeX" /> &amp; <Tech 127 - name="Typst" 128 - /> 129 - </li> 130 - </ul> 131 - </div> 132 - <div class="social"> 133 - <h3>Social</h3> 134 - <ul> 135 - <li> 136 - Active member of multiple <strong>student associations</strong> 137 - </li> 138 - <li> 139 - <strong>Organized &amp; taught</strong> web programming <strong 140 - >classes</strong 141 - > 142 - </li> 143 - <li> 144 - <strong>Performed</strong> electronic music <strong>live</strong> 145 - </li> 146 - <li> 147 - Was a <strong>point of contact</strong> between users and developers 148 - for a large student web platform 149 - </li> 150 - </ul> 151 - </div> 152 - <div class="media"> 153 - <h3>Design</h3> 154 - <h4>User interfaces</h4> 155 - <ul> 156 - <li> 157 - Designed in 158 - <Tech name="Figma" /> or <Tech name="Penpot" /> 159 - prior to implementation 160 - </li> 161 - </ul> 162 - <h4>Media</h4> 163 - <ul> 164 - <li> 165 - Posters for associations using Adobe <Tech name="Photoshop" />, <Tech 166 - name="InDesign" 167 - /> and <Tech name="Illustrator" /> 168 - </li> 169 - <li> 170 - Short films with Adobe <Tech name="Premiere Pro" /> and <Tech 171 - name="After Effects" 172 - /> 173 - </li> 174 - <li> 175 - Electronic music production w/ <Tech name="FL Studio" /> 176 - <Reference parens url="gwen.works/music" /> 177 - </li> 178 - </ul> 179 - </div> 180 - <div class="transdisciplinary"> 181 - <h3>Transdisciplinary</h3> 182 - <ul> 183 - <li> 184 - 2D Video engine made for music video creation with <abbr 185 - title="Digial Audio Workstation, such as FL Studio for example" 186 - >DAW</abbr 187 - > integrations & <Tech name="WASM" /> support using Rust <Reference 188 - parens 189 - url="gwen.works/shapemaker" 190 - /> 191 - </li> 192 - </ul> 193 - </div> 194 - </section> 195 - <section class="education"> 196 - <h2>Education</h2> 197 - <dl class="timeline"> 198 - <dt>now</dt> 199 - { 200 - education 201 - .sort((a, b) => a.time - b.time) 202 - .reverse() 203 - .map(({ time, title, school, location, diploma }) => ( 204 - <dd> 205 - <h3> 206 - <span class="main"> 207 - {school.name} 208 - </span> 209 - <span class="secondary"> 210 - @ {location} 211 - </span> 212 - </h3> 213 - <p> 214 - {title} 215 - <br> 216 - {'results' in diploma ? "" : diploma.name} 217 - </p> 218 - </dd> 219 - <dt> 220 - {time} 221 - </dt> 222 - )) 223 - } 224 - </dl> 225 - </section> 226 - <section> 227 - <h2>Experience</h2> 228 - </section> 229 - </main> 230 - </Bare> 231 - 232 - <style> 233 - @media print { 234 - :root { 235 - font-size: 0.7rem; 236 - } 237 - } 238 - 239 - section.skills { 240 - columns: 2; 241 - } 242 - 243 - @media screen and (max-width: 800px) { 244 - section.skills { 245 - columns: 1; 246 - } 247 - } 248 - 249 - section.skills > div { 250 - break-inside: avoid; 251 - } 252 - 253 - section.education dd { 254 - margin-top: 3ch; 255 - } 256 - 257 - section.education dt { 258 - text-align: center; 259 - width: 100%; 260 - color: var(--gold); 261 - background-color: var(--void); 262 - height: 1lh; 263 - line-height: 1.2; 264 - padding: 1ch 0; 265 - z-index: 1; 266 - } 267 - 268 - section.education dl { 269 - position: relative; 270 - } 271 - 272 - section.education dl::before { 273 - content: ""; 274 - position: absolute; 275 - top: 0; 276 - bottom: 0; 277 - width: 0.5ch; 278 - left: 2ch; 279 - background: var(--gold); 280 - z-index: 1; 281 - } 282 - 283 - section.education h3 .main { 284 - font-weight: bold; 285 - color: var(--quartz); 286 - } 287 - 288 - section.education h3 .secondary { 289 - font-weight: normal; 290 - color: var(--jade); 291 - } 292 - 293 - 294 - :root { 295 - --diamond: #39c6df; 296 - --jade: #73daca; 297 - --gold: #e4ab6a; 298 - --gray: #7982a9; 299 - --quartz: #f5f5f5; 300 - --void: #16161e; 301 - --ruby: #f7768e; 302 - --lapis: #60a2f7; 303 - } 304 - 305 - dl { 306 - display: grid; 307 - grid-template-columns: max-content 2fr; 308 - gap: 0.5ch 2ch; 309 - } 310 - 311 - dd, 312 - dt { 313 - margin: 0; 314 - } 315 - 316 - h1 { 317 - color: var(--jade); 318 - font-size: 2.5em; 319 - margin: 0; 320 - margin-bottom: 0.25ch; 321 - line-height: 1; 322 - } 323 - 324 - h2 { 325 - color: var(--jade); 326 - font-size: 2em; 327 - margin: 0; 328 - } 329 - 330 - h3 { 331 - font-size: 1em; 332 - margin: 0; 333 - } 334 - 335 - section.skills h3 { 336 - color: var(--lapis); 337 - font-family: "Victor Mono", monospace; 338 - } 339 - section.skills h3::after { 340 - content: "-------------------------------------"; 341 - display: block; 342 - } 343 - 344 - h4 { 345 - font-size: 1em; 346 - margin: 0; 347 - font-family: "Victor Mono", monospace; 348 - color: var(--jade); 349 - } 350 - 351 - .intro { 352 - font-family: "Victor Mono", monospace; 353 - font-style: italic; 354 - color: var(--jade); 355 - } 356 - 357 - main { 358 - line-height: 1.4; 359 - } 360 - 361 - h3, 362 - li, 363 - dt, 364 - dd { 365 - font-family: "Victor Mono", monospace; 366 - } 367 - 368 - p { 369 - margin: 0; 370 - } 371 - 372 - ul { 373 - padding-left: 0; 374 - margin: 0; 375 - margin-bottom: 2ch; 376 - } 377 - 378 - li { 379 - list-style: none; 380 - } 381 - 382 - li::before { 383 - content: "— "; 384 - color: var(--ruby); 385 - } 386 - 387 - :global(a, a:visited) { 388 - color: var(--diamond); 389 - text-decoration-color: currentColor; 390 - } 391 - 392 - :global(a:hover, a:focus-visible) { 393 - color: var(--jade); 394 - text-decoration-color: currentColor; 395 - text-decoration-thickness: 2px; 396 - } 397 - 398 - :global(strong, strong a) { 399 - font-weight: normal; 400 - color: var(--gold); 401 - } 402 - 403 - :global(strong a:is(:hover, :focus-visible)) { 404 - color: var(--ruby); 405 - } 406 - 407 - </style> 1 + --- 2 + import { getCollection } from "astro:content"; 3 + import Bare from "../../layouts/Bare.astro"; 4 + import Tech from "./Tech.astro"; 5 + import Reference from "./Reference.astro"; 6 + 7 + const wakatime = await getCollection("wakatime").then((entries) => 8 + Object.fromEntries( 9 + entries.map((entry) => [ 10 + entry.id, 11 + Math.floor(entry.data.total_seconds / 3600), 12 + ]), 13 + ), 14 + ); 15 + 16 + const timeSpent = { 17 + htmlcssjs: wakatime.html + wakatime.css + wakatime.javascript, 18 + python: wakatime.python, 19 + }; 20 + 21 + const education = await getCollection("education").then((entries) => 22 + entries.map(({ data }) => data), 23 + ); 24 + 25 + const experience = await getCollection("experiences").then((entries) => 26 + entries.map(({ data }) => data), 27 + ); 28 + --- 29 + 30 + <Bare 31 + bodyStyles={{ 32 + color: "var(--gray)", 33 + background: "var(--void)", 34 + "--pad": "1.5em", 35 + }} 36 + > 37 + <header> 38 + <h1>Gwenn Le Bihan</h1> 39 + <p class="intro" i18n> 40 + I am interested in almost anything that is both creative &amp; digital. 41 + </p> 42 + <dl> 43 + <dt>Portfolio</dt> 44 + <dd><a href="https://gwen.works">gwen.works</a></dd> 45 + <dt>Email</dt> 46 + <dd> 47 + <a href="https://gwen.works/to/email">gwenn.lebihan7 (at) gmail.com</a> 48 + </dd> 49 + </dl> 50 + </header> 51 + 52 + <main> 53 + <h2>Skills</h2> 54 + <section class="skills"> 55 + <div class="programming"> 56 + <h3>Programming</h3> 57 + <h4>Web</h4> 58 + <ul> 59 + <li> 60 + <strong>{timeSpent.htmlcssjs}+</strong> hours of 61 + <Tech name="html" />, <Tech name="css" /> and <Tech 62 + name="javascript" 63 + /> 64 + </li> 65 + <li> 66 + Large platform in <Tech name="graphql" />+<Tech name="sveltekit" /> 67 + <Reference parens url="github.com/inp-net/churros" /> 68 + </li> 69 + <li> 70 + Technical GraphQL documentation site generator <Reference 71 + parens 72 + url="github.com/graphinx/graphinx" 73 + /> 74 + </li> 75 + <li> 76 + Deployment of several services on a <Tech name="Kubernetes" /> cluster 77 + </li> 78 + </ul> 79 + <h4>Data science</h4> 80 + <ul> 81 + <li> 82 + <strong>{timeSpent.python}+</strong> hours of <Tech name="python" /> 83 + </li> 84 + <li> 85 + Detection &amp; classification webapp to help entomoly research 86 + using <strong><a href="/neural networks">neural networks</a></strong 87 + > 88 + <Reference parens url="github.com/cigaleapp/cigale" /> 89 + </li> 90 + </ul> 91 + <h4>Miscelleanous</h4> 92 + <ul> 93 + <li> 94 + CLI programs in Python, <Tech name="Ruby" /> or <Tech name="Go" /> 95 + <Reference parens url="gwen.works/terminal" /> 96 + </li> 97 + <li> 98 + Homework and class notes taken in <Tech name="LaTeX" /> &amp; <Tech 99 + name="Typst" 100 + /> 101 + </li> 102 + </ul> 103 + </div> 104 + <div class="social"> 105 + <h3>Social</h3> 106 + <ul> 107 + <li> 108 + Active member of multiple <strong>student associations</strong> 109 + </li> 110 + <li> 111 + <strong>Organized &amp; taught</strong> web programming <strong 112 + >classes</strong 113 + > 114 + </li> 115 + <li> 116 + <strong>Performed</strong> electronic music <strong>live</strong> 117 + </li> 118 + <li> 119 + Was a <strong>point of contact</strong> between users and developers 120 + for a large student web platform 121 + </li> 122 + </ul> 123 + </div> 124 + <div class="language"> 125 + <h3>Language</h3> 126 + <h4>French</h4> 127 + <ul> 128 + <li>Native</li> 129 + </ul> 130 + <h4>English</h4> 131 + <ul> 132 + <li> 133 + <strong>950/990</strong> 134 + (<a href="https://www.etsglobal.org/fr/en">TOEIC</a>) 135 + </li> 136 + <li> 137 + <strong>176/180</strong> 138 + (<a 139 + href="https://www.etsglobal.org/fr/en/test-type-family/toeic-bridge-test" 140 + >TOEIC Bridge</a 141 + >) 142 + </li> 143 + <li> 144 + <strong>C1</strong> 145 + (<a 146 + href="https://www.cambridgeenglish.org/fr/exams-and-tests/linguaskill/" 147 + >Cambridge LinguaSkill</a 148 + >) 149 + </li> 150 + </ul> 151 + <h4>Japanese</h4> 152 + <ul> 153 + <li>Japanese</li> 154 + </ul> 155 + </div> 156 + <div class="media"> 157 + <h3>Design</h3> 158 + <h4>User interfaces</h4> 159 + <ul> 160 + <li> 161 + Designed in 162 + <Tech name="Figma" /> or <Tech name="Penpot" /> 163 + prior to implementation 164 + </li> 165 + </ul> 166 + <h4>Media</h4> 167 + <ul> 168 + <li> 169 + Posters for associations using Adobe <Tech name="Photoshop" />, <Tech 170 + name="InDesign" 171 + /> and <Tech name="Illustrator" /> 172 + </li> 173 + <li> 174 + Short films with Adobe <Tech name="Premiere Pro" /> and <Tech 175 + name="After Effects" 176 + /> 177 + </li> 178 + <li> 179 + Electronic music production w/ <Tech name="FL Studio" /> 180 + <Reference parens url="gwen.works/music" /> 181 + </li> 182 + </ul> 183 + </div> 184 + <div class="transdisciplinary"> 185 + <h3>Transdisciplinary</h3> 186 + <ul> 187 + <li> 188 + 2D Video engine made for music video creation with <abbr 189 + title="Digial Audio Workstation, such as FL Studio for example" 190 + >DAW</abbr 191 + > integrations & <Tech name="WASM" /> support using <Tech 192 + name="Rust" 193 + /> 194 + <Reference parens url="gwen.works/shapemaker" /> 195 + </li> 196 + </ul> 197 + </div> 198 + </section> 199 + <div class="edu-exp"> 200 + <section class="education"> 201 + <h2>Education</h2> 202 + <dl class="timeline times"> 203 + <dt>now</dt> 204 + { 205 + education 206 + .sort((a, b) => a.time - b.time) 207 + .reverse() 208 + .map(({ time, title, school, location, diploma }) => ( 209 + <> 210 + <dd> 211 + <h3> 212 + <span class="main">{school.name}</span> 213 + <span class="secondary">@ {location}</span> 214 + </h3> 215 + <p> 216 + {title} 217 + <br /> 218 + {"results" in diploma && 219 + diploma.results && 220 + "location" in diploma.results ? ( 221 + "" 222 + ) : ( 223 + <> 224 + {diploma.name} 225 + <br /> 226 + {diploma.results?.scores && 227 + Object.entries(diploma.results.scores).map( 228 + ([label, [score, max]]) => ( 229 + <> 230 + <br /> 231 + {label}&nbsp;<strong>{score}</strong> {max} 232 + </> 233 + ), 234 + )} 235 + </> 236 + )} 237 + </p> 238 + {"results" in diploma && 239 + diploma.results && 240 + "location" in diploma.results && ( 241 + <> 242 + <h3 class="results"> 243 + <span class="main">{diploma.name}</span> 244 + <span class="secondary"> 245 + @ {diploma.results.location} 246 + </span> 247 + </h3> 248 + <dl class="results"> 249 + {Object.entries(diploma.results.scores).map( 250 + ([label, [score, max]]) => ( 251 + <> 252 + <dt>{label}</dt> 253 + <dd> 254 + <strong>{score}</strong> {max} 255 + </dd> 256 + </> 257 + ), 258 + )} 259 + </dl> 260 + </> 261 + )} 262 + </dd> 263 + <dt> 264 + {typeof time === "number" ? ( 265 + time 266 + ) : ( 267 + <> 268 + {time[0]} 269 + <br />-<br /> 270 + {time[1]} 271 + </> 272 + )} 273 + </dt> 274 + </> 275 + )) 276 + } 277 + </dl> 278 + </section> 279 + <section> 280 + <h2>Experience</h2> 281 + <dl class="times"> 282 + { 283 + experience 284 + .sort((a, b) => { 285 + const sortee = ({ time }: { time: number | number[] }) => 286 + typeof time === "number" ? time : Math.min(...time); 287 + return sortee(a) - sortee(b); 288 + }) 289 + .reverse() 290 + .map(({ time, title, company, links }) => ( 291 + <> 292 + {" "} 293 + <dt> 294 + <strong> 295 + {typeof time === "number" ? ( 296 + time 297 + ) : ( 298 + <> 299 + {time[0]} 300 + <br />-<br /> 301 + {time[1]} 302 + </> 303 + )} 304 + </strong> 305 + </dt> 306 + <dd> 307 + <h3> 308 + <span class="main">{title}</span> 309 + <span class="secondary">@ {company.name}</span> 310 + </h3> 311 + <p>{company.description}</p> 312 + <p class="links"> 313 + {[company.url, ...(links ?? [])].map((u) => ( 314 + <a href={u} target="_blank"> 315 + {new URL(u).hostname} 316 + </a> 317 + ))} 318 + </p> 319 + </dd> 320 + </> 321 + )) 322 + } 323 + </dl> 324 + </section> 325 + </div> 326 + </main> 327 + </Bare> 328 + 329 + <style> 330 + @media print { 331 + :root { 332 + font-size: 0.7rem; 333 + } 334 + } 335 + 336 + .edu-exp { 337 + margin-top: 3em; 338 + } 339 + 340 + section.skills, 341 + .edu-exp { 342 + columns: 2; 343 + } 344 + 345 + @media screen and (max-width: 800px) { 346 + section.skills, 347 + .edu-exp { 348 + columns: 1; 349 + } 350 + } 351 + 352 + section.skills > div, 353 + .edu-exp > section { 354 + break-inside: avoid; 355 + } 356 + 357 + dl.timeline h3.results { 358 + margin-top: 1ch; 359 + } 360 + 361 + dl.results { 362 + display: grid; 363 + grid-template-columns: max-content 1fr; 364 + gap: 0.5ch 2ch; 365 + margin-top: 1ch; 366 + margin-bottom: 1ch; 367 + } 368 + 369 + dl.timeline > dd { 370 + margin-top: 3ch; 371 + } 372 + 373 + dl.timeline > dt { 374 + text-align: center; 375 + width: 100%; 376 + color: var(--gold); 377 + background-color: var(--void); 378 + height: 1lh; 379 + line-height: 1.2; 380 + padding: 1ch 0; 381 + z-index: 1; 382 + } 383 + 384 + dl.times:not(.timeline) { 385 + gap: 2ch; 386 + } 387 + 388 + dl.timeline { 389 + position: relative; 390 + } 391 + 392 + dl.timeline::before { 393 + content: ""; 394 + position: absolute; 395 + top: 0; 396 + bottom: 0; 397 + width: 0.5ch; 398 + left: 2ch; 399 + background: var(--gold); 400 + z-index: 1; 401 + } 402 + 403 + dl.times h3 .main { 404 + font-weight: bold; 405 + color: var(--quartz); 406 + } 407 + 408 + dl.times h3 .secondary { 409 + font-weight: normal; 410 + color: var(--jade); 411 + } 412 + 413 + dl.times .links { 414 + display: flex; 415 + align-items: center; 416 + gap: 2ch; 417 + } 418 + 419 + :root { 420 + --diamond: #39c6df; 421 + --jade: #73daca; 422 + --gold: #e4ab6a; 423 + --gray: #7a88c5; 424 + --quartz: #f5f5f5; 425 + --void: #16161e; 426 + --ruby: #f7768e; 427 + --lapis: #60a2f7; 428 + } 429 + 430 + dl { 431 + display: grid; 432 + grid-template-columns: max-content 2fr; 433 + gap: 0.5ch 2ch; 434 + } 435 + 436 + dd, 437 + dt { 438 + margin: 0; 439 + } 440 + 441 + h1 { 442 + color: var(--jade); 443 + font-size: 2.5em; 444 + margin: 0; 445 + margin-bottom: 0.25ch; 446 + line-height: 1; 447 + } 448 + 449 + h2 { 450 + color: var(--jade); 451 + font-size: 2em; 452 + margin: 0; 453 + } 454 + 455 + h3 { 456 + font-size: 1em; 457 + margin: 0; 458 + } 459 + 460 + section.skills h3 { 461 + color: var(--lapis); 462 + font-family: "Victor Mono", monospace; 463 + } 464 + section.skills h3::after { 465 + content: "-------------------------------------"; 466 + display: block; 467 + } 468 + 469 + h4 { 470 + font-size: 1em; 471 + margin: 0; 472 + font-family: "Victor Mono", monospace; 473 + color: var(--jade); 474 + } 475 + 476 + .intro { 477 + font-family: "Victor Mono", monospace; 478 + font-style: italic; 479 + color: var(--jade); 480 + } 481 + 482 + main { 483 + line-height: 1.4; 484 + } 485 + 486 + h3, 487 + li, 488 + dt, 489 + dd { 490 + font-family: "Victor Mono", monospace; 491 + } 492 + 493 + p { 494 + margin: 0; 495 + } 496 + 497 + ul { 498 + padding-left: 0; 499 + margin: 0; 500 + margin-bottom: 2ch; 501 + } 502 + 503 + li { 504 + list-style: none; 505 + } 506 + 507 + li::before { 508 + content: "— "; 509 + color: var(--ruby); 510 + } 511 + 512 + :global(a, a:visited) { 513 + color: var(--diamond); 514 + text-decoration-color: currentColor; 515 + } 516 + 517 + :global(a:hover, a:focus-visible) { 518 + color: var(--jade); 519 + text-decoration-color: currentColor; 520 + text-decoration-thickness: 2px; 521 + } 522 + 523 + :global(strong, strong a) { 524 + font-weight: normal; 525 + color: var(--gold); 526 + } 527 + 528 + :global(strong a:is(:hover, :focus-visible)) { 529 + color: var(--ruby); 530 + } 531 + </style>