1- import { createCanvas , Canvas , CanvasRenderingContext2D } from 'canvas' ;
2- import { calculatePace , formatTime , type LogbookResult } from '../logbook/client' ;
1+ import { createCanvas , Canvas , CanvasRenderingContext2D } from "canvas" ;
2+ import {
3+ calculatePace ,
4+ formatTime ,
5+ type LogbookResult ,
6+ } from "../logbook/client" ;
37
48// Define types for better type safety
59interface WorkoutRow {
@@ -10,17 +14,16 @@ interface WorkoutRow {
1014}
1115
1216interface DaisyForestColors {
13- base100 : string ; // Main background
14- base200 : string ; // Secondary background
15- base300 : string ; // Tertiary background
17+ base100 : string ; // Main background
18+ base200 : string ; // Secondary background
19+ base300 : string ; // Tertiary background
1620 baseContent : string ; // Light text
17- primary : string ; // Primary green
18- secondary : string ; // Secondary teal
19- accent : string ; // Accent cyan
20- neutral : string ; // Neutral gray
21+ primary : string ; // Primary green
22+ secondary : string ; // Secondary teal
23+ accent : string ; // Accent cyan
24+ neutral : string ; // Neutral gray
2125}
2226
23-
2427// // Helper function to format pace (time per 500m)
2528// function formatPace(timeInSeconds: number, distanceInMeters: number): string {
2629// const paceSeconds = (timeInSeconds / distanceInMeters) * 500;
@@ -36,21 +39,23 @@ function formatDistance(meters: number): string {
3639
3740// Helper function to format stroke rate
3841function formatStrokeRate ( rate : number ) : string {
39- return rate ? rate . toString ( ) : '0' ;
42+ return rate ? rate . toString ( ) : "0" ;
4043}
4144
42- export function generateWorkoutDisplay ( username : string , logbookResult : LogbookResult ) : Buffer {
43-
45+ export function generateWorkoutDisplay (
46+ username : string ,
47+ logbookResult : LogbookResult ,
48+ ) : Buffer {
4449 // DaisyUI Forest theme color palette
4550 const colors : DaisyForestColors = {
46- base100 : ' #1F2937' , // Main dark background
47- base200 : ' #111827' , // Darker background
48- base300 : ' #0F172A' , // Darkest background
49- baseContent : ' #F9FAFB' , // Light text
50- primary : ' #22C55E' , // Primary green
51- secondary : ' #14B8A6' , // Secondary teal
52- accent : ' #06B6D4' , // Accent cyan
53- neutral : ' #374151' // Neutral gray
51+ base100 : " #1F2937" , // Main dark background
52+ base200 : " #111827" , // Darker background
53+ base300 : " #0F172A" , // Darkest background
54+ baseContent : " #F9FAFB" , // Light text
55+ primary : " #22C55E" , // Primary green
56+ secondary : " #14B8A6" , // Secondary teal
57+ accent : " #06B6D4" , // Accent cyan
58+ neutral : " #374151" , // Neutral gray
5459 } ;
5560
5661 // Prepare workout data
@@ -61,7 +66,7 @@ export function generateWorkoutDisplay(username: string, logbookResult: LogbookR
6166 time : formatTime ( logbookResult . time ) ,
6267 meter : formatDistance ( logbookResult . distance ) ,
6368 pace : formatTime ( calculatePace ( logbookResult . distance , logbookResult . time ) ) ,
64- strokeRate : formatStrokeRate ( logbookResult . strokeRate )
69+ strokeRate : formatStrokeRate ( logbookResult . strokeRate ) ,
6570 } ) ;
6671
6772 // Add splits or intervals if available
@@ -71,28 +76,31 @@ export function generateWorkoutDisplay(username: string, logbookResult: LogbookR
7176 time : formatTime ( split . time ) ,
7277 meter : formatDistance ( split . distance ) ,
7378 pace : formatTime ( calculatePace ( split . distance , split . time ) ) ,
74- strokeRate : formatStrokeRate ( split . strokeRate )
79+ strokeRate : formatStrokeRate ( split . strokeRate ) ,
7580 } ) ;
7681 }
77- } else if ( logbookResult . workout . intervals && logbookResult . workout . intervals . length > 0 ) {
82+ } else if (
83+ logbookResult . workout . intervals &&
84+ logbookResult . workout . intervals . length > 0
85+ ) {
7886 for ( const interval of logbookResult . workout . intervals ) {
7987 workoutRows . push ( {
8088 time : formatTime ( interval . time ) ,
8189 meter : formatDistance ( interval . distance ) ,
8290 pace : formatTime ( calculatePace ( interval . distance , interval . time ) ) ,
83- strokeRate : formatStrokeRate ( interval . strokeRate )
91+ strokeRate : formatStrokeRate ( interval . strokeRate ) ,
8492 } ) ;
8593 }
8694 }
8795
8896 // Calculate dynamic height based on number of rows
8997 const baseHeight = 270 ; // Base height for headers, borders, footer (reduced by 30)
9098 const rowHeight = 28 ;
91- const totalHeight = baseHeight + ( workoutRows . length * rowHeight ) ;
99+ const totalHeight = baseHeight + workoutRows . length * rowHeight ;
92100
93101 // Create canvas with dynamic height
94102 const canvas : Canvas = createCanvas ( 550 , totalHeight ) ;
95- const ctx : CanvasRenderingContext2D = canvas . getContext ( '2d' ) ;
103+ const ctx : CanvasRenderingContext2D = canvas . getContext ( "2d" ) ;
96104
97105 // Fill background with base color
98106 ctx . fillStyle = colors . base300 ;
@@ -130,8 +138,10 @@ export function generateWorkoutDisplay(username: string, logbookResult: LogbookR
130138 ctx . fillStyle = colors . accent ;
131139 ctx . shadowColor = colors . accent ;
132140 ctx . shadowBlur = 8 ;
133- ctx . font = 'bold 20px monospace' ;
134- const dateStr = logbookResult . date ? new Date ( logbookResult . date ) . toISOString ( ) . split ( 'T' ) [ 0 ] : new Date ( ) . toISOString ( ) . split ( 'T' ) [ 0 ] ;
141+ ctx . font = "bold 20px monospace" ;
142+ const dateStr = logbookResult . date
143+ ? new Date ( logbookResult . date ) . toISOString ( ) . split ( "T" ) [ 0 ]
144+ : new Date ( ) . toISOString ( ) . split ( "T" ) [ 0 ] ;
135145 ctx . fillText ( `>>> ${ dateStr } <<<` , 60 , 80 ) ;
136146 ctx . shadowBlur = 0 ;
137147
@@ -157,14 +167,14 @@ export function generateWorkoutDisplay(username: string, logbookResult: LogbookR
157167 ctx . fillStyle = colors . baseContent ;
158168 ctx . shadowColor = colors . baseContent ;
159169 ctx . shadowBlur = 5 ;
160- ctx . font = ' bold 16px monospace' ;
170+ ctx . font = " bold 16px monospace" ;
161171
162172 // Right-align all headers to match the data columns
163- ctx . textAlign = ' right' ;
164- ctx . fillText ( ' TIME' , 160 , 145 ) ;
165- ctx . fillText ( ' METERS' , 260 , 145 ) ;
166- ctx . fillText ( ' PACE/500M' , 400 , 145 ) ;
167- ctx . fillText ( ' S/MIN' , 480 , 145 ) ;
173+ ctx . textAlign = " right" ;
174+ ctx . fillText ( " TIME" , 160 , 145 ) ;
175+ ctx . fillText ( " METERS" , 260 , 145 ) ;
176+ ctx . fillText ( " PACE/500M" , 400 , 145 ) ;
177+ ctx . fillText ( " S/MIN" , 480 , 145 ) ;
168178 ctx . shadowBlur = 0 ;
169179
170180 // Use the prepared workout data
@@ -181,7 +191,7 @@ export function generateWorkoutDisplay(username: string, logbookResult: LogbookR
181191 ctx . shadowBlur = 0 ;
182192
183193 // Draw all table rows with DaisyUI styling
184- ctx . font = ' 14px monospace' ;
194+ ctx . font = " 14px monospace" ;
185195 let yPos : number = 190 ;
186196
187197 rowData . forEach ( ( row : WorkoutRow , index : number ) => {
@@ -201,7 +211,7 @@ export function generateWorkoutDisplay(username: string, logbookResult: LogbookR
201211 }
202212
203213 // Right-align all columns for better alignment of numeric data
204- ctx . textAlign = ' right' ;
214+ ctx . textAlign = " right" ;
205215 ctx . fillText ( row . time , 160 , yPos ) ;
206216 ctx . fillText ( row . meter , 260 , yPos ) ;
207217 ctx . fillText ( row . pace , 400 , yPos ) ;
@@ -234,7 +244,7 @@ export function generateWorkoutDisplay(username: string, logbookResult: LogbookR
234244 ctx . fillRect ( 450 , decorationY + 10 , 4 , 8 ) ;
235245
236246 // Return the image buffer
237- const buffer : Buffer = canvas . toBuffer ( ' image/png' ) ;
247+ const buffer : Buffer = canvas . toBuffer ( " image/png" ) ;
238248 return buffer ;
239249}
240250
0 commit comments