@regmisatyam/retex 0.1.0 → 0.2.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.
package/dist/react.js CHANGED
@@ -1,16 +1,23 @@
1
1
  // src/theme/default.ts
2
- var defaultTheme = {
3
- name: "default",
4
- colors: {
5
- primary: "#2563eb",
6
- secondary: "#64748b",
7
- text: "#1e293b",
8
- muted: "#64748b",
9
- background: "#ffffff",
10
- border: "#e2e8f0",
11
- accent: "#2563eb",
12
- success: "#16a34a"
13
- },
2
+ var blankTheme = {
3
+ name: "blank"
4
+ };
5
+ var defaultTheme = blankTheme;
6
+
7
+ // src/theme/themes.ts
8
+ function resolveTheme(partial, base = defaultTheme) {
9
+ return {
10
+ name: partial?.name ?? base.name,
11
+ colors: { ...base.colors, ...partial?.colors },
12
+ fonts: { ...base.fonts, ...partial?.fonts },
13
+ fontSizes: { ...base.fontSizes, ...partial?.fontSizes },
14
+ spacing: { ...base.spacing, ...partial?.spacing },
15
+ page: { ...base.page, ...partial?.page },
16
+ sectionStyle: partial?.sectionStyle ?? base.sectionStyle,
17
+ headings: { ...base.headings, ...partial?.headings }
18
+ };
19
+ }
20
+ var styledBase = {
14
21
  fonts: {
15
22
  heading: '"Inter", "Helvetica Neue", Helvetica, Arial, sans-serif',
16
23
  body: '"Inter", "Helvetica Neue", Helvetica, Arial, sans-serif',
@@ -25,41 +32,36 @@ var defaultTheme = {
25
32
  name: "26pt",
26
33
  section: "13pt"
27
34
  },
28
- spacing: {
29
- unit: "4px",
30
- section: "1.1rem",
31
- item: "0.28rem",
32
- page: "0.55in"
33
- },
34
- page: {
35
- size: "Letter",
36
- margin: "0.55in",
37
- maxWidth: "8.5in"
38
- },
39
- sectionStyle: "rule"
35
+ spacing: { unit: "4px", section: "1.1rem", item: "0.28rem", page: "0.55in" },
36
+ page: { size: "Letter", margin: "0.55in", maxWidth: "8.5in" },
37
+ headings: { transform: "uppercase", tracking: "0.06em", nameTracking: "-0.01em" }
40
38
  };
41
-
42
- // src/theme/themes.ts
43
- function resolveTheme(partial, base = defaultTheme) {
44
- if (!partial) return base;
45
- return {
46
- name: partial.name ?? base.name,
47
- colors: { ...base.colors, ...partial.colors },
48
- fonts: { ...base.fonts, ...partial.fonts },
49
- fontSizes: { ...base.fontSizes, ...partial.fontSizes },
50
- spacing: { ...base.spacing, ...partial.spacing },
51
- page: { ...base.page, ...partial.page },
52
- sectionStyle: partial.sectionStyle ?? base.sectionStyle
53
- };
54
- }
55
39
  resolveTheme({
40
+ ...styledBase,
56
41
  name: "modern",
57
- colors: { primary: "#7c3aed", accent: "#7c3aed", text: "#111827" },
42
+ colors: {
43
+ primary: "#7c3aed",
44
+ secondary: "#64748b",
45
+ text: "#111827",
46
+ muted: "#64748b",
47
+ background: "#ffffff",
48
+ border: "#e2e8f0",
49
+ accent: "#7c3aed"
50
+ },
58
51
  sectionStyle: "underline"
59
52
  });
60
53
  resolveTheme({
54
+ ...styledBase,
61
55
  name: "classic",
62
- colors: { primary: "#111827", secondary: "#4b5563", accent: "#111827" },
56
+ colors: {
57
+ primary: "#111827",
58
+ secondary: "#4b5563",
59
+ text: "#1e293b",
60
+ muted: "#4b5563",
61
+ background: "#ffffff",
62
+ border: "#cbd5e1",
63
+ accent: "#111827"
64
+ },
63
65
  fonts: {
64
66
  heading: 'Georgia, "Times New Roman", serif',
65
67
  body: 'Georgia, "Times New Roman", serif',
@@ -68,7 +70,17 @@ resolveTheme({
68
70
  sectionStyle: "rule"
69
71
  });
70
72
  resolveTheme({
73
+ ...styledBase,
71
74
  name: "compact",
75
+ colors: {
76
+ primary: "#2563eb",
77
+ secondary: "#64748b",
78
+ text: "#1e293b",
79
+ muted: "#64748b",
80
+ background: "#ffffff",
81
+ border: "#e2e8f0",
82
+ accent: "#2563eb"
83
+ },
72
84
  fontSizes: {
73
85
  base: "9.5pt",
74
86
  small: "8pt",
@@ -242,41 +254,59 @@ function iconToSvg(name, opts = {}) {
242
254
  const def = getIcon(name);
243
255
  if (!def) return null;
244
256
  const size = opts.size ?? "1em";
245
- const dim = typeof size === "number" ? `${size}` : size;
257
+ const dim2 = typeof size === "number" ? `${size}` : size;
246
258
  const cls = opts.className ? ` class="${opts.className}"` : "";
247
259
  const fillOrStroke = def.stroked ? 'fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"' : 'fill="currentColor"';
248
- return `<svg${cls} width="${dim}" height="${dim}" viewBox="0 0 24 24" ${fillOrStroke} role="img" aria-hidden="true" focusable="false">${def.body}</svg>`;
260
+ return `<svg${cls} width="${dim2}" height="${dim2}" viewBox="0 0 24 24" ${fillOrStroke} role="img" aria-hidden="true" focusable="false">${def.body}</svg>`;
249
261
  }
250
262
 
251
263
  // src/renderers/css.ts
252
264
  var tokenSafe = (s) => s.replace(/[^a-zA-Z0-9_-]/g, "");
265
+ var has = (v) => v != null && v !== "";
266
+ var color = (v, fallback) => has(v) && isSafeColor(v) ? v : fallback;
267
+ var dim = (v, fallback) => has(v) && isSafeDimension(v) ? v : fallback;
268
+ var val = (v, fallback) => has(v) ? sanitizeStyleValue(v) ?? fallback : fallback;
253
269
  function themeToCss(theme, prefix = "retex") {
254
270
  const p = prefix;
255
- const colorVars = Object.entries(theme.colors).map(([k, v]) => ` --${p}-color-${tokenSafe(k)}: ${v};`).join("\n");
271
+ const c = theme.colors ?? {};
272
+ const f = theme.fonts ?? {};
273
+ const fs = theme.fontSizes ?? {};
274
+ const sp = theme.spacing ?? {};
275
+ const h = theme.headings ?? {};
276
+ const colorVars = Object.entries(c).filter(([, v]) => has(v) && isSafeColor(v)).map(([k, v]) => ` --${p}-color-${tokenSafe(k)}: ${v};`).join("\n");
277
+ const primary = color(c.primary, "");
278
+ const skillBg = primary ? `color-mix(in srgb, ${primary} 12%, transparent)` : "transparent";
279
+ const skillColor = primary || "inherit";
280
+ const linkDecoration = primary ? "none" : "underline";
256
281
  return `.${p}-resume {
257
- ${colorVars}
258
- --${p}-primary: ${theme.colors.primary};
259
- --${p}-text: ${theme.colors.text};
260
- --${p}-muted: ${theme.colors.muted};
261
- --${p}-border: ${theme.colors.border};
262
- --${p}-bg: ${theme.colors.background};
263
- --${p}-font-heading: ${theme.fonts.heading};
264
- --${p}-font-body: ${theme.fonts.body};
265
- --${p}-font-mono: ${theme.fonts.mono};
266
- --${p}-fs-base: ${theme.fontSizes.base};
267
- --${p}-fs-small: ${theme.fontSizes.small};
268
- --${p}-fs-large: ${theme.fontSizes.large};
269
- --${p}-fs-Large: ${theme.fontSizes.Large};
270
- --${p}-fs-Huge: ${theme.fontSizes.Huge};
271
- --${p}-fs-name: ${theme.fontSizes.name};
272
- --${p}-fs-section: ${theme.fontSizes.section};
273
- --${p}-sp-section: ${theme.spacing.section};
274
- --${p}-sp-item: ${theme.spacing.item};
282
+ ${colorVars ? colorVars + "\n" : ""} --${p}-primary: ${primary || "inherit"};
283
+ --${p}-text: ${color(c.text, "inherit")};
284
+ --${p}-muted: ${color(c.muted, "inherit")};
285
+ --${p}-border: ${color(c.border, "currentColor")};
286
+ --${p}-bg: ${color(c.background, "transparent")};
287
+ --${p}-font-heading: ${val(f.heading, "inherit")};
288
+ --${p}-font-body: ${val(f.body, "inherit")};
289
+ --${p}-font-mono: ${val(f.mono, "ui-monospace, SFMono-Regular, Menlo, monospace")};
290
+ --${p}-fs-base: ${dim(fs.base, "inherit")};
291
+ --${p}-fs-small: ${dim(fs.small, "0.85em")};
292
+ --${p}-fs-large: ${dim(fs.large, "1.2em")};
293
+ --${p}-fs-Large: ${dim(fs.Large, "1.45em")};
294
+ --${p}-fs-Huge: ${dim(fs.Huge, "2em")};
295
+ --${p}-fs-name: ${dim(fs.name, "2em")};
296
+ --${p}-fs-section: ${dim(fs.section, "1.25em")};
297
+ --${p}-sp-section: ${dim(sp.section, "1.1rem")};
298
+ --${p}-sp-item: ${dim(sp.item, "0.28rem")};
299
+ --${p}-section-transform: ${val(h.transform, "none")};
300
+ --${p}-section-tracking: ${val(h.tracking, "normal")};
301
+ --${p}-name-tracking: ${val(h.nameTracking, "normal")};
302
+ --${p}-link-decoration: ${linkDecoration};
303
+ --${p}-skill-bg: ${skillBg};
304
+ --${p}-skill-color: ${skillColor};
275
305
 
276
306
  box-sizing: border-box;
277
- max-width: ${theme.page.maxWidth};
307
+ max-width: ${dim(theme.page?.maxWidth, "none")};
278
308
  margin: 0 auto;
279
- padding: ${theme.spacing.page};
309
+ padding: ${dim(sp.page, "0")};
280
310
  background: var(--${p}-bg);
281
311
  color: var(--${p}-text);
282
312
  font-family: var(--${p}-font-body);
@@ -292,7 +322,7 @@ ${colorVars}
292
322
  font-weight: 700;
293
323
  margin: 0 0 0.1em;
294
324
  color: var(--${p}-text);
295
- letter-spacing: -0.01em;
325
+ letter-spacing: var(--${p}-name-tracking);
296
326
  }
297
327
  .${p}-title {
298
328
  font-size: var(--${p}-fs-large);
@@ -321,8 +351,8 @@ ${colorVars}
321
351
  font-family: var(--${p}-font-heading);
322
352
  font-size: var(--${p}-fs-section);
323
353
  font-weight: 700;
324
- text-transform: uppercase;
325
- letter-spacing: 0.06em;
354
+ text-transform: var(--${p}-section-transform);
355
+ letter-spacing: var(--${p}-section-tracking);
326
356
  color: var(--${p}-primary);
327
357
  margin: 0 0 0.5em;
328
358
  }
@@ -365,8 +395,8 @@ ${colorVars}
365
395
 
366
396
  .${p}-skills { display: flex; flex-wrap: wrap; gap: 0.4rem; list-style: none; margin: 0.2rem 0; padding: 0; }
367
397
  .${p}-skill {
368
- background: color-mix(in srgb, var(--${p}-primary) 12%, transparent);
369
- color: var(--${p}-primary);
398
+ background: var(--${p}-skill-bg);
399
+ color: var(--${p}-skill-color);
370
400
  border-radius: 4px;
371
401
  padding: 0.12rem 0.5rem;
372
402
  font-size: var(--${p}-fs-small);
@@ -374,10 +404,14 @@ ${colorVars}
374
404
  white-space: nowrap;
375
405
  }
376
406
 
377
- .${p}-link { color: var(--${p}-primary); text-decoration: none; }
407
+ .${p}-link { color: var(--${p}-primary); text-decoration: var(--${p}-link-decoration); }
378
408
  .${p}-link:hover { text-decoration: underline; }
379
409
  .${p}-icon { display: inline-flex; vertical-align: -0.125em; }
380
410
  .${p}-rule { border: none; border-top: 1px solid var(--${p}-border); margin: 0.6rem 0; }
411
+ .${p}-rule--dashed { border-top-style: dashed; }
412
+ .${p}-rule--dotted { border-top-style: dotted; }
413
+ .${p}-rule--thick { border-top-width: 3px; }
414
+ .${p}-rule--double { border-top-style: double; border-top-width: 3px; }
381
415
  .${p}-center { text-align: center; }
382
416
  .${p}-scale-small { font-size: var(--${p}-fs-small); }
383
417
  .${p}-scale-large { font-size: var(--${p}-fs-large); }
@@ -435,7 +469,7 @@ function splitPreamble(nodes) {
435
469
  (n) => CONTACTISH.has(n.type) && n !== name && n !== title
436
470
  );
437
471
  const other = nodes.filter(
438
- (n) => !CONTACTISH.has(n.type) && n.type !== "parbreak" && !(n.type === "text" && n.value.trim() === "")
472
+ (n) => !CONTACTISH.has(n.type) && n.type !== "parbreak" && n.type !== "usepackage" && !(n.type === "text" && n.value.trim() === "")
439
473
  );
440
474
  return { name, title, contacts, other };
441
475
  }
@@ -476,7 +510,7 @@ var ReactRenderer = class {
476
510
  "ReactRenderer requires a `createElement` factory (e.g. React.createElement)."
477
511
  );
478
512
  }
479
- this.theme = options.theme ?? resolveTheme();
513
+ this.theme = resolveTheme(options.theme);
480
514
  this.prefix = options.classPrefix ?? "retex";
481
515
  this.h = options.createElement;
482
516
  this.Fragment = options.Fragment ?? "div";
@@ -512,10 +546,11 @@ var ReactRenderer = class {
512
546
  }
513
547
  /* --------------------------- structuring ---------------------------- */
514
548
  renderSection(section, body) {
549
+ const className = this.theme.sectionStyle ? `${this.cls("section")} ${this.cls("section")}--${this.theme.sectionStyle}` : this.cls("section");
515
550
  return this.el(
516
551
  "section",
517
552
  {
518
- className: `${this.cls("section")} ${this.cls("section")}--${this.theme.sectionStyle}`
553
+ className
519
554
  },
520
555
  [
521
556
  this.el("h2", { className: this.cls("section-title") }, [section.title]),
@@ -581,10 +616,14 @@ var ReactRenderer = class {
581
616
  return node.value;
582
617
  case "parbreak":
583
618
  return null;
619
+ case "usepackage":
620
+ return null;
584
621
  case "linebreak":
585
622
  return this.el("br", null, []);
586
- case "rule":
587
- return this.el("hr", { className: this.cls("rule") }, []);
623
+ case "rule": {
624
+ const variant = node.style && node.style !== "solid" ? ` ${this.cls(`rule--${node.style}`)}` : "";
625
+ return this.el("hr", { className: `${this.cls("rule")}${variant}` }, []);
626
+ }
588
627
  case "space":
589
628
  return node.axis === "vertical" ? this.el("div", { style: { height: this.dim(node.size) } }, []) : this.el(
590
629
  "span",