* feat: add section heading icons to PDF templates
Add customizable Phosphor icons before section titles in PDF output.
Users can toggle visibility globally via a new "Hide section heading icons"
switch (independent of item-level icons) and customize individual section
icons through the builder sidebar icon picker.
- Add `icon` field to `baseSectionSchema` and `summarySchema`
- Add `hideSectionIcons` to `pageSchema` (defaults to true for backward compat)
- Implement `SectionHeadingIcon` component with heading font-size scaling
- Support "none" sentinel for per-section icon hiding
- Fallback to sensible defaults (briefcase, graduation-cap, etc.) for legacy data
- Add icon picker to builder sidebar sections and custom section dialogs
Closes#2632
* test: add unit tests for section heading icons
- Add tests for getResumeSectionIcon() covering built-in sections,
summary, custom sections, "none" sentinel, and default fallbacks
- Add schema tests for baseSectionSchema icon field, summarySchema icon,
and pageSchema hideSectionIcons default behavior
* refactor: minor updates to icon display
* Update apps/web/locales/es-ES.po
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
---------
Co-authored-by: Amruth Pillai <im.amruth@gmail.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
* fix(pdf): apply custom style fontSize to icon and level indicator sizes
Map fontSize from Icon and Level Indicator custom style slots to Phosphor
icon size and level indicator dimensions, since react-pdf icons ignore
fontSize in favor of the size prop.
* fix: separate global icon and scoped level indicator font sizes
Icon slot fontSize now drives all resume icons plus level display
decorations. Level indicator fontSize overrides only within level display.
Shared sizing logic lives in schema; design sidebar preview uses global rules.
---------
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
* fix(pdf): align textkit line-box and font metrics to browser behaviour
CJK characters in resumes with a tightened typography line-height
(< ~1.4) had their descenders clipped by the next line. Latin glyphs
in the same resume rendered fine. Fixes the visual regression vs the
v5.0.x Puppeteer-based renderer reported in issue #2986 and follow-ups.
The clipping is caused by two independent gaps in @react-pdf/textkit
relative to standard CSS line-box rules:
1. `height(run)` short-circuits to the user-supplied lineHeight and
ignores the run's intrinsic ascent + descent. CSS line-boxes are
spec'd as `max(line-height, content-area)` — when CJK glyphs are
present the content-area is taller than a tightened lineHeight, so
the box must grow. textkit didn't, so the baseline (computed from
the real, larger CJK ascent) sat below the box and the descender
bled into the next line.
2. `ascent / descent / lineGap` are read directly from fontkit's hhea
defaults. For Source Han Sans/Serif (the CJK fallbacks registered
in #3013) hhea is intentionally inflated for legacy Windows GDI
compatibility (1.45 em vs 1.0 em), so even a fixed line-box would
have been excessively tall. Browsers (and the v5.0.x Puppeteer
renderer) read OS/2 sTypoAscender/Descender/LineGap instead, which
are the values the type designers intend for modern shaping.
Both are upstream behaviours of `@react-pdf/textkit`, but waiting for
an upstream release would leave existing users with broken CJK output.
The fix is shipped as a pnpm patch (~30 LOC):
- `resolveTypoMetrics(font)`: prefer OS/2 typo metrics, fall back to
hhea when an OS/2 table is absent (e.g. the StandardFont stand-ins
for Helvetica/Courier/Times). Used by ascent/descent/lineGap so all
height-related calculations stay consistent.
- `height(run)`: `Math.max(lineHeight || 0, intrinsic)` instead of
the original short-circuit, matching CSS line-box rules.
The patch is self-contained: existing Latin-only resumes are
unaffected (IBM Plex Serif's typo metrics equal hhea; Roboto's typo
is slightly smaller, but only changes the rendered line-box for users
who set lineHeight below ~1.17, which already used to clip ascenders
under v5.1.x and now lays out as it would in a browser).
Tooling notes:
- `Dockerfile.dev` copies `patches/` before `pnpm install` so the
dev image build no longer fails on `--frozen-lockfile`. The
production `Dockerfile` already gets it for free via
`turbo prune --docker` (the patch reference in package.json marks
the directory as part of the pruned slice).
- The patch will become a no-op once an equivalent fix lands upstream
in @react-pdf/textkit; the entry can then be removed from
`pnpm.patchedDependencies` and the file deleted.
* fix(deps): regenerate lockfile and move patchedDependencies for pnpm 11
The previous commit's lockfile was authored by pnpm 8 (lockfileVersion 6.0)
and kept patchedDependencies under package.json#pnpm. The repository now
declares packageManager: pnpm@11.1.2, which:
- writes lockfileVersion 9.0 and rejects v6 with ERR_PNPM_LOCKFILE_BREAKING_CHANGE
on --frozen-lockfile (CI failure observed in autofix.ci);
- reads pnpm settings from pnpm-workspace.yaml, silently ignoring the
package.json#pnpm field — so the textkit patch was no longer applied.
Regenerate pnpm-lock.yaml with pnpm 11.1.2 and move patchedDependencies
to pnpm-workspace.yaml so the patch is applied and CI passes.
* chore: update dependencies
---------
Co-authored-by: Amruth Pillai <im.amruth@gmail.com>