94 lines
2.6 KiB
Go
94 lines
2.6 KiB
Go
// Package layout provides responsive dimension calculations for the Nebara OS TUI.
|
||
// All functions operate on terminal cell dimensions, not pixels.
|
||
package layout
|
||
|
||
// Constraints holds calculated layout values for a given terminal size.
|
||
type Constraints struct {
|
||
TermWidth int
|
||
TermHeight int
|
||
|
||
// Outer horizontal margin in cells (applied to both left and right sides).
|
||
MarginH int
|
||
// Outer vertical margin in cells (applied to top and bottom).
|
||
MarginV int
|
||
|
||
// ContentWidth is the usable width between the two horizontal margins.
|
||
ContentWidth int
|
||
|
||
// AppInfoLines is the number of rows reserved for appliance information
|
||
// (product title + 4 metadata rows).
|
||
AppInfoLines int
|
||
|
||
// MessageVisible indicates whether the message row should be shown.
|
||
// On very compact terminals it may be suppressed.
|
||
MessageVisible bool
|
||
|
||
// MenuInnerPad is the horizontal padding inside the menu border.
|
||
MenuInnerPad int
|
||
|
||
// FooterLines is the number of rows occupied by the footer (description + shortcuts).
|
||
FooterLines int
|
||
|
||
// IsMinimum flags terminals smaller than the supported minimum.
|
||
IsMinimum bool
|
||
}
|
||
|
||
// MinWidth is the smallest terminal width the application supports gracefully.
|
||
const MinWidth = 60
|
||
|
||
// MinHeight is the smallest terminal height the application supports gracefully.
|
||
const MinHeight = 20
|
||
|
||
// Calculate derives layout constraints from terminal dimensions.
|
||
// Reference: Figma frame 1920×1080 with 80px outer margins (4.17% of width)
|
||
// and 60px vertical margins (5.56% of height).
|
||
func Calculate(termW, termH int) Constraints {
|
||
if termW < MinWidth || termH < MinHeight {
|
||
return Constraints{
|
||
TermWidth: termW,
|
||
TermHeight: termH,
|
||
IsMinimum: true,
|
||
}
|
||
}
|
||
|
||
// Horizontal margin: ~4.17% of width, min 4 cells, max 12 cells.
|
||
marginH := clamp(termW*417/10000, 4, 12)
|
||
|
||
// Vertical margin: ~5.56% of height, min 1 cell, max 4 cells.
|
||
marginV := clamp(termH*556/10000, 1, 4)
|
||
|
||
contentWidth := termW - marginH*2
|
||
|
||
// Menu inner horizontal padding (space between border char and text).
|
||
menuInnerPad := 2
|
||
if termW < 100 {
|
||
menuInnerPad = 1
|
||
}
|
||
|
||
// Message row visibility: suppress on very compact terminals.
|
||
messageVisible := termH >= 24
|
||
|
||
return Constraints{
|
||
TermWidth: termW,
|
||
TermHeight: termH,
|
||
MarginH: marginH,
|
||
MarginV: marginV,
|
||
ContentWidth: contentWidth,
|
||
AppInfoLines: 6, // blank + product title + blank + 4 metadata rows
|
||
MessageVisible: messageVisible,
|
||
MenuInnerPad: menuInnerPad,
|
||
FooterLines: 2,
|
||
IsMinimum: false,
|
||
}
|
||
}
|
||
|
||
func clamp(v, lo, hi int) int {
|
||
if v < lo {
|
||
return lo
|
||
}
|
||
if v > hi {
|
||
return hi
|
||
}
|
||
return v
|
||
}
|