From f7afdb7f5c57f078c6f2685d3b1ab15ac9fcb3c4 Mon Sep 17 00:00:00 2001 From: Shane Murphy Date: Fri, 12 Jun 2026 17:56:39 +0200 Subject: [PATCH 1/2] feat: add preferences.anonymous for blind-review mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Enables a single-toggle blind-review render: the header drops basics.name, basics.image, and the contact bar; basics.label (when present) becomes the sole header line. PDF metadata title and author are swapped for the placeholder "Candidate" so the file itself cannot unmask the candidate via its document properties. All other sections render normally — same data dict, same compile command, single toggle. Closes #55 --- README.md | 1 + lib.typ | 194 ++++++++++++++++++++++++++------------------ tests/anonymous.typ | 56 +++++++++++++ 3 files changed, 172 insertions(+), 79 deletions(-) create mode 100644 tests/anonymous.typ diff --git a/README.md b/README.md index c0cc9c8..09346dc 100644 --- a/README.md +++ b/README.md @@ -281,6 +281,7 @@ Every theme, font, layout, and behaviour knob lives in `preferences`. Override a | `uppercaseName` | `true` | When `true` (the default — matching AltaCV's visual ancestor), `basics.name` renders in uppercase. Set to `false` to render the name as supplied. Useful for scripts where uppercase is a different glyph set (Turkish dotless-i, etc.), scripts that have no case at all, or simply when the loud uppercase look isn't wanted. | | `lastModifiedFooter` | `false` | When `true` and `meta.lastModified` is set, renders a small right-aligned `Last updated: ` line in the page footer. The label text is localisable via `labels.lastModified`; the timestamp is rendered as supplied (the full ISO 8601 string flows through verbatim). PDF metadata (date / keywords / description) is enriched from `meta` / `basics` independently of this flag — see [PDF metadata](#pdf-metadata). | | `dateFormat` | `"long"` | How ISO 8601 date strings (`"2024"`, `"2024-06"`, `"2024-06-15"` — the three shapes the [JSON Resume `iso8601` definition](https://github.com/jsonresume/resume-schema/blob/master/schema.json) accepts) are rendered wherever the template surfaces a date (`startDate`, `endDate`, `awards[].date`, `publications[].releaseDate`, …). Non-ISO strings (e.g. `"Jan 2022"`, `"May 2016 – Jul 2017"`) always pass through verbatim regardless of this setting — back-compat with pre-formatted data. Accepted values: `"long"` (`"Jun 2024"` / `"15 Jun 2024"`, month names sourced from `labels.months`), `"short"` (`"06/2024"` / `"15/06/2024"`), `"iso"` (passthrough), **a bracketed template** in [Typst's `datetime.display()` syntax](https://typst.app/docs/reference/foundations/datetime/#definitions-display) (e.g. `"[day padding:none] [month repr:short] [year]"` → `"15 Jun 2024"`; supported tokens are `year`/`month`/`day` with `padding:` and `repr:long`/`repr:short`/`repr:numerical` modifiers, with `month repr:long`/`repr:short` reading from `labels.months` so they localise), or a closure `parts => str` receiving a `(year, month, day)` dict (`month` and `day` are `none` for year-only / year-month inputs). | +| `anonymous` | `false` | Blind-review mode. When `true`, the rendered header drops `basics.name`, `basics.image`, and the contact bar entirely; `basics.label` (when present) becomes the sole header line. PDF metadata `title` and `author` are swapped for the generic placeholder `"Candidate"`, and the `keywords` / `description` fields are suppressed so the file itself can't unmask the candidate via its document properties. Every other section renders normally — same data dict, same compile command, single toggle. | | `linkContactInfo` | `true` | Controls whether contact-bar entries are wrapped in deep links (`mailto:`, `tel:`, the configured maps URL for location — see `mapsProvider`, the supplied URL for `basics.url` and for each profile). Accepts a **boolean** (`true` / `false`, applied uniformly to every channel) or a **partial dict** keyed by channel — `"email"`, `"phone"`, `"location"`, `"url"`, `"profiles"` — so you can opt out per channel without touching the data. E.g. `linkContactInfo: (phone: false)` keeps email / location / homepage / profile links but renders the phone as plain text. Omitted channels stay linked; unknown channel keys panic. | | `mapsProvider` | `maps-providers.google` | URL template for the `basics.location` deep link. The `{q}` placeholder is replaced with the URL-encoded location at render time. Use a built-in template — `maps-providers.{google,apple,bing,duckduckgo,osm}`, all exported from the module — or pass any other URL template string for a provider that isn't built in (no code change required). Pass `none` to suppress the link entirely (icon + plain text still render). Strings missing `{q}` panic; non-string / non-`none` values panic. | | `columnRatio` | `0.65` | Left-column width as a fraction of the page, in `(0, 1]`. The right column gets the remainder minus a fixed gutter. Use the complement (`1 - r`) to invert the layout, or set to `1` for a [single-column layout](#single-column-layout). | diff --git a/lib.typ b/lib.typ index 0e7df5c..4cbd175 100644 --- a/lib.typ +++ b/lib.typ @@ -661,6 +661,7 @@ link-contact-info: true, maps-provider: maps-providers.google, uppercase-name: true, + anonymous: false, ) = { if image-position not in ("left", "right", "center") { panic("imagePosition must be \"left\", \"right\", or \"center\", got: " + repr(image-position)) @@ -687,16 +688,21 @@ let accent = _accent_state.get() let header-text = align(text-align, { - block( - spacing: 0pt, - below: 1.2 * body-size, - text( - 2.5 * body-size, - fill: accent, - weight: "bold", - if uppercase-name { upper(basics.name) } else { basics.name }, - ), - ) + // Anonymous mode skips the name block entirely — the label + // (when present) becomes the sole header line, so role-relevant + // signal survives while identifying detail is dropped. + if not anonymous { + block( + spacing: 0pt, + below: 1.2 * body-size, + text( + 2.5 * body-size, + fill: accent, + weight: "bold", + if uppercase-name { upper(basics.name) } else { basics.name }, + ), + ) + } if "label" in basics and basics.label != none { block( @@ -709,71 +715,77 @@ set text(0.8 * body-size, weight: "bold") let bar-icon = icon.with(size: 0.9 * body-size, shift: 0.2 * body-size, fill: accent) + // Anonymous mode suppresses the contact bar wholesale — every + // channel (email, phone, location, url, profiles) carries + // identifying signal, so the safe default is to drop them all + // rather than pick winners. let entries = () - let email = basics.at("email", default: none) - if email != none { - entries.push(( - channel: "email", - icon: "email", - value: email, - url: "mailto:" + email, - )) - } - let phone = basics.at("phone", default: none) - if phone != none { - // Strip RFC 3966 visual separators (spaces, parens, hyphens, dots) - // from the dialable URI; the displayed value keeps them intact. - let dialable = phone.replace(regex("[\s()\-.]"), "") - entries.push(( - channel: "phone", - icon: "phone", - value: phone, - url: "tel:" + dialable, - )) - } - // `_format_location` collapses the JSON Resume dict form - // `{address, postalCode, city, countryCode, region}` to a - // single line, leaves an already-flat string untouched, and - // returns `none` when every relevant field is empty. Both the - // display value and the maps deep link are fed from the same - // result so they cannot drift. - let location = _format_location(basics.at("location", default: none)) - if location != none { - let url = if maps-provider == none { none } else { - maps-provider.replace("{q}", _url_encode(location)) + if not anonymous { + let email = basics.at("email", default: none) + if email != none { + entries.push(( + channel: "email", + icon: "email", + value: email, + url: "mailto:" + email, + )) } - entries.push(( - channel: "location", - icon: "location", - value: location, - url: url, - )) - } - let url = basics.at("url", default: none) - if url != none { - entries.push(( - channel: "url", - icon: "link", - value: url, - url: url, - )) - } - for profile in basics.at("profiles", default: ()) { - let raw = lower(profile.network) - let network = _network_aliases.at(raw, default: raw) - if network not in _profile_networks { - panic( - "Unknown profile network: " + repr(profile.network) - + ". Supported: " + _profile_networks.join(", ") - + ". To add another, vendor its SVG into icons/ and register it in _network_icon_sources.", - ) + let phone = basics.at("phone", default: none) + if phone != none { + // Strip RFC 3966 visual separators (spaces, parens, hyphens, dots) + // from the dialable URI; the displayed value keeps them intact. + let dialable = phone.replace(regex("[\s()\-.]"), "") + entries.push(( + channel: "phone", + icon: "phone", + value: phone, + url: "tel:" + dialable, + )) + } + // `_format_location` collapses the JSON Resume dict form + // `{address, postalCode, city, countryCode, region}` to a + // single line, leaves an already-flat string untouched, and + // returns `none` when every relevant field is empty. Both the + // display value and the maps deep link are fed from the same + // result so they cannot drift. + let location = _format_location(basics.at("location", default: none)) + if location != none { + let url = if maps-provider == none { none } else { + maps-provider.replace("{q}", _url_encode(location)) + } + entries.push(( + channel: "location", + icon: "location", + value: location, + url: url, + )) + } + let url = basics.at("url", default: none) + if url != none { + entries.push(( + channel: "url", + icon: "link", + value: url, + url: url, + )) + } + for profile in basics.at("profiles", default: ()) { + let raw = lower(profile.network) + let network = _network_aliases.at(raw, default: raw) + if network not in _profile_networks { + panic( + "Unknown profile network: " + repr(profile.network) + + ". Supported: " + _profile_networks.join(", ") + + ". To add another, vendor its SVG into icons/ and register it in _network_icon_sources.", + ) + } + entries.push(( + channel: "profiles", + icon: network, + value: profile.at("username", default: profile.at("url", default: "")), + url: profile.url, + )) } - entries.push(( - channel: "profiles", - icon: network, - value: profile.at("username", default: profile.at("url", default: "")), - url: profile.url, - )) } // Each entry is wrapped in `box(...)` so the icon and its @@ -800,11 +812,13 @@ // Anything else panics with a clear message instead of falling // through to a cryptic `image()` failure or — worse — silently // dropping the photo (which is what an empty array would do under - // a bare `.len()` check). + // a bare `.len()` check). Anonymous mode forces the portrait off + // even when `basics.image` is supplied — validation still runs so + // a malformed value can't slip through unnoticed via the flag. let has-image = if image-src == none { false } else if type(image-src) in (str, bytes) { - image-src.len() > 0 + not anonymous and image-src.len() > 0 } else { panic( "basics.image must be a string path or bytes, got: " + repr(image-src), @@ -1349,6 +1363,12 @@ // "iso" — passthrough of the original string // closure — (parts) -> str, where parts is (year, month?, day?) dateFormat: "long", + // Blind-review mode: redacts name, photo, and contact bar from the + // rendered header, and overrides PDF metadata `author` with a + // generic placeholder so the document itself doesn't leak identity. + // The label (e.g. "Senior Software Engineer") still renders, as do + // all other sections — only the identifying header surface is dropped. + anonymous: false, // Fraction in (0, 1] (validated in alta()). Use the complement // (`1 - r`) and swap the column-section arrays to invert the layout; // exactly 1 collapses the grid to a single full-width column. @@ -1452,6 +1472,11 @@ "labels.months must be an array of 12 strings, got: " + repr(months), ) } + if type(preferences.anonymous) != bool { + panic( + "anonymous must be a bool, got: " + repr(preferences.anonymous), + ) + } let accent = preferences.accent let body-size = preferences.bodySize _accent_state.update(accent) @@ -1464,15 +1489,25 @@ // rejects `none` for `date`, and emitting empty strings for // `description` / `keywords` would still write a present-but-empty // entry. + // + // `uppercaseName` is purely visual — PDF metadata stays canonical. + // + // `anonymous` flips the title and author into generic placeholders + // and suppresses the keyword / description fields so the file itself + // can't unmask the candidate via its metadata (a blind reviewer who + // saved the PDF would otherwise see the real name in their reader's + // "document properties" pane, and the description / keywords would + // surface basics.summary and the skill keywords verbatim). let meta = cv.at("meta", default: (:)) let last-modified-raw = meta.at("lastModified", default: none) let doc-date = _iso_datetime(last-modified-raw) - let doc-keywords = _collect_keywords(cv.at("skills", default: ())) - let doc-description = cv.basics.at("summary", default: none) + let doc-title = if preferences.anonymous { "Candidate --- CV" } else { cv.basics.name + " --- CV" } + let doc-author = if preferences.anonymous { "Candidate" } else { cv.basics.name } + let doc-keywords = if preferences.anonymous { () } else { _collect_keywords(cv.at("skills", default: ())) } + let doc-description = if preferences.anonymous { none } else { cv.basics.at("summary", default: none) } set document( - // `uppercaseName` is purely visual — PDF metadata stays canonical. - title: cv.basics.name + " --- CV", - author: cv.basics.name, + title: doc-title, + author: doc-author, ..(if doc-keywords.len() > 0 { (keywords: doc-keywords) } else { (:) }), ..(if _present(doc-description) { (description: doc-description) } else { (:) }), ..(if doc-date != none { (date: doc-date) } else { (:) }), @@ -1546,6 +1581,7 @@ link-contact-info: preferences.linkContactInfo, maps-provider: preferences.mapsProvider, uppercase-name: preferences.uppercaseName, + anonymous: preferences.anonymous, ) _summary(cv.basics) diff --git a/tests/anonymous.typ b/tests/anonymous.typ new file mode 100644 index 0000000..0b54ba3 --- /dev/null +++ b/tests/anonymous.typ @@ -0,0 +1,56 @@ +// `preferences.anonymous: true` enables blind-review mode: the +// rendered header drops the name, photo, and contact bar, leaving +// only the label as the leading line. PDF metadata `title` and +// `author` are swapped for generic placeholders so the file itself +// can't unmask the candidate via its document properties. +// +// Three documents exercise the relevant shapes: +// +// 1. Anonymous on, fully-populated basics — name / photo / +// contact bar should all be suppressed; label remains. +// 2. Anonymous on, no `label` — header collapses to nothing +// (summary + sections still render). +// 3. Anonymous off (default, asserted explicitly) — every +// identifying field renders normally. + +#import "../lib.typ": alta + +#let cv = ( + basics: ( + name: "Jane Doe", + label: "Senior Software Engineer", + summary: [Backend engineer with eight years' experience.], + email: "jane@example.com", + phone: "+353 1 555 0100", + location: "Dublin, Ireland", + url: "https://janedoe.dev", + profiles: ( + (network: "GitHub", username: "janedoe", url: "https://github.com/janedoe"), + ), + ), + work: ( + ( + name: "Acme Corp", + position: "Senior Software Engineer", + startDate: "Jan 2022", + highlights: ([Led the platform migration.],), + ), + ), +) + +#alta(cv, preferences: (anonymous: true)) + +#pagebreak() + +#alta( + (basics: ( + name: "Jane Doe", + email: "jane@example.com", + phone: "+353 1 555 0100", + )), + preferences: (anonymous: true), +) + +#pagebreak() + +#alta(cv, preferences: (anonymous: false)) From adcc661c8ba8d2303c39f95f8b324f88428691d1 Mon Sep 17 00:00:00 2001 From: Shane Murphy Date: Sun, 14 Jun 2026 11:00:40 +0200 Subject: [PATCH 2/2] chore: regenerate examples/tests/*.pdf --- examples/tests/anonymous.pdf | Bin 0 -> 38491 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 examples/tests/anonymous.pdf diff --git a/examples/tests/anonymous.pdf b/examples/tests/anonymous.pdf new file mode 100644 index 0000000000000000000000000000000000000000..6d85fc3ce0b1f16782534965258af15ab75e53ae GIT binary patch literal 38491 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