kamisaku 0.3.3 → 0.4.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.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +17 -0
  3. data/Gemfile.lock +1 -1
  4. data/README.md +28 -64
  5. data/examples/birthday_invitation/dino/invitation.pdf +0 -0
  6. data/examples/resume/chromatic/example.pdf +0 -0
  7. data/examples/resume/gradient/example.pdf +0 -0
  8. data/examples/resume/meridian/example.pdf +0 -0
  9. data/examples/resume/paper/example.pdf +0 -0
  10. data/examples/resume/prism/example.pdf +0 -0
  11. data/examples/resume/sleek/example.pdf +0 -0
  12. data/examples/resume/zenith/example.pdf +0 -0
  13. data/lib/kamisaku/arg_parser.rb +4 -0
  14. data/lib/kamisaku/cli_runner.rb +2 -2
  15. data/lib/kamisaku/content_validators/base_content_validator.rb +14 -0
  16. data/lib/kamisaku/content_validators/birthday_invitation_content_validator.rb +218 -0
  17. data/lib/kamisaku/{content_validator.rb → content_validators/resume_content_validator.rb} +28 -11
  18. data/lib/kamisaku/html_builder.rb +4 -3
  19. data/lib/kamisaku/pdf.rb +17 -12
  20. data/lib/kamisaku/template_helpers.rb +0 -2
  21. data/lib/kamisaku/version.rb +1 -1
  22. data/lib/kamisaku.rb +4 -2
  23. data/lib/schema/birthday_invitation/example.yml +45 -0
  24. data/lib/schema/birthday_invitation/schema.yml +40 -0
  25. data/lib/schema/resume/example.yml +274 -0
  26. data/lib/schema/resume/schema.yml +112 -0
  27. data/lib/templates/birthday_invitation/dino/template.html.erb +486 -0
  28. data/lib/templates/resume/chromatic/template.html.erb +275 -0
  29. data/lib/templates/resume/gradient/template.html.erb +793 -0
  30. data/lib/templates/resume/meridian/template.html.erb +535 -0
  31. data/lib/templates/resume/paper/template.html.erb +525 -0
  32. data/lib/templates/resume/prism/template.html.erb +818 -0
  33. data/lib/templates/{sleek → resume/sleek}/template.html.erb +1 -1
  34. data/lib/templates/resume/zenith/template.html.erb +546 -0
  35. data/scripts/rebuild_examples.rb +45 -0
  36. metadata +25 -9
  37. data/examples/paper/john_doe.pdf +0 -0
  38. data/examples/paper/john_doe.yml +0 -157
  39. data/examples/sleek/john_doe.pdf +0 -0
  40. data/examples/sleek/john_doe.yml +0 -157
  41. data/lib/templates/paper/template.html.erb +0 -420
  42. data/template.yml +0 -64
