@workingdevshero/olympia-ait-adapter 0.1.5 → 1.1.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 (70) hide show
  1. package/README.md +139 -35
  2. package/dist/index.d.ts +6 -3
  3. package/dist/index.d.ts.map +1 -1
  4. package/dist/index.js +6 -3
  5. package/dist/index.js.map +1 -1
  6. package/dist/reader/cell-utils.d.ts +10 -0
  7. package/dist/reader/cell-utils.d.ts.map +1 -0
  8. package/dist/reader/cell-utils.js +40 -0
  9. package/dist/reader/cell-utils.js.map +1 -0
  10. package/dist/reader/parse-day-sheet.d.ts +0 -1
  11. package/dist/reader/parse-day-sheet.d.ts.map +1 -1
  12. package/dist/reader/parse-day-sheet.js +95 -75
  13. package/dist/reader/parse-day-sheet.js.map +1 -1
  14. package/dist/reader/parse-warmup-workbook.d.ts +13 -0
  15. package/dist/reader/parse-warmup-workbook.d.ts.map +1 -0
  16. package/dist/reader/parse-warmup-workbook.js +154 -0
  17. package/dist/reader/parse-warmup-workbook.js.map +1 -0
  18. package/dist/reader/parse-workbook.d.ts +2 -2
  19. package/dist/reader/parse-workbook.d.ts.map +1 -1
  20. package/dist/reader/parse-workbook.js +1 -6
  21. package/dist/reader/parse-workbook.js.map +1 -1
  22. package/dist/schema/program.d.ts +398 -67
  23. package/dist/schema/program.d.ts.map +1 -1
  24. package/dist/schema/program.js +135 -28
  25. package/dist/schema/program.js.map +1 -1
  26. package/dist/schema/warmup.d.ts +426 -0
  27. package/dist/schema/warmup.d.ts.map +1 -0
  28. package/dist/schema/warmup.js +100 -0
  29. package/dist/schema/warmup.js.map +1 -0
  30. package/dist/server.d.ts.map +1 -1
  31. package/dist/server.js +51 -18
  32. package/dist/server.js.map +1 -1
  33. package/dist/tools/program-json-to-xlsx.d.ts +3 -0
  34. package/dist/tools/program-json-to-xlsx.d.ts.map +1 -0
  35. package/dist/tools/program-json-to-xlsx.js +5 -0
  36. package/dist/tools/program-json-to-xlsx.js.map +1 -0
  37. package/dist/tools/program-xlsx-to-json.d.ts +3 -0
  38. package/dist/tools/program-xlsx-to-json.d.ts.map +1 -0
  39. package/dist/tools/program-xlsx-to-json.js +5 -0
  40. package/dist/tools/program-xlsx-to-json.js.map +1 -0
  41. package/dist/tools/warmup-json-to-xlsx.d.ts +3 -0
  42. package/dist/tools/warmup-json-to-xlsx.d.ts.map +1 -0
  43. package/dist/tools/warmup-json-to-xlsx.js +5 -0
  44. package/dist/tools/warmup-json-to-xlsx.js.map +1 -0
  45. package/dist/tools/warmup-xlsx-to-json.d.ts +3 -0
  46. package/dist/tools/warmup-xlsx-to-json.d.ts.map +1 -0
  47. package/dist/tools/warmup-xlsx-to-json.js +5 -0
  48. package/dist/tools/warmup-xlsx-to-json.js.map +1 -0
  49. package/dist/writer/build-warmup-workbook.d.ts +3 -0
  50. package/dist/writer/build-warmup-workbook.d.ts.map +1 -0
  51. package/dist/writer/build-warmup-workbook.js +101 -0
  52. package/dist/writer/build-warmup-workbook.js.map +1 -0
  53. package/dist/writer/build-workbook.d.ts +2 -2
  54. package/dist/writer/build-workbook.d.ts.map +1 -1
  55. package/dist/writer/build-workbook.js +19 -23
  56. package/dist/writer/build-workbook.js.map +1 -1
  57. package/dist/writer/layout.d.ts +19 -7
  58. package/dist/writer/layout.d.ts.map +1 -1
  59. package/dist/writer/layout.js +40 -21
  60. package/dist/writer/layout.js.map +1 -1
  61. package/dist/writer/stamp-exercise.d.ts +13 -5
  62. package/dist/writer/stamp-exercise.d.ts.map +1 -1
  63. package/dist/writer/stamp-exercise.js +25 -18
  64. package/dist/writer/stamp-exercise.js.map +1 -1
  65. package/dist/writer/supplemental-template.d.ts +3 -2
  66. package/dist/writer/supplemental-template.d.ts.map +1 -1
  67. package/dist/writer/supplemental-template.js +15 -15
  68. package/dist/writer/supplemental-template.js.map +1 -1
  69. package/package.json +5 -4
  70. package/skills/olympia-authoring/SKILL.md +140 -0
