@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.
- package/README.md +139 -35
- package/dist/index.d.ts +6 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -3
- package/dist/index.js.map +1 -1
- package/dist/reader/cell-utils.d.ts +10 -0
- package/dist/reader/cell-utils.d.ts.map +1 -0
- package/dist/reader/cell-utils.js +40 -0
- package/dist/reader/cell-utils.js.map +1 -0
- package/dist/reader/parse-day-sheet.d.ts +0 -1
- package/dist/reader/parse-day-sheet.d.ts.map +1 -1
- package/dist/reader/parse-day-sheet.js +95 -75
- package/dist/reader/parse-day-sheet.js.map +1 -1
- package/dist/reader/parse-warmup-workbook.d.ts +13 -0
- package/dist/reader/parse-warmup-workbook.d.ts.map +1 -0
- package/dist/reader/parse-warmup-workbook.js +154 -0
- package/dist/reader/parse-warmup-workbook.js.map +1 -0
- package/dist/reader/parse-workbook.d.ts +2 -2
- package/dist/reader/parse-workbook.d.ts.map +1 -1
- package/dist/reader/parse-workbook.js +1 -6
- package/dist/reader/parse-workbook.js.map +1 -1
- package/dist/schema/program.d.ts +398 -67
- package/dist/schema/program.d.ts.map +1 -1
- package/dist/schema/program.js +135 -28
- package/dist/schema/program.js.map +1 -1
- package/dist/schema/warmup.d.ts +426 -0
- package/dist/schema/warmup.d.ts.map +1 -0
- package/dist/schema/warmup.js +100 -0
- package/dist/schema/warmup.js.map +1 -0
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +51 -18
- package/dist/server.js.map +1 -1
- package/dist/tools/program-json-to-xlsx.d.ts +3 -0
- package/dist/tools/program-json-to-xlsx.d.ts.map +1 -0
- package/dist/tools/program-json-to-xlsx.js +5 -0
- package/dist/tools/program-json-to-xlsx.js.map +1 -0
- package/dist/tools/program-xlsx-to-json.d.ts +3 -0
- package/dist/tools/program-xlsx-to-json.d.ts.map +1 -0
- package/dist/tools/program-xlsx-to-json.js +5 -0
- package/dist/tools/program-xlsx-to-json.js.map +1 -0
- package/dist/tools/warmup-json-to-xlsx.d.ts +3 -0
- package/dist/tools/warmup-json-to-xlsx.d.ts.map +1 -0
- package/dist/tools/warmup-json-to-xlsx.js +5 -0
- package/dist/tools/warmup-json-to-xlsx.js.map +1 -0
- package/dist/tools/warmup-xlsx-to-json.d.ts +3 -0
- package/dist/tools/warmup-xlsx-to-json.d.ts.map +1 -0
- package/dist/tools/warmup-xlsx-to-json.js +5 -0
- package/dist/tools/warmup-xlsx-to-json.js.map +1 -0
- package/dist/writer/build-warmup-workbook.d.ts +3 -0
- package/dist/writer/build-warmup-workbook.d.ts.map +1 -0
- package/dist/writer/build-warmup-workbook.js +101 -0
- package/dist/writer/build-warmup-workbook.js.map +1 -0
- package/dist/writer/build-workbook.d.ts +2 -2
- package/dist/writer/build-workbook.d.ts.map +1 -1
- package/dist/writer/build-workbook.js +19 -23
- package/dist/writer/build-workbook.js.map +1 -1
- package/dist/writer/layout.d.ts +19 -7
- package/dist/writer/layout.d.ts.map +1 -1
- package/dist/writer/layout.js +40 -21
- package/dist/writer/layout.js.map +1 -1
- package/dist/writer/stamp-exercise.d.ts +13 -5
- package/dist/writer/stamp-exercise.d.ts.map +1 -1
- package/dist/writer/stamp-exercise.js +25 -18
- package/dist/writer/stamp-exercise.js.map +1 -1
- package/dist/writer/supplemental-template.d.ts +3 -2
- package/dist/writer/supplemental-template.d.ts.map +1 -1
- package/dist/writer/supplemental-template.js +15 -15
- package/dist/writer/supplemental-template.js.map +1 -1
- package/package.json +5 -4
- package/skills/olympia-authoring/SKILL.md +140 -0
|
@@ -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 @@
|
|
|
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 @@
|
|
|
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 @@
|
|
|
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 @@
|
|
|
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 @@
|
|
|
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
|
|
2
|
-
export declare function
|
|
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,
|
|
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 {
|
|
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
|
|
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
|
|
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 <
|
|
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 <
|
|
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 ===
|
|
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 <
|
|
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 <
|
|
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 <
|
|
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
|
-
|
|
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":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,QAAQ,IAAI,EAAE,EAAE,MAAM,SAAS,CAAC;AACzC,OAAO,OAAO,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"build-workbook.js","sourceRoot":"","sources":["../../src/writer/build-workbook.ts"],"names":[],"mappings":"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"}
|
package/dist/writer/layout.d.ts
CHANGED
|
@@ -1,14 +1,26 @@
|
|
|
1
|
-
export
|
|
2
|
-
|
|
3
|
-
|
|
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":"
|
|
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"}
|
package/dist/writer/layout.js
CHANGED
|
@@ -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
|
-
|
|
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,
|
|
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
|
|
18
|
-
* when N > 2);
|
|
19
|
-
* -
|
|
20
|
-
*
|
|
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;
|
|
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
|
|
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
|
|
8
|
-
* when N > 2);
|
|
9
|
-
* -
|
|
10
|
-
*
|
|
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 =
|
|
21
|
-
|
|
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
|
|
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
|
|
36
|
+
if (hasGroupLabel) {
|
|
31
37
|
const groupCell = ws.getCell(`${EXERCISE_NAME_COL}${lastBlockRow}`);
|
|
32
|
-
groupCell.value =
|
|
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
|
|
48
|
-
if (
|
|
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 <
|
|
61
|
+
for (let setIdx = 0; setIdx < rowCount; setIdx++) {
|
|
56
62
|
const r = startRow + setIdx;
|
|
57
63
|
const isTop = setIdx === 0;
|
|
58
|
-
const isBottom = setIdx ===
|
|
59
|
-
const setRow = exercise.sets[setIdx];
|
|
60
|
-
|
|
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
|
}
|