@@ -0,0 +1,535 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title><%= data[:profile][:name] %> - Resume</title>
7
+ <style>
8
+ /* Base print and preview styles */
9
+ @page {
10
+ margin: 0 auto;
11
+ padding: 0.5in;
12
+ size: A4;
13
+ }
14
+ @media screen {
15
+ body {
16
+ background: #e0e0e0;
17
+ }
18
+ .paper {
19
+ padding: 0.5in;
20
+ }
21
+ }
22
+ @media screen, print {
23
+ .paper {
24
+ background: white;
25
+ margin: 0 auto;
26
+ width: 210mm;
27
+ height: 100%;
28
+ }
29
+ }
30
+
31
+ /* ATS-friendly typography and layout */
32
+ * {
33
+ margin: 0;
34
+ padding: 0;
35
+ box-sizing: border-box;
36
+ }
37
+
38
+ body {
39
+ font-family: "Times New Roman", Times, serif;
40
+ font-size: 11pt;
41
+ line-height: 1.4;
42
+ color: #000;
43
+ }
44
+
45
+ .resume-container {
46
+ max-width: 100%;
47
+ }
48
+
49
+ /* Header section */
50
+ .resume-header {
51
+ text-align: center;
52
+ margin-bottom: 20px;
53
+ border-bottom: 2px solid #000;
54
+ padding-bottom: 10px;
55
+ }
56
+
57
+ .candidate-name {
58
+ font-size: 18pt;
59
+ font-weight: bold;
60
+ margin-bottom: 5px;
61
+ text-transform: uppercase;
62
+ letter-spacing: 1px;
63
+ }
64
+
65
+ .candidate-title {
66
+ font-size: 12pt;
67
+ font-style: italic;
68
+ margin-bottom: 8px;
69
+ color: #333;
70
+ }
71
+
72
+ .contact-info {
73
+ font-size: 10pt;
74
+ display: flex;
75
+ justify-content: center;
76
+ flex-wrap: wrap;
77
+ gap: 15px;
78
+ }
79
+
80
+ .contact-item {
81
+ white-space: nowrap;
82
+ }
83
+
84
+ /* Section styling */
85
+ .resume-section {
86
+ margin-bottom: 18px;
87
+ }
88
+
89
+ .section-title {
90
+ font-size: 12pt;
91
+ font-weight: bold;
92
+ text-transform: uppercase;
93
+ border-bottom: 1px solid #000;
94
+ margin-bottom: 8px;
95
+ padding-bottom: 2px;
96
+ letter-spacing: 0.5px;
97
+ }
98
+
99
+ /* Professional summary */
100
+ .professional-summary {
101
+ text-align: justify;
102
+ margin-bottom: 15px;
103
+ }
104
+
105
+ /* Experience section */
106
+ .experience-item {
107
+ margin-bottom: 15px;
108
+ page-break-inside: avoid;
109
+ }
110
+
111
+ .job-header {
112
+ display: flex;
113
+ justify-content: space-between;
114
+ align-items: flex-start;
115
+ margin-bottom: 3px;
116
+ }
117
+
118
+ .job-title {
119
+ font-weight: bold;
120
+ font-size: 11pt;
121
+ }
122
+
123
+ .job-duration {
124
+ font-style: italic;
125
+ font-size: 10pt;
126
+ text-align: right;
127
+ }
128
+
129
+ .company-info {
130
+ font-size: 10pt;
131
+ margin-bottom: 5px;
132
+ color: #333;
133
+ }
134
+
135
+ .company-name {
136
+ font-weight: bold;
137
+ }
138
+
139
+ .job-skills {
140
+ margin-bottom: 5px;
141
+ }
142
+
143
+ .skills-label {
144
+ font-weight: bold;
145
+ font-size: 10pt;
146
+ }
147
+
148
+ .skills-list {
149
+ font-size: 10pt;
150
+ color: #333;
151
+ }
152
+
153
+ .achievements-list {
154
+ margin-left: 15px;
155
+ }
156
+
157
+ .achievement-item {
158
+ margin-bottom: 3px;
159
+ text-align: justify;
160
+ }
161
+
162
+ /* Education section */
163
+ .education-item {
164
+ margin-bottom: 12px;
165
+ page-break-inside: avoid;
166
+ }
167
+
168
+ .education-header {
169
+ display: flex;
170
+ justify-content: space-between;
171
+ align-items: flex-start;
172
+ margin-bottom: 3px;
173
+ }
174
+
175
+ .degree-info {
176
+ font-weight: bold;
177
+ }
178
+
179
+ .education-duration {
180
+ font-style: italic;
181
+ font-size: 10pt;
182
+ }
183
+
184
+ .institution-info {
185
+ font-size: 10pt;
186
+ color: #333;
187
+ margin-bottom: 5px;
188
+ }
189
+
190
+ /* Skills section */
191
+ .skills-section {
192
+ display: grid;
193
+ grid-template-columns: 1fr 1fr;
194
+ gap: 15px;
195
+ }
196
+
197
+ .skill-category {
198
+ margin-bottom: 10px;
199
+ }
200
+
201
+ .skill-name {
202
+ font-weight: bold;
203
+ font-size: 10pt;
204
+ margin-bottom: 2px;
205
+ }
206
+
207
+ .skill-items {
208
+ font-size: 10pt;
209
+ color: #333;
210
+ }
211
+
212
+ /* Projects section */
213
+ .project-item {
214
+ margin-bottom: 12px;
215
+ page-break-inside: avoid;
216
+ }
217
+
218
+ .project-name {
219
+ font-weight: bold;
220
+ margin-bottom: 3px;
221
+ }
222
+
223
+ .project-tech {
224
+ font-size: 10pt;
225
+ color: #333;
226
+ margin-bottom: 3px;
227
+ }
228
+
229
+ /* Certifications and Awards */
230
+ .cert-award-item {
231
+ margin-bottom: 8px;
232
+ display: flex;
233
+ justify-content: space-between;
234
+ align-items: flex-start;
235
+ }
236
+
237
+ .cert-award-info {
238
+ flex: 1;
239
+ }
240
+
241
+ .cert-award-name {
242
+ font-weight: bold;
243
+ }
244
+
245
+ .cert-award-issuer {
246
+ font-size: 10pt;
247
+ color: #333;
248
+ }
249
+
250
+ .cert-award-date {
251
+ font-size: 10pt;
252
+ font-style: italic;
253
+ text-align: right;
254
+ margin-left: 10px;
255
+ }
256
+
257
+ /* Additional sections */
258
+ .languages-interests {
259
+ display: grid;
260
+ grid-template-columns: 1fr 1fr;
261
+ gap: 15px;
262
+ }
263
+
264
+ .list-inline {
265
+ font-size: 10pt;
266
+ color: #333;
267
+ }
268
+
269
+ /* Utilities */
270
+ .text-center {
271
+ text-align: center;
272
+ }
273
+
274
+ .mb-small {
275
+ margin-bottom: 5px;
276
+ }
277
+
278
+ /* Print optimizations */
279
+ @media print {
280
+ .resume-section {
281
+ page-break-inside: avoid;
282
+ }
283
+ }
284
+ </style>
285
+ </head>
286
+ <body>
287
+ <div class="paper">
288
+ <div class="resume-container">
289
+ <!-- Header Section -->
290
+ <header class="resume-header">
291
+ <h1 class="candidate-name"><%= data[:profile][:name] %></h1>
292
+ <% if data[:profile][:title] %>
293
+ <div class="candidate-title"><%= data[:profile][:title] %></div>
294
+ <% end %>
295
+
296
+ <% if data[:contact] %>
297
+ <div class="contact-info">
298
+ <% if data[:contact][:email] %>
299
+ <span class="contact-item"><%= data[:contact][:email] %></span>
300
+ <% end %>
301
+ <% if data[:contact][:mobile] %>
302
+ <span class="contact-item"><%= data[:contact][:mobile] %></span>
303
+ <% end %>
304
+ <% if data[:contact][:location] && (data[:contact][:location][:city] || data[:contact][:location][:country]) %>
305
+ <span class="contact-item">
306
+ <%= [data[:contact][:location][:city], data[:contact][:location][:country]].compact.join(', ') %>
307
+ </span>
308
+ <% end %>
309
+ <% if data[:contact][:linkedin] %>
310
+ <span class="contact-item">LinkedIn: <%= data[:contact][:linkedin] %></span>
311
+ <% end %>
312
+ <% if data[:contact][:github] %>
313
+ <span class="contact-item">GitHub: <%= data[:contact][:github] %></span>
314
+ <% end %>
315
+ </div>
316
+ <% end %>
317
+ </header>
318
+
319
+ <!-- Professional Summary -->
320
+ <% if data[:profile][:about] %>
321
+ <section class="resume-section">
322
+ <h2 class="section-title">Professional Summary</h2>
323
+ <div class="professional-summary">
324
+ <%= data[:profile][:about] %>
325
+ </div>
326
+ </section>
327
+ <% end %>
328
+
329
+ <!-- Experience Section -->
330
+ <% if data[:experiences] && !data[:experiences].empty? %>
331
+ <section class="resume-section">
332
+ <h2 class="section-title">Professional Experience</h2>
333
+ <% data[:experiences].each do |exp| %>
334
+ <div class="experience-item">
335
+ <div class="job-header">
336
+ <div class="job-title"><%= exp[:title] %></div>
337
+ <div class="job-duration">
338
+ <%= exp[:from][:month] %>/<%= exp[:from][:year] %> -
339
+ <%= exp[:to] ? "#{exp[:to][:month]}/#{exp[:to][:year]}" : "Present" %>
340
+ </div>
341
+ </div>
342
+
343
+ <div class="company-info">
344
+ <span class="company-name"><%= exp[:organisation] %></span>
345
+ <% if exp[:location] && (exp[:location][:city] || exp[:location][:country]) %>
346
+ | <%= [exp[:location][:city], exp[:location][:country]].compact.join(', ') %>
347
+ <% end %>
348
+ </div>
349
+
350
+ <% if exp[:skills] && !exp[:skills].empty? %>
351
+ <div class="job-skills">
352
+ <span class="skills-label">Key Skills:</span>
353
+ <span class="skills-list"><%= exp[:skills].join(', ') %></span>
354
+ </div>
355
+ <% end %>
356
+
357
+ <% if exp[:achievements] && !exp[:achievements].empty? %>
358
+ <ul class="achievements-list">
359
+ <% exp[:achievements].each do |achievement| %>
360
+ <li class="achievement-item"><%= achievement %></li>
361
+ <% end %>
362
+ </ul>
363
+ <% end %>
364
+ </div>
365
+ <% end %>
366
+ </section>
367
+ <% end %>
368
+
369
+ <!-- Education Section -->
370
+ <% if data[:education] && !data[:education].empty? %>
371
+ <section class="resume-section">
372
+ <h2 class="section-title">Education</h2>
373
+ <% data[:education].each do |edu| %>
374
+ <div class="education-item">
375
+ <div class="education-header">
376
+ <div class="degree-info">
377
+ <%= edu[:qualification] %><% if edu[:field] %> in <%= edu[:field] %><% end %>
378
+ </div>
379
+ <% if edu[:from] %>
380
+ <div class="education-duration">
381
+ <%= edu[:from][:month] %>/<%= edu[:from][:year] %><% if edu[:to] %> - <%= edu[:to][:month] %>/<%= edu[:to][:year] %><% end %>
382
+ </div>
383
+ <% end %>
384
+ </div>
385
+
386
+ <div class="institution-info">
387
+ <%= edu[:institute] %><% if edu[:location] && (edu[:location][:city] || edu[:location][:country]) %> | <%= [edu[:location][:city], edu[:location][:country]].compact.join(', ') %><% end %>
388
+ </div>
389
+
390
+ <% if edu[:achievements] && !edu[:achievements].empty? %>
391
+ <ul class="achievements-list">
392
+ <% edu[:achievements].each do |achievement| %>
393
+ <li class="achievement-item"><%= achievement %></li>
394
+ <% end %>
395
+ </ul>
396
+ <% end %>
397
+ </div>
398
+ <% end %>
399
+ </section>
400
+ <% end %>
401
+
402
+ <!-- Skills Section -->
403
+ <% if data[:skills] && !data[:skills].empty? %>
404
+ <section class="resume-section">
405
+ <h2 class="section-title">Core Competencies</h2>
406
+ <div class="skills-section">
407
+ <% data[:skills].each do |skill| %>
408
+ <div class="skill-category">
409
+ <div class="skill-name"><%= skill[:name] %></div>
410
+ <% if skill[:items] && !skill[:items].empty? %>
411
+ <div class="skill-items"><%= skill[:items].join(', ') %></div>
412
+ <% end %>
413
+ </div>
414
+ <% end %>
415
+ </div>
416
+ </section>
417
+ <% end %>
418
+
419
+ <!-- Projects Section -->
420
+ <% if data[:projects] && !data[:projects].empty? %>
421
+ <section class="resume-section">
422
+ <h2 class="section-title">Notable Projects</h2>
423
+ <% data[:projects].each do |project| %>
424
+ <div class="project-item">
425
+ <div class="project-name">
426
+ <%= project[:name] %><% if project[:link] %> | <%= project[:link] %><% end %>
427
+ </div>
428
+ <% if project[:description] %>
429
+ <div class="mb-small"><%= project[:description] %></div>
430
+ <% end %>
431
+ <% if project[:technologies] && !project[:technologies].empty? %>
432
+ <div class="project-tech">Technologies: <%= project[:technologies].join(', ') %></div>
433
+ <% end %>
434
+ </div>
435
+ <% end %>
436
+ </section>
437
+ <% end %>
438
+
439
+ <!-- Certifications Section -->
440
+ <% if data[:certifications] && !data[:certifications].empty? %>
441
+ <section class="resume-section">
442
+ <h2 class="section-title">Certifications</h2>
443
+ <% data[:certifications].each do |cert| %>
444
+ <div class="cert-award-item">
445
+ <div class="cert-award-info">
446
+ <div class="cert-award-name"><%= cert[:name] %></div>
447
+ <% if cert[:issuer] %>
448
+ <div class="cert-award-issuer"><%= cert[:issuer] %></div>
449
+ <% end %>
450
+ </div>
451
+ <% if cert[:date] %>
452
+ <div class="cert-award-date">
453
+ <%= cert[:date][:month] %>/<%= cert[:date][:year] %>
454
+ </div>
455
+ <% end %>
456
+ </div>
457
+ <% end %>
458
+ </section>
459
+ <% end %>
460
+
461
+ <!-- Awards Section -->
462
+ <% if data[:awards] && !data[:awards].empty? %>
463
+ <section class="resume-section">
464
+ <h2 class="section-title">Awards & Recognition</h2>
465
+ <% data[:awards].each do |award| %>
466
+ <div class="cert-award-item">
467
+ <div class="cert-award-info">
468
+ <div class="cert-award-name"><%= award[:title] %></div>
469
+ <% if award[:issuer] %>
470
+ <div class="cert-award-issuer"><%= award[:issuer] %></div>
471
+ <% end %>
472
+ <% if award[:description] %>
473
+ <div class="cert-award-issuer"><%= award[:description] %></div>
474
+ <% end %>
475
+ </div>
476
+ <% if award[:date] %>
477
+ <div class="cert-award-date">
478
+ <%= award[:date][:month] %>/<%= award[:date][:year] %>
479
+ </div>
480
+ <% end %>
481
+ </div>
482
+ <% end %>
483
+ </section>
484
+ <% end %>
485
+
486
+ <!-- Publications Section -->
487
+ <% if data[:publications] && !data[:publications].empty? %>
488
+ <section class="resume-section">
489
+ <h2 class="section-title">Publications</h2>
490
+ <% data[:publications].each do |pub| %>
491
+ <div class="cert-award-item">
492
+ <div class="cert-award-info">
493
+ <div class="cert-award-name"><%= pub[:title] %></div>
494
+ <% if pub[:publisher] %>
495
+ <div class="cert-award-issuer"><%= pub[:publisher] %></div>
496
+ <% end %>
497
+ </div>
498
+ <% if pub[:date] %>
499
+ <div class="cert-award-date">
500
+ <%= pub[:date][:month] %>/<%= pub[:date][:year] %>
501
+ </div>
502
+ <% end %>
503
+ </div>
504
+ <% end %>
505
+ </section>
506
+ <% end %>
507
+
508
+ <!-- Languages and Interests -->
509
+ <% if (data[:languages] && !data[:languages].empty?) || (data[:interests] && !data[:interests].empty?) %>
510
+ <section class="resume-section">
511
+ <div class="languages-interests">
512
+ <% if data[:languages] && !data[:languages].empty? %>
513
+ <div>
514
+ <h3 class="section-title">Languages</h3>
515
+ <div class="list-inline">
516
+ <%= data[:languages].map { |lang| lang[:name] }.join(', ') %>
517
+ </div>
518
+ </div>
519
+ <% end %>
520
+
521
+ <% if data[:interests] && !data[:interests].empty? %>
522
+ <div>
523
+ <h3 class="section-title">Interests</h3>
524
+ <div class="list-inline">
525
+ <%= data[:interests].map { |interest| interest[:name] }.join(', ') %>
526
+ </div>
527
+ </div>
528
+ <% end %>
529
+ </div>
530
+ </section>
531
+ <% end %>
532
+ </div>
533
+ </div>
534
+ </body>
535
+ </html>