@@ -0,0 +1,5 @@
1
+ import { parseProgramWorkbook } from "../reader/parse-workbook.js";
2
+ export async function programXlsxToJson(input) {
3
+ return parseProgramWorkbook(input.xlsxPath);
4
+ }
5
+ //# sourceMappingURL=program-xlsx-to-json.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"program-xlsx-to-json.js","sourceRoot":"","sources":["../../src/tools/program-xlsx-to-json.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AAMnE,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,KAA6B;IAE7B,OAAO,oBAAoB,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;AAC9C,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { WarmUpJsonToXlsxInput, WarmUpJsonToXlsxOutput } from "../schema/warmup.js";
2
+ export declare function warmUpJsonToXlsx(input: WarmUpJsonToXlsxInput): Promise<WarmUpJsonToXlsxOutput>;
3
+ //# sourceMappingURL=warmup-json-to-xlsx.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"warmup-json-to-xlsx.d.ts","sourceRoot":"","sources":["../../src/tools/warmup-json-to-xlsx.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,qBAAqB,EACrB,sBAAsB,EACvB,MAAM,qBAAqB,CAAC;AAE7B,wBAAsB,gBAAgB,CACpC,KAAK,EAAE,qBAAqB,GAC3B,OAAO,CAAC,sBAAsB,CAAC,CAEjC"}
@@ -0,0 +1,5 @@
1
+ import { buildWarmUpWorkbook } from "../writer/build-warmup-workbook.js";
2
+ export async function warmUpJsonToXlsx(input) {
3
+ return buildWarmUpWorkbook(input.warmUp, input.outputPath);
4
+ }
5
+ //# sourceMappingURL=warmup-json-to-xlsx.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"warmup-json-to-xlsx.js","sourceRoot":"","sources":["../../src/tools/warmup-json-to-xlsx.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,oCAAoC,CAAC;AAMzE,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,KAA4B;IAE5B,OAAO,mBAAmB,CAAC,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,UAAU,CAAC,CAAC;AAC7D,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { WarmUpXlsxToJsonInput, WarmUpXlsxToJsonOutput } from "../schema/warmup.js";
2
+ export declare function warmUpXlsxToJson(input: WarmUpXlsxToJsonInput): Promise<WarmUpXlsxToJsonOutput>;
3
+ //# sourceMappingURL=warmup-xlsx-to-json.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"warmup-xlsx-to-json.d.ts","sourceRoot":"","sources":["../../src/tools/warmup-xlsx-to-json.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,qBAAqB,EACrB,sBAAsB,EACvB,MAAM,qBAAqB,CAAC;AAE7B,wBAAsB,gBAAgB,CACpC,KAAK,EAAE,qBAAqB,GAC3B,OAAO,CAAC,sBAAsB,CAAC,CAEjC"}
@@ -0,0 +1,5 @@
1
+ import { parseWarmUpWorkbook } from "../reader/parse-warmup-workbook.js";
2
+ export async function warmUpXlsxToJson(input) {
3
+ return parseWarmUpWorkbook(input.xlsxPath);
4
+ }
5
+ //# sourceMappingURL=warmup-xlsx-to-json.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"warmup-xlsx-to-json.js","sourceRoot":"","sources":["../../src/tools/warmup-xlsx-to-json.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,oCAAoC,CAAC;AAMzE,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,KAA4B;IAE5B,OAAO,mBAAmB,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;AAC7C,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { WarmUpDocument, WarmUpJsonToXlsxOutput } from "../schema/warmup.js";
2
+ export declare function buildWarmUpWorkbook(doc: WarmUpDocument, outputPath: string): Promise<WarmUpJsonToXlsxOutput>;
3
+ //# sourceMappingURL=build-warmup-workbook.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"build-warmup-workbook.d.ts","sourceRoot":"","sources":["../../src/writer/build-warmup-workbook.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,cAAc,EACd,sBAAsB,EACvB,MAAM,qBAAqB,CAAC;AAyC7B,wBAAsB,mBAAmB,CACvC,GAAG,EAAE,cAAc,EACnB,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,sBAAsB,CAAC,CAwEjC"}
@@ -0,0 +1,101 @@
1
+ import { promises as fs } from "node:fs";
2
+ import ExcelJS from "exceljs";
3
+ // The warm-up format shares nothing with the program format (no borders,
4
+ // no fills, no logo, Calibri instead of Arial), so its four styles live
5
+ // here instead of in styles.ts.
6
+ const FONT_BASE = {
7
+ name: "Calibri",
8
+ family: 2,
9
+ size: 14,
10
+ };
11
+ const CENTER = { horizontal: "center" };
12
+ const WU_DAY_HEADER = {
13
+ font: { ...FONT_BASE, bold: true, underline: true },
14
+ alignment: CENTER,
15
+ };
16
+ const WU_SECTION_HEADER = {
17
+ font: { ...FONT_BASE, bold: true },
18
+ alignment: CENTER,
19
+ };
20
+ const WU_ITEM = {
21
+ font: { ...FONT_BASE },
22
+ alignment: { ...CENTER, wrapText: true },
23
+ };
24
+ // Italic — not the source files' plain-12pt convention — so that notes
25
+ // without surrounding parentheses still decode as notes (the reader treats
26
+ // italic as the primary note marker).
27
+ const WU_NOTE = {
28
+ font: { ...FONT_BASE, italic: true },
29
+ alignment: { ...CENTER, wrapText: true },
30
+ };
31
+ const DAY_COLUMN_WIDTH = 35.83203125;
32
+ const DAY_HEADER_ROW = 1;
33
+ const FIRST_SECTION_ROW = 3;
34
+ export async function buildWarmUpWorkbook(doc, outputPath) {
35
+ const workbook = new ExcelJS.Workbook();
36
+ workbook.creator = "olympia-ait-adapter";
37
+ workbook.created = new Date(0);
38
+ workbook.modified = new Date(0);
39
+ workbook.title = `${doc.client} Warm Up ${doc.warmUpDate}`;
40
+ workbook.subject = doc.client;
41
+ workbook.keywords = doc.warmUpDate;
42
+ const ws = workbook.addWorksheet("Sheet1");
43
+ ws.pageSetup.orientation = "landscape";
44
+ ws.views = [{ style: "pageLayout" }];
45
+ // Day i lives in column 1 + 2i (A, C, E, …) with empty gutter columns
46
+ // between; all columns through the last day column get the same width.
47
+ const colOf = (dayIdx) => 1 + 2 * dayIdx;
48
+ for (let c = 1; c <= colOf(doc.days.length - 1); c++) {
49
+ ws.getColumn(c).width = DAY_COLUMN_WIDTH;
50
+ }
51
+ for (const [dayIdx, day] of doc.days.entries()) {
52
+ const cell = ws.getRow(DAY_HEADER_ROW).getCell(colOf(dayIdx));
53
+ cell.value = day.name;
54
+ Object.assign(cell, WU_DAY_HEADER);
55
+ }
56
+ // Sections are row-aligned across days: section s starts on the same row
57
+ // in every day column, and the next section starts after the tallest
58
+ // day's block (items + notes) plus one blank spacer row.
59
+ const sectionCount = Math.max(...doc.days.map((d) => d.sections.length));
60
+ let row = FIRST_SECTION_ROW;
61
+ for (let s = 0; s < sectionCount; s++) {
62
+ let blockHeight = 0;
63
+ for (const [dayIdx, day] of doc.days.entries()) {
64
+ const section = day.sections[s];
65
+ if (!section)
66
+ continue;
67
+ if (section.title !== "") {
68
+ const cell = ws.getRow(row).getCell(colOf(dayIdx));
69
+ cell.value = section.title;
70
+ Object.assign(cell, WU_SECTION_HEADER);
71
+ }
72
+ let r = row + 1;
73
+ for (const item of section.items) {
74
+ const itemCell = ws.getRow(r).getCell(colOf(dayIdx));
75
+ itemCell.value = item.text;
76
+ Object.assign(itemCell, WU_ITEM);
77
+ r++;
78
+ if (item.note !== undefined) {
79
+ // The schema rejects blank note lines, but direct library callers
80
+ // bypass it — skip them so layout height matches what the reader
81
+ // can observe (blank cells are structural no-ops on decode).
82
+ const lines = item.note
83
+ .split("\n")
84
+ .filter((line) => line.trim() !== "");
85
+ for (const line of lines) {
86
+ const noteCell = ws.getRow(r).getCell(colOf(dayIdx));
87
+ noteCell.value = line;
88
+ Object.assign(noteCell, WU_NOTE);
89
+ r++;
90
+ }
91
+ }
92
+ }
93
+ blockHeight = Math.max(blockHeight, r - (row + 1));
94
+ }
95
+ row += 1 + blockHeight + 1; // header + tallest block + blank spacer
96
+ }
97
+ await workbook.xlsx.writeFile(outputPath);
98
+ const stat = await fs.stat(outputPath);
99
+ return { outputPath, bytesWritten: stat.size };
100
+ }
101
+ //# sourceMappingURL=build-warmup-workbook.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"build-warmup-workbook.js","sourceRoot":"","sources":["../../src/writer/build-warmup-workbook.ts"],"names":[],"mappings":"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"}
@@ -1,3 +1,3 @@
1
- import type { JsonToXlsxOutput, Program } from "../schema/program.js";
2
- export declare function buildWorkbook(program: Program, outputPath: string): Promise<JsonToXlsxOutput>;
1
+ import { type ProgramJsonToXlsxOutput, type Program } from "../schema/program.js";
2
+ export declare function buildProgramWorkbook(program: Program, outputPath: string): Promise<ProgramJsonToXlsxOutput>;
3
3
  //# sourceMappingURL=build-workbook.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"build-workbook.d.ts","sourceRoot":"","sources":["../../src/writer/build-workbook.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACV,gBAAgB,EAChB,OAAO,EAER,MAAM,sBAAsB,CAAC;AAgC9B,wBAAsB,aAAa,CACjC,OAAO,EAAE,OAAO,EAChB,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,gBAAgB,CAAC,CAoK3B"}
