loadingView renders an animated hourglass centered in the content area.
(width, contentHeight int, phase float64)
| 155 | |
| 156 | // loadingView renders an animated hourglass centered in the content area. |
| 157 | func loadingView(width, contentHeight int, phase float64) string { |
| 158 | if width < hourglassVisualWidth || contentHeight < 2 { |
| 159 | return "Loading..." |
| 160 | } |
| 161 | |
| 162 | frame := hourglassFrames[hourglassFrameIndex(phase)] |
| 163 | |
| 164 | glass := lipgloss.NewStyle().Foreground(colorPrimary) |
| 165 | label := styleMuted |
| 166 | |
| 167 | // Build centered lines |
| 168 | padLeft := (width - hourglassVisualWidth) / 2 |
| 169 | if padLeft < 0 { |
| 170 | padLeft = 0 |
| 171 | } |
| 172 | prefix := strings.Repeat(" ", padLeft) |
| 173 | |
| 174 | var lines []string |
| 175 | for _, line := range frame { |
| 176 | lines = append(lines, prefix+glass.Render(line)) |
| 177 | } |
| 178 | |
| 179 | // "Loading..." label centered below |
| 180 | labelText := "Loading..." |
| 181 | labelPad := (width - len(labelText)) / 2 |
| 182 | if labelPad < 0 { |
| 183 | labelPad = 0 |
| 184 | } |
| 185 | lines = append(lines, strings.Repeat(" ", labelPad)+label.Render(labelText)) |
| 186 | |
| 187 | // Vertical centering |
| 188 | totalLines := len(lines) |
| 189 | topPad := (contentHeight - totalLines) / 2 |
| 190 | if topPad < 0 { |
| 191 | topPad = 0 |
| 192 | } |
| 193 | |
| 194 | var b strings.Builder |
| 195 | for range topPad { |
| 196 | b.WriteString("\n") |
| 197 | } |
| 198 | b.WriteString(strings.Join(lines, "\n")) |
| 199 | |
| 200 | return b.String() |
| 201 | } |
no test coverage detected