calculateModalHeight determines the dynamic modal height based on content.
()
| 268 | |
| 269 | // calculateModalHeight determines the dynamic modal height based on content. |
| 270 | func (c *CompletionScreen) calculateModalHeight() int { |
| 271 | // Base: header(1) + subtitle(1) + divider(1) + blank(1) + duration(1) + blank(1) |
| 272 | // + branch(1) + blank(1) + divider(1) + footer(1) + padding(2) = ~12 |
| 273 | base := 12 |
| 274 | |
| 275 | // Story timings |
| 276 | storyLines := len(c.storyTimings) |
| 277 | maxStoryLines := c.height - base - 6 |
| 278 | if maxStoryLines < 3 { |
| 279 | maxStoryLines = 3 |
| 280 | } |
| 281 | if storyLines > maxStoryLines { |
| 282 | storyLines = maxStoryLines + 1 // +1 for "... and N more" |
| 283 | } |
| 284 | if storyLines > 0 { |
| 285 | storyLines++ // blank line before stories |
| 286 | } |
| 287 | |
| 288 | // Auto-action lines |
| 289 | autoLines := 0 |
| 290 | if c.pushState != AutoActionIdle { |
| 291 | autoLines++ |
| 292 | } |
| 293 | if c.prState != AutoActionIdle { |
| 294 | autoLines++ |
| 295 | if c.prState == AutoActionSuccess { |
| 296 | autoLines++ // URL line |
| 297 | } |
| 298 | } |
| 299 | if !c.hasAutoActions && c.pushState == AutoActionIdle && c.prState == AutoActionIdle { |
| 300 | autoLines++ // hint line |
| 301 | } |
| 302 | |
| 303 | // No duration line if zero |
| 304 | durationLine := 0 |
| 305 | if c.totalDuration > 0 { |
| 306 | durationLine = 2 // blank + duration text |
| 307 | } |
| 308 | |
| 309 | calculated := base + storyLines + autoLines + durationLine |
| 310 | maxHeight := c.height - 4 |
| 311 | if maxHeight < 10 { |
| 312 | maxHeight = 10 |
| 313 | } |
| 314 | if calculated > maxHeight { |
| 315 | calculated = maxHeight |
| 316 | } |
| 317 | if calculated < 10 { |
| 318 | calculated = 10 |
| 319 | } |
| 320 | return calculated |
| 321 | } |
| 322 | |
| 323 | // renderStoryTimings renders the per-story timing list with mini bar charts. |
| 324 | func (c *CompletionScreen) renderStoryTimings(innerWidth int) string { |