jekyll-theme-resume 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/403.html +6 -0
- data/404.html +6 -0
- data/500.html +6 -0
- data/CHANGELOG.md +498 -0
- data/CODE_OF_CONDUCT.md +92 -0
- data/LICENSE.txt +22 -0
- data/README.md +184 -0
- data/SECURITY.md +30 -0
- data/_config.sample.yml +329 -0
- data/_data/locales/ar.yml +85 -0
- data/_data/locales/de.yml +86 -0
- data/_data/locales/en.yml +84 -0
- data/_data/locales/es.yml +86 -0
- data/_data/locales/fr.yml +86 -0
- data/_data/locales/ur.yml +86 -0
- data/_data/social_networks.yml +83 -0
- data/_includes/analytics-body.html +12 -0
- data/_includes/analytics-head.html +36 -0
- data/_includes/avatar.html +84 -0
- data/_includes/dark-mode-toggle.html +202 -0
- data/_includes/data-loader.html +42 -0
- data/_includes/date-formatter.html +63 -0
- data/_includes/grouped-item-list.html +53 -0
- data/_includes/hreflang.html +58 -0
- data/_includes/language-switcher.html +72 -0
- data/_includes/print-social-links.html +23 -0
- data/_includes/resume-section.html +547 -0
- data/_includes/safe-url.html +21 -0
- data/_includes/shared-head.html +51 -0
- data/_includes/social-links.html +54 -0
- data/_includes/vendors/svg-icons/ATTRIBUTION.md +34 -0
- data/_includes/vendors/svg-icons/dev.svg +3 -0
- data/_includes/vendors/svg-icons/dribbble-symbol.svg +3 -0
- data/_includes/vendors/svg-icons/envelope.svg +4 -0
- data/_includes/vendors/svg-icons/facebook.svg +3 -0
- data/_includes/vendors/svg-icons/flickr.svg +4 -0
- data/_includes/vendors/svg-icons/github.svg +3 -0
- data/_includes/vendors/svg-icons/globe-1.svg +3 -0
- data/_includes/vendors/svg-icons/instagram.svg +4 -0
- data/_includes/vendors/svg-icons/linkedin.svg +3 -0
- data/_includes/vendors/svg-icons/medium.svg +3 -0
- data/_includes/vendors/svg-icons/phone.svg +13 -0
- data/_includes/vendors/svg-icons/pinterest.svg +3 -0
- data/_includes/vendors/svg-icons/postcard.svg +14 -0
- data/_includes/vendors/svg-icons/telegram.svg +3 -0
- data/_includes/vendors/svg-icons/whatsapp.svg +3 -0
- data/_includes/vendors/svg-icons/x.svg +3 -0
- data/_includes/vendors/svg-icons/youtube.svg +3 -0
- data/_layouts/default.html +65 -0
- data/_layouts/error.html +138 -0
- data/_layouts/profile.html +123 -0
- data/_layouts/resume.html +238 -0
- data/_plugins/error_pages_generator.rb +71 -0
- data/_plugins/json_resume_generator.rb +79 -0
- data/_plugins/resume_pages_generator.rb +71 -0
- data/_plugins/resume_validator.rb +40 -0
- data/_sass/_all-pages.scss +335 -0
- data/_sass/_base.scss +130 -0
- data/_sass/_dark-mode.scss +387 -0
- data/_sass/_layout.scss +116 -0
- data/_sass/_mixins.scss +136 -0
- data/_sass/_normalize.scss +379 -0
- data/_sass/_profile-page.scss +60 -0
- data/_sass/_resume-ltr.scss +436 -0
- data/_sass/_resume-rtl.scss +91 -0
- data/_sass/_variables.scss +45 -0
- data/assets/css/cv-ltr.scss +31 -0
- data/assets/css/cv-rtl.scss +36 -0
- data/assets/css/main.scss +8 -0
- data/assets/css/profile.scss +9 -0
- data/assets/favicon/resume/about.txt +6 -0
- data/assets/favicon/resume/android-chrome-192x192.png +0 -0
- data/assets/favicon/resume/android-chrome-512x512.png +0 -0
- data/assets/favicon/resume/apple-touch-icon.png +0 -0
- data/assets/favicon/resume/favicon-16x16.png +0 -0
- data/assets/favicon/resume/favicon-32x32.png +0 -0
- data/assets/favicon/resume/favicon.ico +0 -0
- data/assets/favicon/resume/site.webmanifest +1 -0
- data/bin/validate-resume +89 -0
- data/bin/verify +27 -0
- data/docs/README.md +89 -0
- data/docs/explanation/accessibility-decisions.md +27 -0
- data/docs/explanation/architecture.md +44 -0
- data/docs/explanation/dark-mode-approach.md +25 -0
- data/docs/explanation/data-driven-model.md +25 -0
- data/docs/explanation/multilingual-and-rtl-design.md +40 -0
- data/docs/how-to/add-a-language.md +57 -0
- data/docs/how-to/add-a-section.md +35 -0
- data/docs/how-to/add-a-social-platform.md +32 -0
- data/docs/how-to/add-a-test.md +34 -0
- data/docs/how-to/create-a-custom-layout.md +64 -0
- data/docs/how-to/enable-dark-mode.md +43 -0
- data/docs/how-to/link-translations-with-hreflang.md +25 -0
- data/docs/how-to/migrate-v0.9-to-v1.0.md +46 -0
- data/docs/how-to/override-locale-strings.md +51 -0
- data/docs/how-to/override-sass-partials.md +26 -0
- data/docs/how-to/proof-built-html.md +22 -0
- data/docs/how-to/publish-json-resume.md +38 -0
- data/docs/how-to/show-language-proficiency-in-header.md +13 -0
- data/docs/how-to/switch-resume-versions.md +42 -0
- data/docs/how-to/troubleshoot-builds.md +39 -0
- data/docs/how-to/validate-in-ci.md +38 -0
- data/docs/how-to/verify-accessibility.md +28 -0
- data/docs/reference/accessibility-coverage.md +39 -0
- data/docs/reference/config.md +378 -0
- data/docs/reference/data-schemas.md +529 -0
- data/docs/reference/glossary.md +39 -0
- data/docs/reference/includes.md +197 -0
- data/docs/reference/json-resume-fields.md +148 -0
- data/docs/reference/layouts.md +144 -0
- data/docs/reference/locale-keys.md +76 -0
- data/docs/reference/repository-map.md +83 -0
- data/docs/reference/sass-tokens.md +279 -0
- data/docs/reference/testing-suites.md +62 -0
- data/docs/reference/validator-cli.md +203 -0
- data/docs/tutorials/getting-started.md +173 -0
- data/lib/jekyll-theme-resume/json_resume_exporter.rb +334 -0
- data/lib/jekyll-theme-resume/resume_validator.rb +853 -0
- data/lib/jekyll-theme-resume/schemas/LICENSE.md +21 -0
- data/lib/jekyll-theme-resume/schemas/json_resume_v1.0.0.json +500 -0
- data/lib/jekyll-theme-resume.rb +21 -0
- metadata +371 -0
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# Repository Map
|
|
2
|
+
|
|
3
|
+
*Audience: theme developers*
|
|
4
|
+
|
|
5
|
+
Annotated tree of the theme's code directories. The `docs/` directory is not listed; see the [documentation index](../README.md).
|
|
6
|
+
|
|
7
|
+
```text
|
|
8
|
+
jekyll-theme-resume/
|
|
9
|
+
├── 403.html / 404.html / 500.html # Root HTTP error pages (layout: error)
|
|
10
|
+
│
|
|
11
|
+
├── _layouts/
|
|
12
|
+
│ ├── default.html # Base HTML shell
|
|
13
|
+
│ ├── profile.html # Standalone landing page
|
|
14
|
+
│ ├── resume.html # Resume layout for every language (LTR and RTL)
|
|
15
|
+
│ └── error.html # HTTP error suite (404/403/500/503)
|
|
16
|
+
│
|
|
17
|
+
├── _includes/
|
|
18
|
+
│ ├── resume-section.html # Section dispatcher (14 sections, every language)
|
|
19
|
+
│ ├── grouped-item-list.html # Shared Experience/Volunteering renderer
|
|
20
|
+
│ ├── date-formatter.html # Locale-driven date and "Present" formatting
|
|
21
|
+
│ ├── data-loader.html # Dot-path data resolution into resume_data
|
|
22
|
+
│ ├── shared-head.html # Meta, anti-FOUC script, favicons
|
|
23
|
+
│ ├── avatar.html # Profile picture
|
|
24
|
+
│ ├── safe-url.html # URL scheme allowlist (sets safe_url)
|
|
25
|
+
│ ├── dark-mode-toggle.html # Floating theme toggle
|
|
26
|
+
│ ├── language-switcher.html # Floating dropdown linking to every other configured language
|
|
27
|
+
│ ├── social-links.html # Social icons (email + 14 platforms)
|
|
28
|
+
│ ├── print-social-links.html # Print-only social links text list
|
|
29
|
+
│ ├── hreflang.html # Alternate-language SEO links
|
|
30
|
+
│ ├── analytics-head.html # GTM / GA4 head script
|
|
31
|
+
│ ├── analytics-body.html # GTM noscript body fallback
|
|
32
|
+
│ └── vendors/svg-icons/ # Bundled Lineicons SVGs (MIT; see ATTRIBUTION.md inside)
|
|
33
|
+
│
|
|
34
|
+
├── _sass/
|
|
35
|
+
│ ├── _variables.scss # Widths, gutters, font stacks
|
|
36
|
+
│ ├── _dark-mode.scss # Color tokens, overrides, print reset
|
|
37
|
+
│ ├── _base.scss # Reset, .sr-only, base typography
|
|
38
|
+
│ ├── _layout.scss # Floating language-switcher styles
|
|
39
|
+
│ ├── _resume-ltr.scss # Main resume styles + LTR positioning
|
|
40
|
+
│ ├── _resume-rtl.scss # Language-neutral RTL overrides
|
|
41
|
+
│ ├── _profile-page.scss # Landing page styles
|
|
42
|
+
│ ├── _all-pages.scss # Shared markdown typography, icon links, footer, error-page styles
|
|
43
|
+
│ ├── _mixins.scss # Breakpoints and font mixins
|
|
44
|
+
│ └── _normalize.scss # Normalize.css v8.0.1
|
|
45
|
+
│
|
|
46
|
+
├── assets/
|
|
47
|
+
│ ├── css/
|
|
48
|
+
│ │ ├── cv-ltr.scss # Resume entrypoint for LTR locales
|
|
49
|
+
│ │ ├── cv-rtl.scss # Resume entrypoint for RTL locales
|
|
50
|
+
│ │ ├── profile.scss # Profile page entrypoint
|
|
51
|
+
│ │ └── main.scss # Default/error pages entrypoint
|
|
52
|
+
│ └── favicon/resume/ # Favicon suite
|
|
53
|
+
│
|
|
54
|
+
├── _data/
|
|
55
|
+
│ ├── locales/ # en, ar, es, fr, de, ur locale dictionaries
|
|
56
|
+
│ └── social_networks.yml # Shared platform list for social-links.html / print-social-links.html
|
|
57
|
+
│
|
|
58
|
+
├── _plugins/
|
|
59
|
+
│ ├── error_pages_generator.rb # Synthesizes missing HTTP error pages
|
|
60
|
+
│ ├── json_resume_generator.rb # Publishes /<lang>/resume.json (and /resume.json for default_lang) via JsonResumeExporter
|
|
61
|
+
│ ├── resume_pages_generator.rb # Synthesizes missing CV/profile pages per language
|
|
62
|
+
│ └── resume_validator.rb # Build-time validation (on by default)
|
|
63
|
+
│
|
|
64
|
+
├── lib/
|
|
65
|
+
│ ├── jekyll-theme-resume.rb # Gem entrypoint
|
|
66
|
+
│ └── jekyll-theme-resume/
|
|
67
|
+
│ ├── json_resume_exporter.rb # Maps resume data to a JSON Resume v1.0.0 document
|
|
68
|
+
│ ├── resume_validator.rb # Validator engine
|
|
69
|
+
│ ├── template_key_checker.rb # Template checker (repository-only)
|
|
70
|
+
│ └── schemas/
|
|
71
|
+
│ ├── json_resume_v1.0.0.json # Bundled JSON Resume schema used to validate exports
|
|
72
|
+
│ └── LICENSE.md # License for the bundled schema
|
|
73
|
+
│
|
|
74
|
+
├── bin/
|
|
75
|
+
│ ├── validate-resume # Validator CLI (gem executable)
|
|
76
|
+
│ ├── check-data-keys # Template checker (repository-only)
|
|
77
|
+
│ └── release # Release script (not packaged)
|
|
78
|
+
│
|
|
79
|
+
├── test/ # Minitest suites; see reference/testing-suites.md
|
|
80
|
+
└── Rakefile # validate, check_data_keys, test, rubocop, proof, default
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Test suites are described in [testing suites](testing-suites.md). Layouts, includes, and Sass are detailed in [layouts](layouts.md), [includes](includes.md), and [Sass tokens](sass-tokens.md).
|
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
# Sass reference (`_sass/`)
|
|
2
|
+
|
|
3
|
+
*Audience: theme developers*
|
|
4
|
+
|
|
5
|
+
Reference for the theme's styling system in [`_sass/`](../../_sass) and the entrypoint stylesheets in [`assets/css/`](../../assets/css): Dart Sass module architecture, partial inventory, and the dark mode tokens.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Entrypoints & Compilation Architecture
|
|
10
|
+
|
|
11
|
+
### Stylesheet Entrypoints
|
|
12
|
+
|
|
13
|
+
Jekyll compiles files in [`assets/css/`](../../assets/css) that start with YAML front matter into final static CSS assets:
|
|
14
|
+
|
|
15
|
+
| Source SCSS | Compiled Output CSS | Consuming Layouts |
|
|
16
|
+
|---|---|---|
|
|
17
|
+
| [`assets/css/cv-ltr.scss`](../../assets/css/cv-ltr.scss) | `assets/css/cv-ltr.css` | [`_layouts/resume.html`](../../_layouts/resume.html) for every locale with `direction: ltr` |
|
|
18
|
+
| [`assets/css/cv-rtl.scss`](../../assets/css/cv-rtl.scss) | `assets/css/cv-rtl.css` | [`_layouts/resume.html`](../../_layouts/resume.html) for every locale with `direction: rtl` |
|
|
19
|
+
| [`assets/css/profile.scss`](../../assets/css/profile.scss) | `assets/css/profile.css` | [`_layouts/profile.html`](../../_layouts/profile.html) |
|
|
20
|
+
| [`assets/css/main.scss`](../../assets/css/main.scss) | `assets/css/main.css` | [`_layouts/default.html`](../../_layouts/default.html), [`_layouts/error.html`](../../_layouts/error.html) |
|
|
21
|
+
|
|
22
|
+
### Modern Dart Sass `@use` Architecture
|
|
23
|
+
|
|
24
|
+
The theme uses `@use` exclusively. The reasons are in [Why `@use` instead of `@import`](../explanation/architecture.md#why-use-instead-of-import).
|
|
25
|
+
|
|
26
|
+
### Overriding Partials in a Consuming Site
|
|
27
|
+
|
|
28
|
+
Steps: [Override Sass partials](../how-to/override-sass-partials.md).
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## SCSS Partial Inventory
|
|
33
|
+
|
|
34
|
+
### 1. `_variables.scss`
|
|
35
|
+
|
|
36
|
+
- **File:** [`_sass/_variables.scss`](../../_sass/_variables.scss)
|
|
37
|
+
- **Role:** Font stacks and default sizes. Only `$white` and `$text_color` are read (by `_base.scss`, as fallbacks for `--bg-color` and `--text-color`); the other variables are currently unused.
|
|
38
|
+
- **Variables:**
|
|
39
|
+
- `$white`, `$text_color`: color fallbacks. They are not declared with `!default`, so they cannot be configured with `@use ... with`.
|
|
40
|
+
- `$container-width: 980px !default;`, `$grid-gutter: 10px !default;`, `$body-font`, `$mono-font`, `$body-font-size: 13px !default;`: declared but not used by any partial or entrypoint.
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
### 2. `_mixins.scss`
|
|
45
|
+
|
|
46
|
+
- **File:** [`_sass/_mixins.scss`](../../_sass/_mixins.scss)
|
|
47
|
+
- **Role:** Breakpoint helpers, typography mixins, and border accents.
|
|
48
|
+
- **Key Mixins:**
|
|
49
|
+
- `@mixin media_mobile` (`max-width: 600px`)
|
|
50
|
+
- `@mixin media_larger_than_mobile` (`min-width: 600px`)
|
|
51
|
+
- `@mixin sans`, `@mixin serif`, `@mixin section_border`
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
### 3. `_normalize.scss`
|
|
56
|
+
|
|
57
|
+
- **File:** [`_sass/_normalize.scss`](../../_sass/_normalize.scss)
|
|
58
|
+
- **Role:** Normalize.css v8.0.1 browser baseline reset.
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
### 4. `_base.scss`
|
|
63
|
+
|
|
64
|
+
- **File:** [`_sass/_base.scss`](../../_sass/_base.scss)
|
|
65
|
+
- **Role:** HTML and body defaults, box-sizing, and screen-reader accessibility classes.
|
|
66
|
+
- **Key Features:**
|
|
67
|
+
- Universal `box-sizing: border-box`.
|
|
68
|
+
- `.sr-only` utility class for WCAG screen-reader announcements.
|
|
69
|
+
- Selection background and text styling.
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
### 5. `_layout.scss`
|
|
74
|
+
|
|
75
|
+
- **File:** [`_sass/_layout.scss`](../../_sass/_layout.scss)
|
|
76
|
+
- **Role:** Floating language switcher component (`.language-switcher`, fixed top-left, hidden in print). The former grid classes (`.container`, `.columns`, `.one-third`, and so on) were removed.
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
### 6. `_resume-ltr.scss`
|
|
81
|
+
|
|
82
|
+
- **File:** [`_sass/_resume-ltr.scss`](../../_sass/_resume-ltr.scss)
|
|
83
|
+
- **Role:** The main resume stylesheet: every shared rule plus LTR positioning. Both entrypoints load it; `cv-rtl.scss` then layers `_resume-rtl.scss` on top.
|
|
84
|
+
- **Typography:** resume text reads `var(--font-locale, <default stack>)` and `var(--line-height-locale, <default>)`, so each locale's font and line height apply without per-language rules.
|
|
85
|
+
- **Components Styled:**
|
|
86
|
+
- Header: Avatar (`.avatar`), candidate name, contact info row, and social links bar.
|
|
87
|
+
- Contact CTA button (`.contact-button`) and "not looking" modifier.
|
|
88
|
+
- Section headers (`.section-header`) and item cards (`.resume-item`).
|
|
89
|
+
- Two-column responsive Languages table.
|
|
90
|
+
- Print-specific media overrides (`@media print`).
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
### 7. `_resume-rtl.scss`
|
|
95
|
+
|
|
96
|
+
- **File:** [`_sass/_resume-rtl.scss`](../../_sass/_resume-rtl.scss)
|
|
97
|
+
- **Role:** Language-neutral RTL overrides scoped under `html[dir="rtl"]`, loaded last by `cv-rtl.scss`. Serves Arabic, Urdu, and any future RTL locale.
|
|
98
|
+
- **Key Overrides:**
|
|
99
|
+
- Flips horizontal floats, text alignments, borders, and margins.
|
|
100
|
+
- Repositions timeline bullets and contact icons for RTL reading order.
|
|
101
|
+
- Resets `letter-spacing` to `normal` on headings.
|
|
102
|
+
- Sets no `font-family` or `line-height`; those come from the locale CSS variables.
|
|
103
|
+
|
|
104
|
+
---
|
|
105
|
+
|
|
106
|
+
<a id="8-_profile-pagescss"></a>
|
|
107
|
+
<a id="8-_profile-page-scss"></a>
|
|
108
|
+
### 8. `_profile-page.scss`
|
|
109
|
+
|
|
110
|
+
- **File:** [`_sass/_profile-page.scss`](../../_sass/_profile-page.scss)
|
|
111
|
+
- **Role:** Styles for the dedicated portfolio landing page layout ([`_layouts/profile.html`](../../_layouts/profile.html)) and entrypoint [`assets/css/profile.scss`](../../assets/css/profile.scss).
|
|
112
|
+
- **Architecture:** Provides clean, unconstrained vertical centering, avatar, bio typography, and CV action button without duplicating universal footer or SVG icon styles (which are loaded from [`_all-pages.scss`](../../_sass/_all-pages.scss)).
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
### 9. `_all-pages.scss`
|
|
117
|
+
|
|
118
|
+
- **File:** [`_sass/_all-pages.scss`](../../_sass/_all-pages.scss)
|
|
119
|
+
- **Role:** Universal styles shared across all layouts.
|
|
120
|
+
- **Key Features:**
|
|
121
|
+
- Shared icon-link sizing, hover animations, and `.page-footer` spacing. Shared rules live here and `.sr-only` lives in `_base.scss`.
|
|
122
|
+
- Complete dark-mode-aware typography rules for markdown content in `.main-content` (headings, paragraphs, blockquotes, tables, lists, and code blocks).
|
|
123
|
+
|
|
124
|
+
---
|
|
125
|
+
|
|
126
|
+
### 10. `_dark-mode.scss`
|
|
127
|
+
|
|
128
|
+
- **File:** [`_sass/_dark-mode.scss`](../../_sass/_dark-mode.scss)
|
|
129
|
+
- **Role:** Single source of truth for all color tokens, theme overrides, and the floating toggle button.
|
|
130
|
+
|
|
131
|
+
---
|
|
132
|
+
|
|
133
|
+
## The Dark Mode Token System
|
|
134
|
+
|
|
135
|
+
### Design Tokens Table
|
|
136
|
+
|
|
137
|
+
Shared color styles use CSS custom properties defined on `:root` in [`_sass/_dark-mode.scss`](../../_sass/_dark-mode.scss):
|
|
138
|
+
|
|
139
|
+
| CSS Custom Property | Light Mode Value | Dark Mode Value | Semantic Role |
|
|
140
|
+
|---|---|---|---|
|
|
141
|
+
| **Background & Typography** | | | |
|
|
142
|
+
| `--bg-color` | `#ffffff` | `#121212` | Main page and viewport background |
|
|
143
|
+
| `--text-color` | `#333` | `#e0e0e0` | Primary reading and heading typography |
|
|
144
|
+
| `--text-muted` | `#999` | `#888888` | Secondary copy, timestamps, and details |
|
|
145
|
+
| `--text-light` | `#646464` | `#aaaaaa` | Tertiary descriptive text |
|
|
146
|
+
| `--border-color` | `#c7c7c7` | `#333333` | Section dividers and card borders |
|
|
147
|
+
| `--card-bg` | `#efefef` | `#1e1e1e` | Button backgrounds and code blocks |
|
|
148
|
+
| **Links & Navigation** | | | |
|
|
149
|
+
| `--link-color` | `#333` | `#e0e0e0` | Interactive hyperlinks |
|
|
150
|
+
| `--link-hover` | `#9c9c9c` | `#ffffff` | Hyperlink hover color |
|
|
151
|
+
| `--link-hover-color` | `var(--link-hover)` | `var(--link-hover)` | Hyperlink hover alias |
|
|
152
|
+
| **Accent & Brand** | | | |
|
|
153
|
+
| `--accent-color` | `#3064a9` | `#6ba4e8` | Primary accents and focus outlines |
|
|
154
|
+
| `--accent-contrast-text` | `#ffffff` | `#121212` | Text and focus outline against the accent background |
|
|
155
|
+
| `--accent-hover` | `#307EA9` | `#8cbcf3` | Accent hover state |
|
|
156
|
+
| `--accent-hover-color` | `var(--accent-hover)` | `var(--accent-hover)` | Accent hover alias |
|
|
157
|
+
| `--social-hover-color` | `var(--accent-hover)` | `var(--accent-hover)` | Social icons hover color |
|
|
158
|
+
| `--about-color` | `var(--text-light)` | `var(--text-light)` | Executive summary / about text color |
|
|
159
|
+
| **Footer** | | | |
|
|
160
|
+
| `--footer-text-color` | `var(--text-muted)` | `var(--text-muted)` | Footer copyright typography |
|
|
161
|
+
| `--footer-link-color` | `var(--link-color)` | `var(--link-color)` | Footer hyperlink color |
|
|
162
|
+
| **Icons & Graphics** | | | |
|
|
163
|
+
| `--icon-fill` | `#333` | `#e0e0e0` | Social and contact SVG icon fill |
|
|
164
|
+
| `--icon-fill-muted` | `#555555` | `#888888` | Muted secondary icon fill |
|
|
165
|
+
| `--icon-fill-dark` | `#000` | `#ffffff` | Dark/prominent icon fill |
|
|
166
|
+
| `--icon-hover-fill` | `var(--icon-fill-dark)` | `var(--icon-fill-dark)` | Icon hover fill |
|
|
167
|
+
| `--header-icon-fill` | `var(--icon-fill-dark)` | `var(--icon-fill-dark)` | Header contact icon fill |
|
|
168
|
+
| **Buttons (.contact-button, .cv-button)** | | | |
|
|
169
|
+
| `--button-bg` | `#efefef` | `#2a2a2a` | Action button background |
|
|
170
|
+
| `--button-text` | `#333` | `#e0e0e0` | Action button label color |
|
|
171
|
+
| `--button-hover-bg` | `#333` | `#444444` | Action button hover background |
|
|
172
|
+
| `--button-hover-text` | `#fff` | `#ffffff` | Action button hover label color |
|
|
173
|
+
| **Text Selection** | | | |
|
|
174
|
+
| `--selection-bg` | `rgba(51, 51, 51, .8)` | `rgba(107, 164, 232, .5)` | Highlighted text background |
|
|
175
|
+
| `--selection-color` | `#fff` | `#ffffff` | Highlighted text color |
|
|
176
|
+
| **Dark Mode Toggle Component** | | | |
|
|
177
|
+
| `--toggle-btn-bg` | `transparent` | `transparent` | Toggle button background |
|
|
178
|
+
| `--toggle-btn-border` | `var(--border-color)` | `var(--border-color)` | Toggle button border |
|
|
179
|
+
| `--toggle-btn-color` | `var(--text-color)` | `var(--text-color)` | Toggle button icon color |
|
|
180
|
+
| `--toggle-btn-hover-bg` | `var(--button-bg)` | `var(--button-bg)` | Toggle button hover background |
|
|
181
|
+
| `--toggle-btn-focus-ring`| `var(--accent-color)`| `var(--accent-color)`| Toggle button focus ring outline |
|
|
182
|
+
|
|
183
|
+
### Two-Tier Activation Mechanism
|
|
184
|
+
|
|
185
|
+
Why activation has two tiers: [Dark mode approach](../explanation/dark-mode-approach.md#two-tiers-of-activation).
|
|
186
|
+
|
|
187
|
+
1. **Automatic Detection:**
|
|
188
|
+
```scss
|
|
189
|
+
@media (prefers-color-scheme: dark) {
|
|
190
|
+
:root:not([data-color-scheme="light"]):not([data-theme="light"]) {
|
|
191
|
+
--bg-color: #121212;
|
|
192
|
+
--text-color: #e0e0e0;
|
|
193
|
+
// ...
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
```
|
|
197
|
+
2. **Explicit User Pin:**
|
|
198
|
+
```scss
|
|
199
|
+
:root[data-color-scheme="dark"],
|
|
200
|
+
:root[data-theme="dark"] {
|
|
201
|
+
--bg-color: #121212;
|
|
202
|
+
--text-color: #e0e0e0;
|
|
203
|
+
// ...
|
|
204
|
+
}
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
### Print Media Resets
|
|
208
|
+
|
|
209
|
+
When printing to physical paper or PDF, [`_sass/_dark-mode.scss`](../../_sass/_dark-mode.scss) enforces a strict print reset:
|
|
210
|
+
|
|
211
|
+
```scss
|
|
212
|
+
@media print {
|
|
213
|
+
:root,
|
|
214
|
+
:root[data-color-scheme="dark"],
|
|
215
|
+
:root[data-color-scheme="light"],
|
|
216
|
+
:root[data-theme="dark"],
|
|
217
|
+
:root[data-theme="light"],
|
|
218
|
+
[data-color-scheme="dark"],
|
|
219
|
+
[data-theme="dark"],
|
|
220
|
+
html.dark,
|
|
221
|
+
html.light {
|
|
222
|
+
color-scheme: light !important;
|
|
223
|
+
--bg-color: #ffffff !important;
|
|
224
|
+
--text-color: #000000 !important;
|
|
225
|
+
--border-color: #c7c7c7 !important;
|
|
226
|
+
--card-bg: #fff !important;
|
|
227
|
+
/* ...every other color token (text, link, accent, icon, button, selection) is reset the same way */
|
|
228
|
+
}
|
|
229
|
+
html,
|
|
230
|
+
body {
|
|
231
|
+
background-color: #fff !important;
|
|
232
|
+
color: #000 !important;
|
|
233
|
+
-webkit-print-color-adjust: exact;
|
|
234
|
+
print-color-adjust: exact;
|
|
235
|
+
}
|
|
236
|
+
.dark-mode-toggle,
|
|
237
|
+
#dark-mode-toggle {
|
|
238
|
+
display: none !important;
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
The block resets every color token to black, white, or grey values, whichever scheme the page is pinned to, forces `html` and `body` to `#fff` and `#000`, and hides the toggle.
|
|
244
|
+
|
|
245
|
+
---
|
|
246
|
+
|
|
247
|
+
## WCAG 2.2 Accessibility & High-Contrast Standards
|
|
248
|
+
|
|
249
|
+
- **Contrast:** see [Accessibility decisions](../explanation/accessibility-decisions.md) for the pair-based contrast rule; [accessibility-coverage.md](accessibility-coverage.md) lists current limitations and verification steps.
|
|
250
|
+
- **Focus Rings:** Interactive elements feature high-contrast visible focus outlines:
|
|
251
|
+
```scss
|
|
252
|
+
:focus-visible {
|
|
253
|
+
outline: 2px solid var(--accent-color, #3064a9);
|
|
254
|
+
outline-offset: 2px;
|
|
255
|
+
}
|
|
256
|
+
```
|
|
257
|
+
- **Screen-Reader Utility:**
|
|
258
|
+
```scss
|
|
259
|
+
.sr-only {
|
|
260
|
+
position: absolute;
|
|
261
|
+
width: 1px;
|
|
262
|
+
height: 1px;
|
|
263
|
+
padding: 0;
|
|
264
|
+
margin: -1px;
|
|
265
|
+
overflow: hidden;
|
|
266
|
+
clip: rect(0, 0, 0, 0);
|
|
267
|
+
white-space: nowrap;
|
|
268
|
+
border-width: 0;
|
|
269
|
+
text-decoration: none !important;
|
|
270
|
+
}
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
---
|
|
274
|
+
|
|
275
|
+
## Locale Typography & RTL Mechanics
|
|
276
|
+
|
|
277
|
+
- **Per-locale typography:** `_layouts/resume.html` emits `--font-locale` (from the locale's `font_family`, when non-empty) and `--line-height-locale` (from `line_height`) in an inline `:root` style, and `_sass/_resume-ltr.scss` reads both with the theme defaults as fallbacks. Shipped font and line-height values: [locale-keys.md](locale-keys.md#shipped-locales). To change a language's font, see [Override locale strings](../how-to/override-locale-strings.md#change-a-languages-font).
|
|
278
|
+
- **Direction selects the entrypoint:** the layout links `cv-<direction>.css` (see the entrypoints table).
|
|
279
|
+
- **RTL scope:** overrides activate via `html[dir="rtl"]`; rationale in [Multilingual and RTL design](../explanation/multilingual-and-rtl-design.md#typography--rtl).
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# Testing suites
|
|
2
|
+
|
|
3
|
+
*Audience: theme developers*
|
|
4
|
+
|
|
5
|
+
How the theme is tested, what each suite proves. Validator rules themselves are in [validator-cli.md](validator-cli.md); agent verification rules are in [AGENTS.md](../../AGENTS.md#rule-5-build--packaging-verification).
|
|
6
|
+
|
|
7
|
+
## Test tasks
|
|
8
|
+
|
|
9
|
+
To run the suites or add a test, see [Add a test](../how-to/add-a-test.md).
|
|
10
|
+
|
|
11
|
+
The `test` task runs every `test/test_*.rb` file, so a new suite needs no Rakefile edit. Two error-page tests run the page's real JavaScript in Node and are skipped when `node` is not installed.
|
|
12
|
+
|
|
13
|
+
`bundle exec rake` (the default task) runs `validate`, `check_data_keys`, `rubocop`, and `test`. The default task runs `validate` with its default data directory (`_data` if `_data/en` exists, else `demo/_data`); pass another one with `rake "validate[path/to/_data]"`. There is no config-path argument; see [validator-cli.md](validator-cli.md#4-rake-task-rake-validate). HTML proofing runs separately after a build.
|
|
14
|
+
|
|
15
|
+
## What each suite covers
|
|
16
|
+
|
|
17
|
+
Every test goes through a public interface; see [Tests use public interfaces only](../explanation/architecture.md#tests-use-public-interfaces-only).
|
|
18
|
+
|
|
19
|
+
| Suite | Interface under test | Covers |
|
|
20
|
+
|---|---|---|
|
|
21
|
+
| [`test_rendered_site.rb`](../../test/test_rendered_site.rb) | Generated HTML of a fixture site built from the theme's real `_layouts`, `_includes`, `_sass`, `_data`, `assets` | Each of the sections (fields, separators, inactive entries, grouping, RTL `dir="ltr"` isolation); date formats; header, contact bar, avatar, microdata; social and print links; hreflang; profile, default and error layouts (including the URL-language script and `baseurl`); config switches such as `enable_live`, `lang_header`, `baseurl`, analytics, dark mode |
|
|
22
|
+
| [`test_language_switcher.rb`](../../test/test_language_switcher.rb) | Generated HTML, six languages | Switcher links, labels, direction, page/site opt-out, error layout |
|
|
23
|
+
| [`test_resume_validator.rb`](../../test/test_resume_validator.rb) | `ResumeValidator#validate`, `bin/validate-resume`, build plugin | Every schema rule per section, dates, "Present" values, URLs, alias keys, locale merge and parity, config resolution, strict mode, CLI flags |
|
|
24
|
+
| [`test_template_key_checker.rb`](../../test/test_template_key_checker.rb) | `TemplateKeyChecker#check`, `bin/check-data-keys` | Liquid binding resolution, include boundaries, advisory exit codes |
|
|
25
|
+
| [`test_error_pages_generator.rb`](../../test/test_error_pages_generator.rb) | Site build | Generated 404/403/500 pages, site overrides, generator registration |
|
|
26
|
+
| [`test_resume_pages_generator.rb`](../../test/test_resume_pages_generator.rb) | Site build | Generated CV/profile pages, collisions, per-language and global toggles |
|
|
27
|
+
| [`test_json_resume_exporter.rb`](../../test/test_json_resume_exporter.rb) | `JsonResumeExporter.export`, site build | JSON Resume mapping, privacy, visibility, schema validation, routes; see [json-resume-fields.md](json-resume-fields.md) |
|
|
28
|
+
| [`test_packaging.rb`](../../test/test_packaging.rb) | Gemspec, shipped `_data` | Gem file list, six-locale key parity, unused locale keys, social icons and labels, demo data parity |
|
|
29
|
+
| [`test_doc_links.rb`](../../test/test_doc_links.rb) | The tracked Markdown files | Every relative link and `#anchor` in the docs resolves; links in code blocks and external URLs are skipped |
|
|
30
|
+
|
|
31
|
+
## The rendered-site fixture
|
|
32
|
+
|
|
33
|
+
`RenderedSiteTest` writes fixture data for `en` (LTR) and `ar` (RTL) into a temporary site. Each section has an entry for every rendering rule, an entry with optional fields missing, and an `active: false` entry whose text starts with `hidden-`. Entries are tagged `EN`/`AR` so a test can tell which language's data rendered.
|
|
34
|
+
|
|
35
|
+
Config variants reuse the same fixture. Pass overrides and the site is built once per distinct override set:
|
|
36
|
+
|
|
37
|
+
```ruby
|
|
38
|
+
cv("en", "enable_live" => true) # _site/en/cv/ built with enable_live on
|
|
39
|
+
html("404.html", "baseurl" => "/cv") # any output path
|
|
40
|
+
section("Experience") # the <section> whose heading matches, default config
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Continuous integration
|
|
44
|
+
|
|
45
|
+
This repository runs the validator and the template key checker in two workflows:
|
|
46
|
+
|
|
47
|
+
- [`.github/workflows/lint.yml`](../../.github/workflows/lint.yml): `./bin/validate-resume demo/_data --fail-on-warnings`, `rake validate[demo/_data]`, `./bin/check-data-keys demo/_data`, `rake check_data_keys[demo/_data]`, a gemspec executable check, and RuboCop.
|
|
48
|
+
- [`.github/workflows/ci.yml`](../../.github/workflows/ci.yml): gem packaging, a strict Jekyll build, built-HTML proofing, RuboCop, the resume validator and template key checker, and the unit tests across Ruby 3.3, 3.4, and 4.0.
|
|
49
|
+
|
|
50
|
+
## Built-HTML proofing semantics
|
|
51
|
+
|
|
52
|
+
- External URLs are not fetched, so results are offline and deterministic.
|
|
53
|
+
- Absolute URLs built from `site.url` (hreflang, canonical) are mapped onto local files so they are checked too.
|
|
54
|
+
- When `_site/index.html` does not exist, `/` and every configured `languages.<lang>.url` are exempted as link targets. A site with a homepage gets no exemption. Use the demo build to check the complete generated site.
|
|
55
|
+
|
|
56
|
+
## JSON Resume export coverage
|
|
57
|
+
|
|
58
|
+
Run the normal demo build and `bundle exec rake`. Export coverage includes visibility, live contacts, privacy, locale characters, schema validation, collisions, literal Liquid content, and discovery-link cleanup on rebuild. Generated JSON can be downloaded directly or imported into JSON Resume tooling; compatibility with every third-party renderer is not guaranteed by schema validity.
|
|
59
|
+
|
|
60
|
+
## Liquid pitfalls the tests guard
|
|
61
|
+
|
|
62
|
+
See [Liquid pitfalls](../explanation/architecture.md#liquid-pitfalls).
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
# Validator and build checks
|
|
2
|
+
|
|
3
|
+
*Audience: site owners and theme developers*
|
|
4
|
+
|
|
5
|
+
The repository has two verification engines; only the resume-data validator ships in the gem. `lib/jekyll-theme-resume/resume_validator.rb` checks resume YAML data — reached three ways: the `validate-resume` CLI, the `rake validate` task, and a Jekyll generator that runs during every consuming site's build. `lib/jekyll-theme-resume/template_key_checker.rb` checks the theme's own `_layouts`/`_includes` Liquid templates for references to data keys that don't exist — reached via the `check-data-keys` CLI and the `rake check_data_keys` task ([section 11](#11-template-key-checker-check-data-keys)); unlike the resume validator, it runs only in this repository's own development workflow and CI, never on a consuming site's build, and it is not packaged in the gem. This page describes what each checks and how their entry points behave.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## 1. What Gets Checked
|
|
10
|
+
|
|
11
|
+
Findings are **errors** or **warnings**. Errors make the CLI exit 1; warnings do too only with `--fail-on-warnings`.
|
|
12
|
+
|
|
13
|
+
| Check | Severity |
|
|
14
|
+
|---|---|
|
|
15
|
+
| YAML syntax in every data, locale, and config file | Error |
|
|
16
|
+
| A configured language has no locale file (neither theme nor site) | Error |
|
|
17
|
+
| A configured language has no data folder | Error |
|
|
18
|
+
| A `languages.<lang>` entry has no `data_path` | Error |
|
|
19
|
+
| An explicit `--config` file does not exist | Error |
|
|
20
|
+
| Required fields per section, date formats, inverted date ranges, URLs that do not parse or do not start with `http://` or `https://` | Error (see [catalog](#6-validation-rules-catalog-by-section)) |
|
|
21
|
+
| A section file exists in one language folder and not another (file parity) | Warning |
|
|
22
|
+
| A language's effective locale is missing keys the reference locale has (locale parity) | Warning |
|
|
23
|
+
| Missing or non-boolean `active` flag, brief or missing header intro, skill `level` outside 1 to 5 | Warning |
|
|
24
|
+
|
|
25
|
+
Entries with `active: false` skip schema checks after the `active` flag check.
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## 2. How Languages and Locales Are Resolved
|
|
30
|
+
|
|
31
|
+
**Config.** The validator reads the site's Jekyll config to learn which languages exist. It uses the first file found: the `--config` path, then `<data_dir>/_config.yml`, `<data_dir>/_config.sample.yml`, `<data_dir>/../_config.yml`, `<data_dir>/../_config.sample.yml`. The Jekyll plugin passes the already-loaded site config instead.
|
|
32
|
+
|
|
33
|
+
**Languages.** The set of languages to validate is, in order of precedence:
|
|
34
|
+
|
|
35
|
+
1. `--languages` on the CLI, if given.
|
|
36
|
+
2. Every key under `languages:` in the config. Each language's folder is `<data_dir>/<data_path>`, with dot paths split into folders (`2025-06.v1` resolves to `<data_dir>/2025-06/v1`).
|
|
37
|
+
3. With no `languages:` in the config (or no config), a directory scan of `<data_dir>` for folders named like language codes (`en`, `pt-BR`, `zh_CN`) that contain YAML files. Folders named `locales`, `sample`, `archive`, `assets`, and similar are skipped.
|
|
38
|
+
|
|
39
|
+
`--all-locales` adds the directory scan on top of 1 or 2.
|
|
40
|
+
|
|
41
|
+
**Locales.** Each language's effective locale is the theme gem's `_data/locales/<lang>.yml` with the site's `<data_dir>/locales/<lang>.yml` deep-merged over it: nested hashes merge key by key, arrays (`months`, `present_values`) are replaced whole. This mirrors how Jekyll layers theme and site data (see [`multilingual-and-rtl-design.md`](../explanation/multilingual-and-rtl-design.md#overriding-theme-locales)). Locale parity is checked on the merged result, so a one-line site override warns on nothing, while a site-only locale for a language the theme does not ship must be complete.
|
|
42
|
+
|
|
43
|
+
**Reference language.** Locale parity compares every language against one reference: `--primary` (default `en`) if it has a locale, else `default_lang`, else the first language that has one. File parity uses `--primary` if it has a data folder, else the first language that does.
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
## 3. CLI Validator (`validate-resume`)
|
|
48
|
+
|
|
49
|
+
The gem installs `validate-resume` as an executable. In a consuming site run it through Bundler; in this repository run `./bin/validate-resume`.
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
bundle exec validate-resume # auto-detects the data directory
|
|
53
|
+
bundle exec validate-resume _data # explicit data directory
|
|
54
|
+
bundle exec validate-resume _data -c _config.yml # explicit config
|
|
55
|
+
./bin/validate-resume demo/_data # this repository's six-language demo
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
With no `DATA_DIR`, the CLI uses the first of `_data` and `demo/_data` that contains at least one language folder, else `_data`. A positional `DATA_DIR` wins over `-d`.
|
|
59
|
+
|
|
60
|
+
| Flag | Long flag | Description | Default |
|
|
61
|
+
|---|---|---|---|
|
|
62
|
+
| `-d DIR` | `--dir DIR` | Data directory | `_data` or `demo/_data` |
|
|
63
|
+
| `-c FILE` | `--config FILE` | Jekyll config that declares `languages:` | First config found next to the data directory ([section 2](#2-how-languages-and-locales-are-resolved)) |
|
|
64
|
+
| `-l LANGS` | `--languages LANGS` | Comma-separated languages to validate; overrides the config | The config's `languages:` |
|
|
65
|
+
| `-a` | `--all-locales` | Also validate every language folder found by directory scan | off |
|
|
66
|
+
| `-p LOCALE` | `--primary LOCALE` | Reference language for parity checks | `en` |
|
|
67
|
+
| `-w` | `--fail-on-warnings` | Exit 1 on warnings as well as errors | off |
|
|
68
|
+
| `-v` | `--verbose` | Accepted for compatibility; currently has no effect | off |
|
|
69
|
+
| `-q` | `--quiet` | Print only when there are findings | off |
|
|
70
|
+
| `-h` | `--help` | Show usage | |
|
|
71
|
+
|
|
72
|
+
Exit codes (from [`bin/validate-resume`](../../bin/validate-resume), which exits with the value `validate` returns; see [section 12](#12-ruby-api-resumevalidator)):
|
|
73
|
+
|
|
74
|
+
| Code | When |
|
|
75
|
+
|---|---|
|
|
76
|
+
| `0` | No errors, and no warnings under `-w`; also after `-h` prints usage |
|
|
77
|
+
| `1` | Any error (including a data directory that does not exist), or any warning under `-w` |
|
|
78
|
+
|
|
79
|
+
An unrecognized option raises an uncaught `OptionParser` exception, so Ruby exits with status `1` before validation starts.
|
|
80
|
+
|
|
81
|
+
---
|
|
82
|
+
|
|
83
|
+
## 4. Rake Task (`rake validate`)
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
bundle exec rake validate # _data if _data/en exists, else demo/_data
|
|
87
|
+
bundle exec rake "validate[path/to/_data]"
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
The task takes no config argument; it finds the config next to the data directory as described in [section 2](#2-how-languages-and-locales-are-resolved). For what the default `bundle exec rake` task runs, see [testing-suites.md](testing-suites.md#test-tasks).
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
## 5. Jekyll Build-Time Validation
|
|
95
|
+
|
|
96
|
+
When the gem is loaded as a plugin (through `group :jekyll_plugins` in the site's `Gemfile` or the theme name in `_config.yml`’s `plugins:` list), `_plugins/resume_validator.rb` validates the site's `data_dir` on every `jekyll build` and `jekyll serve`. It is **on by default**; findings are logged and the build continues.
|
|
97
|
+
|
|
98
|
+
To opt out or gate the build on findings, see [Validate resume data in CI](../how-to/validate-in-ci.md#configure-build-time-validation).
|
|
99
|
+
|
|
100
|
+
| Key | Default | Effect |
|
|
101
|
+
|---|---|---|
|
|
102
|
+
| `validate_resume` | on (unset) | Only the literal value `false` disables validation. |
|
|
103
|
+
| `validate_resume_strict` | `false` | `true` raises `Jekyll::Errors::FatalException` when there are errors. |
|
|
104
|
+
| `validate_resume_fail_on_warnings` | `false` | With `validate_resume_strict: true`, warnings also abort the build. Has no effect without strict mode. |
|
|
105
|
+
|
|
106
|
+
If the configured `data_dir` does not exist, the plugin logs a warning and skips validation.
|
|
107
|
+
|
|
108
|
+
---
|
|
109
|
+
|
|
110
|
+
## 6. Validation Rules Catalog by Section
|
|
111
|
+
|
|
112
|
+
The rules are identical for every language. Required fields must use the canonical key the templates render. Names in parentheses are aliases the templates never read: an entry that sets only an alias still fails, and the error names the alias it found (for example `Missing required field 'company': found 'organization', but the theme only renders 'company'`). Field names are listed in [data-schemas.md](data-schemas.md).
|
|
113
|
+
|
|
114
|
+
| Section file | Required fields | Checked when present |
|
|
115
|
+
|---|---|---|
|
|
116
|
+
| `header.yml` | Must be a Hash | `intro` (or `about`): warning if missing or under 20 characters |
|
|
117
|
+
| `experience.yml` | `company` (`organization`), `position` (`role`) | `startdate`, `enddate` (date or "present"), date order, `url`, empty `durations[].duration` warns; warning if none of `startdate`, `enddate`, or `durations` is set |
|
|
118
|
+
| `education.yml` | `uni` (`institution`, `school`), `degree`, and nonblank `year` unless `startdate` is supplied | `startdate`, `enddate` (date or "present"), date order, `url` |
|
|
119
|
+
| `certifications.yml` | `name` (`title`) | `issue_date`, `expiration`, `expiration >= issue_date`, `credential_url` |
|
|
120
|
+
| `courses.yml` | `name` (`title`, `course`) | `startdate`, `enddate`, date order, `credential_url` |
|
|
121
|
+
| `volunteering.yml` | `company` (`organization`), `position` (`role`) | `startdate`, `enddate` (date or "present"), date order, `url` |
|
|
122
|
+
| `projects.yml` | `project` (`title`, `name`) | `url`, `startdate`, `enddate` (date or "present"), date order |
|
|
123
|
+
| `skills.yml` | `skill` (`category`, `name`) | `level` is an integer 1 to 5 (warning) |
|
|
124
|
+
| `recognitions.yml` | `award` (`title`, `recognition`) | `date` (ISO) |
|
|
125
|
+
| `associations.yml` | `organization` (`company`, `name`) | `url` |
|
|
126
|
+
| `languages.yml` | `language` (`name`) | |
|
|
127
|
+
| `links.yml` | `description` (`name`, `title`), `url` | `url` |
|
|
128
|
+
| `publications.yml` | `name` (`title`) | `release_date` (ISO), `url` (http/https) |
|
|
129
|
+
| `references.yml` | `name`, `reference` (`quote`, `text`) | none |
|
|
130
|
+
| `interests.yml` | none; missing `description` is a warning (naming `interest`/`name` when one is set) | No `active` flag check |
|
|
131
|
+
|
|
132
|
+
Every file except `header.yml` must be a list of Hashes. Every list entry except in `interests.yml` should carry `active: true` or `active: false`.
|
|
133
|
+
|
|
134
|
+
Dates must be ISO: `YYYY-MM-DD`, `YYYY-MM`, or `YYYY`. Ranges compare at the precision given, with partial end dates extended to the end of their period, so `2024-05-15` to `2024-05` is valid and `2025-01` to `2024-05` is an error.
|
|
135
|
+
|
|
136
|
+
URLs must parse and must start with `http://` or `https://`; either failure is an error.
|
|
137
|
+
|
|
138
|
+
---
|
|
139
|
+
|
|
140
|
+
## 7. "Present" Dates
|
|
141
|
+
|
|
142
|
+
The words the validator accepts for an ongoing `enddate` are listed in [Present values](locale-keys.md#present-values).
|
|
143
|
+
|
|
144
|
+
---
|
|
145
|
+
|
|
146
|
+
## 8. Troubleshooting
|
|
147
|
+
|
|
148
|
+
Findings and their fixes are in [Troubleshoot builds](../how-to/troubleshoot-builds.md).
|
|
149
|
+
|
|
150
|
+
---
|
|
151
|
+
|
|
152
|
+
## 9. Continuous Integration
|
|
153
|
+
|
|
154
|
+
This repository's workflows are listed in [testing-suites.md](testing-suites.md#continuous-integration). A consuming-site workflow is in [Validate resume data in CI](../how-to/validate-in-ci.md#run-the-validator-in-github-actions).
|
|
155
|
+
|
|
156
|
+
---
|
|
157
|
+
|
|
158
|
+
## 10. Built-HTML Proofing & Static Analysis
|
|
159
|
+
|
|
160
|
+
Commands are in [Validate resume data in CI](../how-to/proof-built-html.md); proofing semantics are in [testing-suites.md](testing-suites.md#built-html-proofing-semantics).
|
|
161
|
+
|
|
162
|
+
---
|
|
163
|
+
|
|
164
|
+
## 11. Template Key Checker (`check-data-keys`)
|
|
165
|
+
|
|
166
|
+
Why the checker exists and why it never defaults to `--fail-on-warnings`: [Resume Data Validator](../explanation/architecture.md#two-verification-engines).
|
|
167
|
+
|
|
168
|
+
```bash
|
|
169
|
+
./bin/check-data-keys demo/_data # this repository's six-language demo (the default target)
|
|
170
|
+
./bin/check-data-keys demo/_data --fail-on-warnings # opt into strict mode yourself, once you trust your data's coverage
|
|
171
|
+
bundle exec rake check_data_keys # _data if _data/en exists, else demo/_data; never fails the task
|
|
172
|
+
bundle exec rake "check_data_keys[path/to/_data]"
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
| Flag | Long flag | Description | Default |
|
|
176
|
+
|---|---|---|---|
|
|
177
|
+
| `-d DIR` | `--dir DIR` | Data directory whose sample data defines the known keys | `_data` or `demo/_data` |
|
|
178
|
+
| `-c FILE` | `--config FILE` | Jekyll config that declares `languages:` | `_config.yml` / `_config.sample.yml` next to the data directory |
|
|
179
|
+
| `-w` | `--fail-on-warnings` | Exit 1 on warnings | off |
|
|
180
|
+
| `-v` | `--verbose` | Accepted for compatibility; currently has no effect | off |
|
|
181
|
+
| `-q` | `--quiet` | Print only when there are findings | off |
|
|
182
|
+
| `-h` | `--help` | Show usage | |
|
|
183
|
+
|
|
184
|
+
With no `DATA_DIR`, `check-data-keys` uses the first of `_data` and `demo/_data` that contains at least one language folder, else `demo/_data`. A positional `DATA_DIR` wins over `-d`.
|
|
185
|
+
|
|
186
|
+
Scans only `_layouts/*.html` and `_includes/**/*.html` — this repository's own shipped templates, never a consuming site's `_pages/` or `_layouts/`/`_includes` overrides. Runs in `bundle exec rake` (the default task) and in both CI workflows ([testing-suites.md](testing-suites.md#continuous-integration)), always without `--fail-on-warnings`.
|
|
187
|
+
|
|
188
|
+
---
|
|
189
|
+
|
|
190
|
+
## 12. Ruby API (`ResumeValidator`)
|
|
191
|
+
|
|
192
|
+
`JekyllThemeResume::ResumeValidator` in [`lib/jekyll-theme-resume/resume_validator.rb`](../../lib/jekyll-theme-resume/resume_validator.rb) backs the CLI, the Rake task, and the Jekyll generator. Public interface:
|
|
193
|
+
|
|
194
|
+
| Signature | Behavior |
|
|
195
|
+
|---|---|
|
|
196
|
+
| `new(data_dir = "_data", config_path: nil, config: nil, primary_locale: "en")` | Stores the data directory (trailing `/` removed), an explicit config path, an already-parsed site config Hash (the Jekyll plugin passes `site.config`; when `nil` the config is looked up on disk, `config_path` first), and the reference language (`nil` becomes `"en"`). |
|
|
197
|
+
| `validate(languages: nil, all_locales: false, primary_locale: nil, verbose: false, quiet: false, fail_on_warnings: false)` | Clears previous findings, runs every check on the resolved languages, prints the report (skipped under `quiet:` when there are no findings), and returns `1` when there are errors or, with `fail_on_warnings: true`, warnings; otherwise `0`. A missing data directory is an error and returns `1` at once. A non-nil `primary_locale:` replaces the one given to `new`. |
|
|
198
|
+
| `discover_languages` | Returns the subfolders of the data directory that are named like language codes, are not in the skip list, and contain `.yml`/`.yaml` files, with `primary_locale` first (when it is among them) and the rest sorted; `[]` if the data directory does not exist. |
|
|
199
|
+
| `locale_for(lang)` | Returns the effective locale Hash for `lang` (stripped and downcased): the theme's `_data/locales/<lang>.yml` with the site's `<data_dir>/locales/<lang>.yml` deep-merged over it, a site-only locale as-is, or `nil` when neither exists; cached per `validate` run. |
|
|
200
|
+
| `present_aliases_for(lang = nil)` | Returns the unique accepted "present" words for `lang`: the effective locale's `present_values` plus its `ui.present`, falling back to the `default_lang` (else reference-language) locale when `lang` has none; a `nil` or blank `lang` returns the words of every known locale. |
|
|
201
|
+
| `present_date?(date_val, lang: nil)` | Returns `false` for `nil`, `Date`, or `Time` values, `true` for a blank string, and otherwise whether the value matches one of `present_aliases_for(lang)` case-insensitively. |
|
|
202
|
+
|
|
203
|
+
Read-only attributes: `data_dir`, `errors`, `warnings`, `primary_locale`, and `info` (currently always empty). Each finding is a Hash `{ context:, message: }`.
|