diff --git a/packages/preview/resumetyp/0.1.0/LICENSE b/packages/preview/resumetyp/0.1.0/LICENSE new file mode 100644 index 0000000000..c4c3690511 --- /dev/null +++ b/packages/preview/resumetyp/0.1.0/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 Harsh Kasodariya + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/packages/preview/resumetyp/0.1.0/README.md b/packages/preview/resumetyp/0.1.0/README.md new file mode 100644 index 0000000000..469a9a84c8 --- /dev/null +++ b/packages/preview/resumetyp/0.1.0/README.md @@ -0,0 +1,348 @@ +# ResumeTyp + +[![Typst Universe](https://img.shields.io/badge/Typst%20Universe-resumetyp-239dad?logo=typst)](https://typst.app/universe/package/resumetyp) +[![Current package version](https://img.shields.io/badge/version-0.1.0-blue)](https://typst.app/universe/package/resumetyp) +[![Project License](https://img.shields.io/badge/license-MIT-green)](LICENSE) +[![GitHub stars](https://img.shields.io/github/stars/harshkaso/resumetyp?style=flat&logo=github)](https://github.com/harshkaso/resumetyp/stargazers) + +A modular, data-driven Typst resume framework designed to make customization simple. + +![example resumes built using resumetyp template](banner.png) + +## Features + +* Structured resume sections for contact information, summary, skills, experience, projects, education, and certifications. +* Configurable typography, spacing, colours, margins, list markers, and alignment. +* Automatic formatting of dates, metadata, and section headings. +* Built-in support for LinkedIn, GitHub, email, phone, and arbitrary contact fields. +* Reorderable output sections. +* Optional page breaks for individual entries. +* Minimal interface designed to keep resume content separate from presentation. + +## Installation + +Create a new Typst project using the package or import it directly: + +```typst +#import "@preview/resumetyp:0.1.0": * +``` + +The package exposes the resume configuration and content functions directly. + +## Basic Usage + +Configure the appearance of the resume with `resume.with`: + +```typst +#import "@preview/resumetyp:0.1.0": * + +#show: resume.with( + contact-info-position: center, + contacts-separator: [#h(0.4em)◆#h(0.4em)], + inline-separator: [ \/ ], + link-color: rgb("#B5651D"), + accent-color: rgb("#654321"), + font: "Libertinus Serif", + font-size: 11pt, + line-spacing: 0.65em, + page-margin: 0.5in, + list-marker: [--], + justify: true, +) +``` + +Add the resume content using the provided functions: + +```typst +#contact-info( + name: [Bramble Quillwhistle], + phone: [+1 (OWL) HOO-HOOT], + email: [bramble@example.invalid], + address: [Moonbeam, Cloudland], + linkedin: [bramble-qw], +) + +#summary[ + #strong[Quantum Spreadsheet Cartographer] experienced in mapping + imaginary datasets and turning complicated business riddles into + questionable charts. +] + +#skillset( + category: [Arcane Machinery], + skills: [WobbleScript, QuantaQL, HyperCalc, FluxLogic], +) + +#experience( + title: [Chief Spreadsheet Cartographer], + company: [Whizzlewick Data], + location: [Moonbeam], + start-date: [Mar 2023], + end-date: [Present], + [Mapped millions of imaginary records and uncovered previously + undocumented relationships between fictional business metrics.], + [Designed data-processing workflows that transformed chaotic + datasets into structured analytical tables.], +) + +#project( + name: [Interdimensional Sales Oracle], + info: [WobbleScript, FluxLogic], + start-date: [Jan 2024], + end-date: [Mar 2024], + [Predicted fictional sales across twelve dimensions using + historical sandwich observations.], +) + +#education( + degree: [Master of Computational Whimsy], + school: [Royal Academy of Impossibility], + location: [Starling Valley], + start-date: [Sep 2021], + end-date: [Jun 2023], + gpa: [4.87], +) + +#certification( + name: [Certified Spreadsheet Whisperer], + issuer: [Guild of Imaginary Analysts], + date: [Jun 2024], + [Demonstrated advanced spreadsheet whispering and + circular-reference negotiation.], +) +``` + +Finally, print the sections in the desired order: + +```typst +#print-contact +#print-summary +#print-skills +#print-experience +#print-projects +#print-education +#print-certifications +``` + +The data definitions and printed sections are independent, so the output order can be changed without moving the resume data. + +## Configuration + +The `resume.with` function accepts the following options. + +| Option | Default | Description | +| ----------------------- | -------------------- | ----------------------------------------- | +| `contact-info-position` | `left` | Alignment of contact information. | +| `link-color` | `navy` | Colour used for links. | +| `accent-color` | `navy` | Colour used for headings and accents. | +| `font` | `"libertinus serif"` | Font used throughout the document. | +| `font-size` | `11pt` | Base document font size. | +| `line-spacing` | `0.65em` | Paragraph leading. | +| `page-margin` | `0.5in` | Page margin. | +| `list-marker` | `[--]` | Marker used for resume accomplishments. | +| `contacts-separator` | `[/]` | Separator between contact fields. | +| `inline-separator` | `[/]` | Separator between inline metadata fields. | +| `justify` | `true` | Whether paragraph text is justified. | + +## Contact Information + +```typst +#contact-info( + name: [Bramble Quillwhistle], + phone: [+1 (OWL) HOO-HOOT], + email: [bramble@example.invalid], + address: [Moonbeam, Cloudland], + linkedin: [bramble-qw], + github: [bramble-qw], +) +``` + +`name` is required. The other standard contact fields are optional. + +Supported fields include: + +* `phone` +* `email` +* `address` +* `linkedin` +* `github` + +Additional named arguments can be supplied for custom contact fields: + +```typst +#contact-info( + name: [Bramble Quillwhistle], + email: [bramble@example.invalid], + portfolio: [https://example.invalid], +) +``` + +URL values are automatically formatted using their domain as the displayed text. Custom anchors can also be supplied using Typst's `link` function. + +## Summary + +Add a professional summary with `summary`: + +```typst +#summary[ + A concise description of your background, experience, + and professional focus. +] +``` + +## Skills + +Create skill categories with `skillset`: + +```typst +#skillset( + category: [Arcane Machinery], + skills: [WobbleScript, QuantaQL, FluxLogic], +) +``` + +Multiple skill categories can be added independently. + +## Experience + +Add professional experience with `experience`: + +```typst +#experience( + title: [Chief Spreadsheet Cartographer], + company: [Whizzlewick Data], + location: [Moonbeam], + start-date: [Mar 2023], + end-date: [Present], + [Mapped imaginary datasets and uncovered fictional relationships.], + [Built automated data-processing workflows.], +) +``` + +The following arguments are available: + +* `title` +* `company` +* `location` +* `start-date` +* `end-date` +* `new-page` +* Positional accomplishment entries + +Set `new-page: true` to force an entry to begin on a new page: + +```typst +#experience( + title: [Senior Data Enchanter], + company: [Institute of Nonsense], + new-page: true, + [Transformed imaginary datasets into structured analytical records.], +) +``` + +## Projects + +Projects use the `project` function: + +```typst +#project( + name: [Interdimensional Sales Oracle], + info: [WobbleScript, FluxLogic], + start-date: [Jan 2024], + end-date: [Mar 2024], + [Built a predictive model for fictional sales activity.], +) +``` + +Available arguments: + +* `name` +* `info` +* `start-date` +* `end-date` +* `new-page` +* Positional accomplishment entries + +## Education + +Add education with `education`: + +```typst +#education( + degree: [Master of Computational Whimsy], + school: [Royal Academy of Impossibility], + location: [Starling Valley], + start-date: [Sep 2021], + end-date: [Jun 2023], + gpa: [4.87], + coursework: [Nonsense Theory, Imaginary Data, Moon Mathematics], +) +``` + +Available arguments: + +* `degree` +* `school` +* `location` +* `start-date` +* `end-date` +* `gpa` +* `coursework` +* `new-page` + +## Certifications + +Add certifications with `certification`: + +```typst +#certification( + name: [Certified Spreadsheet Whisperer], + issuer: [Guild of Imaginary Analysts], + date: [Jun 2024], + [Demonstrated advanced spreadsheet whispering skills.], +) +``` + +Available arguments: + +* `name` +* `issuer` +* `date` +* `new-page` +* Positional highlight entries + +## Output Sections + +Each resume section has a corresponding print function: + +```typst +#print-contact +#print-summary +#print-skills +#print-experience +#print-projects +#print-education +#print-certifications +``` + +These can be placed in any order. For example: + +```typst +#print-contact +#print-summary +#print-experience +#print-skills +#print-education +#print-projects +#print-certifications +``` + +This allows the same resume data to be presented using different section orders without modifying the underlying content. + +## Complete Example + +A complete working example is available in the package [template](template/resume.typ). + +## License + +This project is licensed under the MIT License. See [`LICENSE`](LICENSE) for the full license text. \ No newline at end of file diff --git a/packages/preview/resumetyp/0.1.0/banner.png b/packages/preview/resumetyp/0.1.0/banner.png new file mode 100644 index 0000000000..8ea9ba042b Binary files /dev/null and b/packages/preview/resumetyp/0.1.0/banner.png differ diff --git a/packages/preview/resumetyp/0.1.0/example-resume.pdf b/packages/preview/resumetyp/0.1.0/example-resume.pdf new file mode 100644 index 0000000000..70565667f6 Binary files /dev/null and b/packages/preview/resumetyp/0.1.0/example-resume.pdf differ diff --git a/packages/preview/resumetyp/0.1.0/example-resume.png b/packages/preview/resumetyp/0.1.0/example-resume.png new file mode 100644 index 0000000000..8ad4207f16 Binary files /dev/null and b/packages/preview/resumetyp/0.1.0/example-resume.png differ diff --git a/packages/preview/resumetyp/0.1.0/src/lib.typ b/packages/preview/resumetyp/0.1.0/src/lib.typ new file mode 100644 index 0000000000..5354a7fbb2 --- /dev/null +++ b/packages/preview/resumetyp/0.1.0/src/lib.typ @@ -0,0 +1 @@ +#import "resumetyp.typ": resume, contact-info, summary, skillset, experience, project, education, certification, print-contact, print-summary, print-skills, print-experience, print-projects, print-education, print-certifications \ No newline at end of file diff --git a/packages/preview/resumetyp/0.1.0/src/resumetyp.typ b/packages/preview/resumetyp/0.1.0/src/resumetyp.typ new file mode 100644 index 0000000000..e3a09db547 --- /dev/null +++ b/packages/preview/resumetyp/0.1.0/src/resumetyp.typ @@ -0,0 +1,386 @@ + +// DATA STATES +#let resume-name = state("resume-name") +#let resume-summary = state("resume-summary") +#let resume-contact = state("resume-contact", ()) +#let resume-skills = state("resume-skills", ()) +#let resume-experiences = state("resume-experiences", ()) +#let resume-projects = state("resume-projects", ()) +#let resume-education = state("resume-education", ()) +#let resume-certifications = state("resume-certifications", ()) + +// CONFIG STATES +#let resume-inline-separator = state("inline-separator", []) +#let resume-contacts-separator = state("contacts-separator", []) + +// TEMPLATE CONFIG +#let resume( + contact-info-position: left, + link-color: navy, + accent-color: navy, + font: "libertinus serif", + font-size: 11pt, + line-spacing: 0.65em, + page-margin: 0.5in, + list-marker: [--], + contacts-separator: [\/], + inline-separator: [\/], + justify: true, + doc +) = { + set page(margin: page-margin) + set par(justify: justify) + set par(leading: line-spacing) + set text(size: font-size, font: font) + set list(marker: list-marker) + + show link: set text(link-color) + show title: set text(accent-color) + show heading: set text(accent-color) + show heading: set text(weight: "regular") + show heading: it => { + pad(top: 0pt, bottom: -10pt, [#smallcaps[#it.body]]) + line(length: 100%, stroke: 0.5pt) + } + show : set align(contact-info-position) + show : set text(accent-color) + + context resume-inline-separator.update(_ => inline-separator) + context resume-contacts-separator.update(_ => contacts-separator) + doc +} + + +// HELPER FUNCTIONS +#let is-url(item) = { + type(item) == str and ( + item.starts-with("https://") or + item.starts-with("http://") + ) +} + +#let url-domain(url) = { + let url = if url.starts-with("https://") { + url.slice(8) + } else if url.starts-with("http://") { + url.slice(7) + } else { + url + } + + let domain = url.split("/").at(0) + + if domain.starts-with("www.") { + domain.slice(4) + } else { + domain + } +} + +#let to-string(it) = { + if type(it) == str { + it + } else if type(it) != content { + str(it) + } else if it.has("text") { + it.text + } else if it.has("children") { + it.children.map(to-string).join() + } else if it.has("body") { + to-string(it.body) + } else if it == [ ] { + " " + } +} + +#let link-formatter(url, content) = { + link(to-string(url))[#content] +} + + +#let contact-formatters = ( + email: (item, type) => + link-formatter( + "mailto:" + item, + item, + ), + phone: (item, type) => + link-formatter( + "tel:" + item, + item, + ), + linkedin: (item, type) => + link-formatter( + "https://linkedin.com/in/" + item, + [linkedin/#item], + ), + github: (item, type) => + link-formatter( + "https://github.com/" + item, + [github/#item], + ), + default: (item, type) => { + if is-url(item) { + link-formatter( + item, + [#type/#url-domain(item)], + ) + } else { + item + } + }, +) + +#let format-item(item, type) = { + contact-formatters + .at(type, default: contact-formatters.default)(item, type) +} + +#let upsert(items, key, value) = { + let result = items.filter(entry => entry.at(0) != key) + result.push((key, value)) + result +} + +#let inline-separator = {context resume-inline-separator.get()} + +#let resume-section(title, body) = { + block[ + == #title + #body + ] +} + +// DATA SETTER FUNCTIONS +#let contact-info( + name: [], + phone: none, + email: none, + address: none, + linkedin: none, + github: none, + ..args +) = { + resume-name.update(_ => upper(name)) + let contact-items = () + if phone != none [#contact-items.push(("phone", phone))] + if email != none [#contact-items.push(("email", email))] + if address != none [#contact-items.push(("address", address))] + if linkedin != none [#contact-items.push(("linkedin", linkedin))] + if github != none [#contact-items.push(("github", github))] + for arg in args.named() [#contact-items.push(arg)] + for (type, item) in contact-items [ + #context resume-contact.update(items => + upsert(items, type, item) + ) + ] +} + +#let summary(content) = { + resume-summary.update(_ => content) +} + +#let skillset(category:"", skills:"") = { + resume-skills.update(entries => { + entries + ( + ( + category: category, + skills: skills, + ), + ) + }) +} + +#let experience( + title: [], + company: none, + location: none, + start-date: none, + end-date: none, + new-page: false, + ..accomplishments +) = { + resume-experiences.update(entries => { + entries + ( + ( + title: title, + company: company, + location: location, + start-date: start-date, + end-date: end-date, + new-page: new-page, + accomplishments: accomplishments.pos(), + ), + ) + }) +} + +#let project( + name: [], + start-date: none, + end-date: none, + info: none, + new-page: false, + ..accomplishments, +) = { + resume-projects.update(entries => { + entries + ( + ( + name: name, + start-date: start-date, + end-date: end-date, + info: info, + new-page: new-page, + accomplishments: accomplishments.pos(), + ), + ) + }) +} + +#let education( + degree: [], + school: none, + location: none, + start-date: none, + end-date: none, + gpa: none, + coursework: none, + new-page: false, +) = { + resume-education.update(entries => { + entries + ( + ( + degree: degree, + school: school, + location: location, + start-date: start-date, + end-date: end-date, + gpa: gpa, + coursework: coursework, + new-page: new-page, + ), + ) + }) +} + +#let certification( + name:[], + issuer:none, + date:none, + new-page: false, + ..highlights +) = { + resume-certifications.update(entries => { + entries + ( + ( + name: name, + issuer: issuer, + date: date, + new-page: new-page, + highlights: highlights.pos() + ), + ) + }) +} + +// PRINT FUNCTIONS +#let print-contact = [ + #title[#context resume-name.get()] + #context { + resume-contact.get() + .map(entry => format-item(entry.at(1), entry.at(0))) + .join([#resume-contacts-separator.get()]) + } +] + +#let print-summary = { + resume-section("Summary", context {resume-summary.get()}) +} + +#let print-skills = { + resume-section("Skills", + context { + table( + columns: (auto, 1fr), + column-gutter: 1em, + row-gutter: par.leading, + stroke: none, + inset: (0pt), + ..resume-skills.get() + .map(entry => ( + [#strong[#entry.category]], + [#entry.skills], + )) + .flatten(), + ) + }) +} + +#let print-experience = { + resume-section("Experiences", + context{ + for entry in resume-experiences.get() [ + #if entry.new-page [#colbreak()] + #strong[#entry.title]#if entry.company != none [#inline-separator#entry.company]#if entry.location != none [#inline-separator#entry.location] + #h(1fr) + *#entry.start-date + #if entry.start-date != none and entry.end-date != none [ -- ] + #entry.end-date* + #for accomplishment in entry.accomplishments [ + - #accomplishment + ] + ] + }) +} + +#let print-projects = { + resume-section("Projects", + context{ + for entry in resume-projects.get() [ + #if entry.new-page [#colbreak()] + #strong[#entry.name]#if entry.info != none [#inline-separator#entry.info] + #h(1fr) + *#entry.start-date + #if entry.start-date != none and entry.end-date != none [ -- ] + #entry.end-date* + #for accomplishment in entry.accomplishments [ + - #accomplishment + ] + ] + }) +} + +#let print-education = { + resume-section("Education", + context{ + let entries = resume-education.get() + for (i, entry) in entries.enumerate() [ + #if entry.new-page [#colbreak()] + #strong[#entry.degree]#if entry.school != none [#inline-separator#entry.school]#if entry.location != none [#inline-separator#entry.location] + #h(1fr) + *#entry.start-date + #if entry.start-date != none and entry.end-date != none [ -- ] + #entry.end-date* \ + #if entry.gpa != none [ + _*GPA* — #entry.gpa _ + ]#if entry.gpa != none and entry.coursework != none [#inline-separator]#if entry.coursework != none [_*Coursework* — #entry.coursework _] + #if i < entries.len() - 1 [ + #v(1pt) + ] + ] + }) +} + +#let print-certifications = { + resume-section("Certifications", + context{ + let entries = resume-certifications.get() + for (i, entry) in entries.enumerate() [ + #if entry.new-page [#colbreak()] + #strong[#entry.name]#if (entry.issuer != none) [#inline-separator#entry.issuer]#if entry.date != none [#h(1fr)*#entry.date*] + #for highlight in entry.highlights [ + - #highlight + ] + ] + }) +} \ No newline at end of file diff --git a/packages/preview/resumetyp/0.1.0/template/resume.typ b/packages/preview/resumetyp/0.1.0/template/resume.typ new file mode 100644 index 0000000000..f7ded3283f --- /dev/null +++ b/packages/preview/resumetyp/0.1.0/template/resume.typ @@ -0,0 +1,213 @@ + +#import "@preview/resumetyp:0.1.0": * + +#show: resume.with( + contact-info-position: center, + contacts-separator: [#h(0.45em)◆#h(0.45em)], + inline-separator: [#h(0.35em)/#h(0.35em)], + link-color: rgb("#B5651D"), + accent-color: rgb("#654321"), + font: "Libertinus Serif", + font-size: 11pt, + line-spacing: 0.65em, + page-margin: 0.5in, + list-marker: [--], + justify: true, +) + +// -------------------------------------------------------------------------------- +// CONTACT INFORMATION +// -------------------------------------------------------------------------------- +// Contact fields are optional except for name. +// LinkedIn/GitHub accept usernames; additional named arguments can be used +// for custom contact fields or URLs. See the examples below. +#contact-info( + name: [Bramble Quillwhistle], + phone: [+1 (OWL) HOO-HOOT], + email: [bramble\@whiffmail.invalid], + address: [Moonbeam, Cloudland], + linkedin: [bramble-qw], + // github: [username], + // arbitrary-url: "https://www.url.com", + // url-with-custom-anchor: [#link("url")[anchor]], + // arbitrary-key: [arbitrary-value], +) + + + +// -------------------------------------------------------------------------------- +// PROFESSIONAL SUMMARY +// -------------------------------------------------------------------------------- +#summary[ + #strong[Quantum Spreadsheet Cartographer] experienced in mapping + imaginary datasets, taming semi-sentient spreadsheets, and turning + complicated business riddles into questionable charts. +] + + +// -------------------------------------------------------------------------------- +// SKILLS +// -------------------------------------------------------------------------------- +#skillset( + category: [Arcane Machinery], + skills: [WobbleScript, QuantaQL, HyperCalc, FluxLogic, ByteWhistling] +) + +#skillset( + category: [Mystical Data], + skills: [Moon Mapping, Data Alchemy, Pattern Sculpting, Cloud Analytics] +) + +#skillset( + category: [Vision Sorcery], + skills: [Dream Charts, Hologram Tables, Orbital Graphs, Nebula Plotting] +) + +#skillset( + category: [Goblin Automation], + skills: [Auto-Wrangling, Clockwork Pipelines, GoblinOps] +) + + +// -------------------------------------------------------------------------------- +// WORK EXPERIENCE +// -------------------------------------------------------------------------------- +// Set `new-page: true` to force this entry to start on a new page. +#experience( + title: [Chief Spreadsheet Cartographer], + company: [Whizzlewick Data], + location: [Moonbeam, Cloudland], + start-date: [Mar 2023], + end-date: [Present], + [Mapped 7.4 million imaginary records, uncovering 842 relationships + between teacup capacity and quarterly moon phases.], + [Designed a #emph[WobbleScript] engine that converted chaotic datasets + into perfectly rectangular tables.], + [Reduced spreadsheet turbulence by 73% using predictive cell alignment + and emotionally supportive formulas.], + [Presented findings to department heads, automated calculators, + and one highly skeptical office fern.] +) + +#experience( + title: [Junior Data Enchanter], + company: [Institute of Nonsense], + location: [Pebblewick, Cloudland], + start-date: [Jun 2021], + end-date: [Feb 2023], + [Processed 480,000 synthetic moon records using #emph[QuantaQL].], + [Built #emph[FluxLogic] pipelines for transforming numerical artifacts + into structured analytical scrolls.], + [Created #emph[Nebula Plotting] visualizations for imaginary + commercial phenomena.], + [Purified datasets by removing corrupted numbers, rogue decimals, + and one particularly troublesome number 47.] +) + +#experience( + title: [Apprentice Pixel Mechanic], + company: [Bumblebyte], + location: [Tinkerbell Plains], + start-date: [May 2020], + end-date: [Aug 2020], + [Maintained experimental computing contraptions for fictional + customer transactions.], + [Developed #emph[ByteWhistling] routines to automate numerical + operations and summon dormant calculators.], + [Investigated anomalous output from legacy computational machinery.] +) + +// -------------------------------------------------------------------------------- +// PROJECTS +// -------------------------------------------------------------------------------- +// Set `new-page: true` to force this entry to start on a new page. +#project( + name: [Interdimensional Sales Oracle], + info: [WobbleScript, FluxLogic, Nebula Plotting], + start-date: [Jan 2024], + end-date: [Mar 2024], + [Predicted fictional sales across twelve dimensions using + historical sandwich observations.] +) + +#project( + name: [Automated Dragon Census], + info: [QuantaQL, HyperCalc, Cloud Mapping], + start-date: [Sep 2023], + end-date: [Nov 2023], + [Catalogued imaginary dragons by wing geometry, treasure preference, + nap duration, and suspiciousness.] +) + +#project( + name: [The Infinite Spreadsheet], + info: [Dream Charts, Auto-Wrangling, GoblinOps], + start-date: [Apr 2023], + end-date: [Jun 2023], + [Created a spreadsheet engine capable of generating tables that + continuously expand without reaching the bottom row.] +) + +// -------------------------------------------------------------------------------- +// EDUCATION +// -------------------------------------------------------------------------------- +// Set `new-page: true` to force this entry to start on a new page. +#education( + degree: [Master of Computational Whimsy], + school: [Royal Academy of Impossibility], + location: [Starling Valley], + start-date: [Sep 2021], + end-date: [Jun 2023], + gpa: [4.87], + coursework: [ + Nonsense Theory, + Computational Daydreaming, + Imaginary Data, + Moon Mathematics + ] +) + +#education( + degree: [Bachelor of Numerical Wizardry], + school: [University of Tuesdays], + location: [Bramblemoor], + start-date: [Sep 2017], + end-date: [Apr 2021], + gpa: [4.42], + coursework: [ + Enchanted Algorithms, + Numerical Spellcraft, + Calculator Theory + ], +) + +// -------------------------------------------------------------------------------- +// CERTIFICATIONS +// -------------------------------------------------------------------------------- +// Set `new-page: true` to force this entry to start on a new page. +#certification( + name: [Certified Spreadsheet Whisperer], + issuer: [Guild of Imaginary Analysts], + date: [Jun 2024], + [Demonstrated advanced spreadsheet whispering and circular-reference + negotiation.] +) + +#certification( + name: [GoblinOps Practitioner], + issuer: [Institute of Goblin Engineering], + date: [Feb 2024], + [Completed training in goblin coordination, recursive paperwork, + and distributed snack allocation.] +) + + +// Sections can be reorder freely +// without needing to reorder data above +#print-contact +#print-summary +#print-skills +#print-experience +#print-projects +#print-education +#print-certifications diff --git a/packages/preview/resumetyp/0.1.0/typst.toml b/packages/preview/resumetyp/0.1.0/typst.toml new file mode 100644 index 0000000000..5871a9b510 --- /dev/null +++ b/packages/preview/resumetyp/0.1.0/typst.toml @@ -0,0 +1,22 @@ +[package] +name = "resumetyp" +version = "0.1.0" +entrypoint = "src/lib.typ" +authors = ["Harsh Kasodariya"] +license = "MIT" +description = "A modular, data-driven resume framework designed to make customization simple." +repository = "https://github.com/harshkaso/resumetyp" +keywords = ["cv", "resume", "ATS", "curriculum vitae", "simple", "minimal", "compact", "customizable", "data"] +categories = ["cv"] +exclude = [ + ".git", + "example-resume.pdf", + "banner.png", + "docs", + ".DS_Store", +] + +[template] +path = "template" +entrypoint = "resume.typ" +thumbnail = "example-resume.png" \ No newline at end of file