1
+ {"version":3,"file":"build-workbook.d.ts","sourceRoot":"","sources":["../../src/writer/build-workbook.ts"],"names":[],"mappings":"AAIA,OAAO,EAEL,KAAK,uBAAuB,EAC5B,KAAK,OAAO,EAEb,MAAM,sBAAsB,CAAC;AA8B9B,wBAAsB,oBAAoB,CACxC,OAAO,EAAE,OAAO,EAChB,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,uBAAuB,CAAC,CA4JlC"}
@@ -2,13 +2,14 @@ import path from "node:path";
2
2
  import { fileURLToPath } from "node:url";
3
3
  import { promises as fs } from "node:fs";
4
4
  import ExcelJS from "exceljs";
5
- import { COLUMN_WIDTHS, DATE_ROW, FIRST_EXERCISE_ROW, HEADER_ROW, LOGO_ANCHOR_TL, LOGO_PIXEL_SIZE, NOTES_COL, WARMUP_ROW, WEEK_REPS_COLS, WEEK_WEIGHT_COLS, } from "./layout.js";
5
+ import { programWeekCount, } from "../schema/program.js";
6
+ import { DATE_ROW, FIRST_EXERCISE_ROW, HEADER_ROW, LOGO_ANCHOR_TL, LOGO_PIXEL_SIZE, WARMUP_ROW, weekLayout, } from "./layout.js";
6
7
  import { DATE_LABEL, EXERCISE_HEADER, headerPadAboveStyle, headerPadBelowStyle, NOTES_HEADER_CELL, NOTES_SPACER, REPS_HEADER, SECTION_LABEL, WARMUP_DAY, WARMUP_DAY_LAST, WEIGHT_HEADER, } from "./styles.js";
7
8
  import { groupNumberOf, stampExercise } from "./stamp-exercise.js";
8
9
  import { stampSupplementalTemplate } from "./supplemental-template.js";
9
10
  const here = path.dirname(fileURLToPath(import.meta.url));
10
11
  const LOGO_PATH = path.resolve(here, "../../src/assets/olympia-logo.png");
11
- export async function buildWorkbook(program, outputPath) {
12
+ export async function buildProgramWorkbook(program, outputPath) {
12
13
  const workbook = new ExcelJS.Workbook();
13
14
  workbook.creator = "olympia-ait-adapter";
14
15
  workbook.created = new Date(0);
@@ -30,10 +31,12 @@ export async function buildWorkbook(program, outputPath) {
30
31
  extension: "png",
31
32
  })
32
33
  : undefined;
34
+ const layout = weekLayout(programWeekCount(program));
35
+ const { weekCount, repsCols: WEEK_REPS_COLS, weightCols: WEEK_WEIGHT_COLS, notesCol: NOTES_COL } = layout;
33
36
  for (const [dayIdx, day] of program.days.entries()) {
34
37
  const ws = workbook.addWorksheet(day.name);
35
38
  // Column widths
36
- for (const { col, width } of COLUMN_WIDTHS) {
39
+ for (const { col, width } of layout.columnWidths) {
37
40
  ws.getColumn(col).width = width;
38
41
  }
39
42
  // --- Row 2: "Date:" cells + "Notes" header ---
@@ -58,7 +61,7 @@ export async function buildWorkbook(program, outputPath) {
58
61
  for (let r = WARMUP_ROW; r < FIRST_EXERCISE_ROW; r++) {
59
62
  Object.assign(ws.getCell(`${NOTES_COL}${r}`), NOTES_SPACER);
60
63
  }
61
- for (let i = 0; i < 6; i++) {
64
+ for (let i = 0; i < weekCount; i++) {
62
65
  ws.mergeCells(`${WEEK_REPS_COLS[i]}${DATE_ROW}:${WEEK_WEIGHT_COLS[i]}${DATE_ROW}`);
63
66
  }
64
67
  // --- Row 3: "Warmup" + "Warm Up #N" labels (N = day index, so
@@ -69,18 +72,18 @@ export async function buildWorkbook(program, outputPath) {
69
72
  Object.assign(c, SECTION_LABEL);
70
73
  }
71
74
  const warmupLabel = `Warm Up #${dayIdx + 1}`;
72
- for (let i = 0; i < 6; i++) {
75
+ for (let i = 0; i < weekCount; i++) {
73
76
  const a = WEEK_REPS_COLS[i];
74
77
  const b = WEEK_WEIGHT_COLS[i];
75
78
  ws.mergeCells(`${a}${WARMUP_ROW}:${b}${WARMUP_ROW}`);
76
79
  const c = ws.getCell(`${a}${WARMUP_ROW}`);
77
80
  c.value = warmupLabel;
78
- Object.assign(c, i === 5 ? WARMUP_DAY_LAST : WARMUP_DAY);
81
+ Object.assign(c, i === weekCount - 1 ? WARMUP_DAY_LAST : WARMUP_DAY);
79
82
  }
80
83
  // --- Row 4: gray padding above the "Exercise" header ---
81
84
  {
82
85
  Object.assign(ws.getCell(`C4`), headerPadAboveStyle("C"));
83
- for (let i = 0; i < 6; i++) {
86
+ for (let i = 0; i < weekCount; i++) {
84
87
  Object.assign(ws.getCell(`${WEEK_REPS_COLS[i]}4`), headerPadAboveStyle("reps"));
85
88
  Object.assign(ws.getCell(`${WEEK_WEIGHT_COLS[i]}4`), headerPadAboveStyle("weight"));
86
89
  }
@@ -91,7 +94,7 @@ export async function buildWorkbook(program, outputPath) {
91
94
  c.value = "Exercise";
92
95
  Object.assign(c, EXERCISE_HEADER);
93
96
  }
94
- for (let i = 0; i < 6; i++) {
97
+ for (let i = 0; i < weekCount; i++) {
95
98
  const reps = ws.getCell(`${WEEK_REPS_COLS[i]}${HEADER_ROW}`);
96
99
  reps.value = "Reps";
97
100
  Object.assign(reps, REPS_HEADER);
@@ -102,21 +105,11 @@ export async function buildWorkbook(program, outputPath) {
102
105
  // --- Row 6: gray padding below the "Exercise" header ---
103
106
  {
104
107
  Object.assign(ws.getCell(`C6`), headerPadBelowStyle("C"));
105
- for (let i = 0; i < 6; i++) {
108
+ for (let i = 0; i < weekCount; i++) {
106
109
  Object.assign(ws.getCell(`${WEEK_REPS_COLS[i]}6`), headerPadBelowStyle("reps"));
107
110
  Object.assign(ws.getCell(`${WEEK_WEIGHT_COLS[i]}6`), headerPadBelowStyle("weight"));
108
111
  }
109
112
  }
110
- // Week dates (row 2) — override "Date:" labels if program has them.
111
- if (program.weekDates) {
112
- for (let i = 0; i < 6; i++) {
113
- const v = program.weekDates[i];
114
- if (v) {
115
- const c = ws.getCell(`${WEEK_REPS_COLS[i]}${DATE_ROW}`);
116
- c.value = v;
117
- }
118
- }
119
- }
120
113
  // --- Body: walk sections, stamp exercises with neighbor-aware borders. ---
121
114
  let row = FIRST_EXERCISE_ROW;
122
115
  for (const section of day.sections) {
@@ -126,11 +119,11 @@ export async function buildWorkbook(program, outputPath) {
126
119
  // not be filling these in for now).
127
120
  continue;
128
121
  }
129
- row = stampSection(ws, row, section);
122
+ row = stampSection(ws, row, section, layout);
130
123
  }
131
124
  // --- Fixed Sport Specific / Supplemental template at the bottom of
132
125
  // the sheet, with any freeform notes the trainer/agent supplied. ---
133
- row = stampSupplementalTemplate(ws, row, day.supplementalNotes);
126
+ row = stampSupplementalTemplate(ws, row, layout, day.supplementalNotes);
134
127
  // Olympia logo: one-cell anchor with explicit pixel dimensions so the
135
128
  // image keeps its native aspect ratio (a two-cell anchor stretches the
136
129
  // image to fit the cell range, which distorts the logo vertically).
@@ -156,7 +149,7 @@ export async function buildWorkbook(program, outputPath) {
156
149
  * - non-last block: group-label bottom NONE (the next block's top provides
157
150
  * the visual separator)
158
151
  */
159
- function stampSection(ws, startRow, section) {
152
+ function stampSection(ws, startRow, section, layout) {
160
153
  let row = startRow;
161
154
  for (let i = 0; i < section.exercises.length; i++) {
162
155
  const ex = section.exercises[i];
@@ -167,7 +160,10 @@ function stampSection(ws, startRow, section) {
167
160
  ? "hair"
168
161
  : "medium";
169
162
  const bottomBorder = i === section.exercises.length - 1 ? "medium" : "none";
170
- row = stampExercise(ws, row, ex, { topBorder, bottomBorder });
163
+ // In-sheet warm-up exercises carry a "Warmup N" label where a main
164
+ // exercise carries its group label.
165
+ const label = section.kind === "warmup" ? `Warmup ${i + 1}` : ex.groupLabel;
166
+ row = stampExercise(ws, row, ex, layout, { topBorder, bottomBorder, label });
171
167
  }
172
168
  return row;
173
169
  }
@@ -1 +1 @@
1
- {"version":3,"file":"build-workbook.js","sourceRoot":"","sources":["../../src/writer/build-workbook.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"build-workbook.js","sourceRoot":"","sources":["../../src/writer/build-workbook.ts"],"names":[],"mappings":"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"}
@@ -1,14 +1,26 @@
1
- export declare const COLUMN_WIDTHS: {
2
- col: string;
3
- width: number;
4
- }[];
1
+ export interface WeekLayout {
2
+ weekCount: number;
3
+ /** Reps column per week: D, F, H, … */
4
+ repsCols: string[];
5
+ /** Weight column per week: E, G, I, … */
6
+ weightCols: string[];
7
+ /** The Notes column sits immediately right of the last week pair. */
8
+ notesCol: string;
9
+ columnWidths: {
10
+ col: string;
11
+ width: number;
12
+ }[];
13
+ }
14
+ /**
15
+ * Column positions for a program of `weekCount` weeks. Week 1 is always
16
+ * D/E; each further week takes the next column pair, and the Notes column
17
+ * follows the last pair (L for 4 weeks, P for 6).
18
+ */
19
+ export declare function weekLayout(weekCount: number): WeekLayout;
5
20
  export declare const DATE_ROW = 2;
6
21
  export declare const WARMUP_ROW = 3;
7
22
  export declare const HEADER_ROW = 5;
8
23
  export declare const FIRST_EXERCISE_ROW = 7;
9
- export declare const WEEK_REPS_COLS: readonly ["D", "F", "H", "J", "L", "N"];
10
- export declare const WEEK_WEIGHT_COLS: readonly ["E", "G", "I", "K", "M", "O"];
11
- export declare const NOTES_COL = "P";
12
24
  export declare const EXERCISE_NAME_COL = "C";
13
25
  export declare const LOGO_ANCHOR_TL: {
14
26
  readonly col: 5;
@@ -1 +1 @@
1
- {"version":3,"file":"layout.d.ts","sourceRoot":"","sources":["../../src/writer/layout.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,aAAa,EAAE;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,EAoBzD,CAAC;AAEF,eAAO,MAAM,QAAQ,IAAI,CAAC;AAC1B,eAAO,MAAM,UAAU,IAAI,CAAC;AAC5B,eAAO,MAAM,UAAU,IAAI,CAAC;AAC5B,eAAO,MAAM,kBAAkB,IAAI,CAAC;AAGpC,eAAO,MAAM,cAAc,yCAA0C,CAAC;AACtE,eAAO,MAAM,gBAAgB,yCAA0C,CAAC;AACxE,eAAO,MAAM,SAAS,MAAM,CAAC;AAC7B,eAAO,MAAM,iBAAiB,MAAM,CAAC;AAOrC,eAAO,MAAM,cAAc;;;CAA+B,CAAC;AAC3D,eAAO,MAAM,eAAe;;;CAAsC,CAAC"}
1
+ {"version":3,"file":"layout.d.ts","sourceRoot":"","sources":["../../src/writer/layout.ts"],"names":[],"mappings":"AA4BA,MAAM,WAAW,UAAU;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,uCAAuC;IACvC,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,yCAAyC;IACzC,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,qEAAqE;IACrE,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CAChD;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,UAAU,CAmBxD;AAED,eAAO,MAAM,QAAQ,IAAI,CAAC;AAC1B,eAAO,MAAM,UAAU,IAAI,CAAC;AAC5B,eAAO,MAAM,UAAU,IAAI,CAAC;AAC5B,eAAO,MAAM,kBAAkB,IAAI,CAAC;AAEpC,eAAO,MAAM,iBAAiB,MAAM,CAAC;AAOrC,eAAO,MAAM,cAAc;;;CAA+B,CAAC;AAC3D,eAAO,MAAM,eAAe;;;CAAsC,CAAC"}
@@ -1,34 +1,53 @@
1
1
  // Column widths and row positions extracted from the sample Olympia workbooks.
2
2
  // These are constants so output is byte-stable.
3
- export const COLUMN_WIDTHS = [
3
+ const MARGIN_WIDTHS = [
4
4
  { col: "A", width: 0.66 },
5
5
  { col: "B", width: 0.66 },
6
6
  { col: "C", width: 25.83 },
7
- { col: "D", width: 7.66 },
8
- { col: "E", width: 8.83 },
9
- { col: "F", width: 7.66 },
10
- { col: "G", width: 7.83 },
11
- { col: "H", width: 7.66 },
12
- { col: "I", width: 8.0 },
13
- { col: "J", width: 7.66 },
14
- { col: "K", width: 8.66 },
15
- { col: "L", width: 7.66 },
16
- { col: "M", width: 9.33 },
17
- { col: "N", width: 7.66 },
18
- { col: "O", width: 8.33 },
19
- // Notes column — widened from the source's 10.83 so coaching cues fit
20
- // without wrapping aggressively.
21
- { col: "P", width: 18 },
22
- { col: "Q", width: 10.5 },
23
7
  ];
8
+ // Reps/weight widths for weeks 1-6, in week order.
9
+ const WEEK_PAIR_WIDTHS = [
10
+ [7.66, 8.83],
11
+ [7.66, 7.83],
12
+ [7.66, 8.0],
13
+ [7.66, 8.66],
14
+ [7.66, 9.33],
15
+ [7.66, 8.33],
16
+ ];
17
+ // Notes column — widened from the source's 10.83 so coaching cues fit
18
+ // without wrapping aggressively.
19
+ const NOTES_WIDTH = 18;
20
+ const TRAILING_WIDTH = 10.5;
21
+ const FIRST_WEEK_COL_INDEX = 4; // column D
22
+ function colLetter(index) {
23
+ return String.fromCharCode(64 + index);
24
+ }
25
+ /**
26
+ * Column positions for a program of `weekCount` weeks. Week 1 is always
27
+ * D/E; each further week takes the next column pair, and the Notes column
28
+ * follows the last pair (L for 4 weeks, P for 6).
29
+ */
30
+ export function weekLayout(weekCount) {
31
+ const repsCols = [];
32
+ const weightCols = [];
33
+ const columnWidths = [...MARGIN_WIDTHS];
34
+ for (let i = 0; i < weekCount; i++) {
35
+ const reps = colLetter(FIRST_WEEK_COL_INDEX + 2 * i);
36
+ const weight = colLetter(FIRST_WEEK_COL_INDEX + 2 * i + 1);
37
+ repsCols.push(reps);
38
+ weightCols.push(weight);
39
+ const [repsWidth, weightWidth] = WEEK_PAIR_WIDTHS[i];
40
+ columnWidths.push({ col: reps, width: repsWidth }, { col: weight, width: weightWidth });
41
+ }
42
+ const notesIndex = FIRST_WEEK_COL_INDEX + 2 * weekCount;
43
+ const notesCol = colLetter(notesIndex);
44
+ columnWidths.push({ col: notesCol, width: NOTES_WIDTH }, { col: colLetter(notesIndex + 1), width: TRAILING_WIDTH });
45
+ return { weekCount, repsCols, weightCols, notesCol, columnWidths };
46
+ }
24
47
  export const DATE_ROW = 2;
25
48
  export const WARMUP_ROW = 3;
26
49
  export const HEADER_ROW = 5;
27
50
  export const FIRST_EXERCISE_ROW = 7;
28
- // Per-week column pairs: D/E = week 1 reps/weight, F/G = week 2, etc.
29
- export const WEEK_REPS_COLS = ["D", "F", "H", "J", "L", "N"];
30
- export const WEEK_WEIGHT_COLS = ["E", "G", "I", "K", "M", "O"];
31
- export const NOTES_COL = "P";
32
51
  export const EXERCISE_NAME_COL = "C";
33
52
  // Olympia logo anchor. We use a one-cell anchor with explicit pixel
34
53
  // dimensions (rather than a two-cell anchor) so the image keeps its native
@@ -1 +1 @@
1
- {"version":3,"file":"layout.js","sourceRoot":"","sources":["../../src/writer/layout.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,gDAAgD;AAEhD,MAAM,CAAC,MAAM,aAAa,GAAqC;IAC7D,EAAE,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE;IACzB,EAAE,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE;IACzB,EAAE,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,KAAK,EAAE;IAC1B,EAAE,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE;IACzB,EAAE,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE;IACzB,EAAE,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE;IACzB,EAAE,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE;IACzB,EAAE,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE;IACzB,EAAE,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,EAAE;IACxB,EAAE,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE;IACzB,EAAE,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE;IACzB,EAAE,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE;IACzB,EAAE,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE;IACzB,EAAE,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE;IACzB,EAAE,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE;IACzB,sEAAsE;IACtE,iCAAiC;IACjC,EAAE,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,EAAE,EAAE;IACvB,EAAE,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE;CAC1B,CAAC;AAEF,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC,CAAC;AAC1B,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,CAAC;AAC5B,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,CAAC;AAC5B,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,CAAC;AAEpC,sEAAsE;AACtE,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAU,CAAC;AACtE,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAU,CAAC;AACxE,MAAM,CAAC,MAAM,SAAS,GAAG,GAAG,CAAC;AAC7B,MAAM,CAAC,MAAM,iBAAiB,GAAG,GAAG,CAAC;AAErC,oEAAoE;AACpE,2EAA2E;AAC3E,yEAAyE;AACzE,yEAAyE;AACzE,0DAA0D;AAC1D,MAAM,CAAC,MAAM,cAAc,GAAG,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,EAAE,EAAW,CAAC;AAC3D,MAAM,CAAC,MAAM,eAAe,GAAG,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,EAAE,EAAW,CAAC"}
1
+ {"version":3,"file":"layout.js","sourceRoot":"","sources":["../../src/writer/layout.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,6 @@
1
1
  import type ExcelJS from "exceljs";
2
2
  import type { Exercise } from "../schema/program.js";
3
+ import { type WeekLayout } from "./layout.js";
3
4
  import { type CTopBorder, type CBottomBorder } from "./styles.js";
4
5
  export interface StampOptions {
5
6
  /** Border style for the top of the exercise-name (column C) cell. */
@@ -9,15 +10,22 @@ export interface StampOptions {
9
10
  * "medium" only on the last exercise of a section; otherwise "none".
10
11
  */
11
12
  bottomBorder: CBottomBorder;
13
+ /**
14
+ * Text for the label row under the exercise name: the group label ("1A")
15
+ * for a main exercise, "Warmup N" for an in-sheet warm-up exercise.
16
+ */
17
+ label: string | undefined;
12
18
  }
13
19
  /**
14
20
  * Stamps one exercise block onto the worksheet starting at `startRow`.
15
21
  *
16
22
  * Layout rules (N = exercise.sets.length):
17
- * - With groupLabel: name occupies the first N−1 rows of col C (merged
18
- * when N > 2); group label sits in col C of the last row.
19
- * - Without groupLabel: name occupies all N rows of col C (merged when
20
- * N > 1); no group-label row.
23
+ * - With a label: name occupies the first N−1 rows of col C (merged
24
+ * when N > 2); the label sits in col C of the last row.
25
+ * - With a label and a single set: the set sits on the name row and the
26
+ * label gets a row of its own below it, with empty prescription cells.
27
+ * - Without a label: name occupies all N rows of col C (merged when
28
+ * N > 1); no label row.
21
29
  *
22
30
  * Borders on column C (the gray bar) are driven by `topBorder` and
23
31
  * `bottomBorder` so the caller can express "this block is the first/last
@@ -25,7 +33,7 @@ export interface StampOptions {
25
33
  *
26
34
  * @returns the next free row after the block.
27
35
  */
28
- export declare function stampExercise(ws: ExcelJS.Worksheet, startRow: number, exercise: Exercise, opts: StampOptions): number;
36
+ export declare function stampExercise(ws: ExcelJS.Worksheet, startRow: number, exercise: Exercise, layout: WeekLayout, opts: StampOptions): number;
29
37
  /** Extracts the leading numeric portion of a group label ("1A" → "1"). */
30
38
  export declare function groupNumberOf(label: string | undefined): string | undefined;
31
39
  //# sourceMappingURL=stamp-exercise.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"stamp-exercise.d.ts","sourceRoot":"","sources":["../../src/writer/stamp-exercise.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,SAAS,CAAC;AACnC,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAOrD,OAAO,EAML,KAAK,UAAU,EACf,KAAK,aAAa,EACnB,MAAM,aAAa,CAAC;AAErB,MAAM,WAAW,YAAY;IAC3B,qEAAqE;IACrE,SAAS,EAAE,UAAU,CAAC;IACtB;;;OAGG;IACH,YAAY,EAAE,aAAa,CAAC;CAC7B;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,aAAa,CAC3B,EAAE,EAAE,OAAO,CAAC,SAAS,EACrB,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,QAAQ,EAClB,IAAI,EAAE,YAAY,GACjB,MAAM,CAiER;AAED,0EAA0E;AAC1E,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAI3E"}
1
+ {"version":3,"file":"stamp-exercise.d.ts","sourceRoot":"","sources":["../../src/writer/stamp-exercise.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,SAAS,CAAC;AACnC,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAqB,KAAK,UAAU,EAAE,MAAM,aAAa,CAAC;AACjE,OAAO,EAML,KAAK,UAAU,EACf,KAAK,aAAa,EACnB,MAAM,aAAa,CAAC;AAErB,MAAM,WAAW,YAAY;IAC3B,qEAAqE;IACrE,SAAS,EAAE,UAAU,CAAC;IACtB;;;OAGG;IACH,YAAY,EAAE,aAAa,CAAC;IAC5B;;;OAGG;IACH,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC;CAC3B;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,aAAa,CAC3B,EAAE,EAAE,OAAO,CAAC,SAAS,EACrB,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,QAAQ,EAClB,MAAM,EAAE,UAAU,EAClB,IAAI,EAAE,YAAY,GACjB,MAAM,CAqER;AAED,0EAA0E;AAC1E,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAI3E"}
@@ -1,13 +1,15 @@
1
- import { EXERCISE_NAME_COL, NOTES_COL, WEEK_REPS_COLS, WEEK_WEIGHT_COLS, } from "./layout.js";
1
+ import { EXERCISE_NAME_COL } from "./layout.js";
2
2
  import { exerciseNameStyle, groupLabelStyle, NOTES_CELL, weekRepsCellStyle, weekWeightCellStyle, } from "./styles.js";
3
3
  /**
4
4
  * Stamps one exercise block onto the worksheet starting at `startRow`.
5
5
  *
6
6
  * Layout rules (N = exercise.sets.length):
7
- * - With groupLabel: name occupies the first N−1 rows of col C (merged
8
- * when N > 2); group label sits in col C of the last row.
9
- * - Without groupLabel: name occupies all N rows of col C (merged when
10
- * N > 1); no group-label row.
7
+ * - With a label: name occupies the first N−1 rows of col C (merged
8
+ * when N > 2); the label sits in col C of the last row.
9
+ * - With a label and a single set: the set sits on the name row and the
10
+ * label gets a row of its own below it, with empty prescription cells.
11
+ * - Without a label: name occupies all N rows of col C (merged when
12
+ * N > 1); no label row.
11
13
  *
12
14
  * Borders on column C (the gray bar) are driven by `topBorder` and
13
15
  * `bottomBorder` so the caller can express "this block is the first/last
@@ -15,21 +17,25 @@ import { exerciseNameStyle, groupLabelStyle, NOTES_CELL, weekRepsCellStyle, week
15
17
  *
16
18
  * @returns the next free row after the block.
17
19
  */
18
- export function stampExercise(ws, startRow, exercise, opts) {
20
+ export function stampExercise(ws, startRow, exercise, layout, opts) {
21
+ const { repsCols: WEEK_REPS_COLS, weightCols: WEEK_WEIGHT_COLS, notesCol: NOTES_COL } = layout;
19
22
  const setCount = exercise.sets.length;
20
- const hasGroupLabel = exercise.groupLabel !== undefined;
21
- const lastBlockRow = startRow + setCount - 1;
23
+ const hasGroupLabel = opts.label !== undefined;
24
+ // The label shares the last set's row; a one-set block gets an extra row
25
+ // for it, left empty of prescriptions.
26
+ const rowCount = hasGroupLabel && setCount === 1 ? 2 : setCount;
27
+ const lastBlockRow = startRow + rowCount - 1;
22
28
  // Where the exercise-name region ends.
23
- const nameLastRow = hasGroupLabel && setCount > 1 ? lastBlockRow - 1 : lastBlockRow;
29
+ const nameLastRow = hasGroupLabel ? lastBlockRow - 1 : lastBlockRow;
24
30
  if (nameLastRow > startRow) {
25
31
  ws.mergeCells(`${EXERCISE_NAME_COL}${startRow}:${EXERCISE_NAME_COL}${nameLastRow}`);
26
32
  }
27
33
  const nameCell = ws.getCell(`${EXERCISE_NAME_COL}${startRow}`);
28
34
  nameCell.value = exercise.name;
29
35
  Object.assign(nameCell, exerciseNameStyle(opts.topBorder));
30
- if (hasGroupLabel && setCount > 1) {
36
+ if (hasGroupLabel) {
31
37
  const groupCell = ws.getCell(`${EXERCISE_NAME_COL}${lastBlockRow}`);
32
- groupCell.value = exercise.groupLabel;
38
+ groupCell.value = opts.label;
33
39
  Object.assign(groupCell, groupLabelStyle(opts.bottomBorder));
34
40
  }
35
41
  else if (!hasGroupLabel && opts.bottomBorder === "medium") {
@@ -44,27 +50,28 @@ export function stampExercise(ws, startRow, exercise, opts) {
44
50
  };
45
51
  Object.assign(nameCell, composed);
46
52
  }
47
- // Notes column P: merge across the whole block when there's more than one row.
48
- if (setCount > 1) {
53
+ // Notes column: merge across the whole block when there's more than one row.
54
+ if (rowCount > 1) {
49
55
  ws.mergeCells(`${NOTES_COL}${startRow}:${NOTES_COL}${lastBlockRow}`);
50
56
  }
51
57
  const noteCell = ws.getCell(`${NOTES_COL}${startRow}`);
52
58
  noteCell.value = exercise.notes ?? "";
53
59
  Object.assign(noteCell, NOTES_CELL);
54
60
  // Per-set per-week cells
55
- for (let setIdx = 0; setIdx < setCount; setIdx++) {
61
+ for (let setIdx = 0; setIdx < rowCount; setIdx++) {
56
62
  const r = startRow + setIdx;
57
63
  const isTop = setIdx === 0;
58
- const isBottom = setIdx === setCount - 1;
59
- const setRow = exercise.sets[setIdx];
60
- for (let weekIdx = 0; weekIdx < 6; weekIdx++) {
64
+ const isBottom = setIdx === rowCount - 1;
65
+ const setRow = exercise.sets[setIdx] ?? [];
66
+ const weightRow = exercise.weights?.[setIdx];
67
+ for (let weekIdx = 0; weekIdx < layout.weekCount; weekIdx++) {
61
68
  const repsCol = WEEK_REPS_COLS[weekIdx];
62
69
  const weightCol = WEEK_WEIGHT_COLS[weekIdx];
63
70
  const repsCell = ws.getCell(`${repsCol}${r}`);
64
71
  repsCell.value = setRow[weekIdx] ?? null;
65
72
  Object.assign(repsCell, weekRepsCellStyle({ isTop, isBottom }));
66
73
  const weightCell = ws.getCell(`${weightCol}${r}`);
67
- weightCell.value = null;
74
+ weightCell.value = weightRow?.[weekIdx] ?? null;
68
75
  Object.assign(weightCell, weekWeightCellStyle({ isTop, isBottom }));
69
76
  }
70
77
  }