-
Notifications
You must be signed in to change notification settings - Fork 236
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: New Border Title API #97
base: master
Are you sure you want to change the base?
Conversation
Once the new API is agreed upon and stable, I will also update the documentation |
This looks really good @eugener, nice work! |
@maaslalani @meowgorithm Is there anything else needed to make this PR a part the next release? |
Hey, @eugener! We just need a little time to give this a proper review. Thanks for your patience with this one; we'll definitely get to it. |
Sounds good! Let me know how I can help. |
Another question I had, was would we want to support Bold / Italic / Underline / Padding / Margin in the border title? I almost wonder if the border title should take its own style or take only a string which we expect the user to style before passing in? I.e: borderTitle := lipgloss.NewStyle().Bold(true).Underline(true).Render("Hello, Borders")
lipgloss.NewStyle().BorderTitle(borderTitle).Border(lipgloss.DoubleBorder()) |
The idea of styled text is great and also makes the Title API surface smaller. |
I think there's two ways to do it, either we can get passed the styled text or take the The current API doesn't prevent people from passing in multi-line text (if I'm not mistaken), so I think it is reasonable to expect the user to pass in a non-multiline string / inline style. But, @meowgorithm may have more thoughts on this. Personally, I think it would be reasonable to remove the What do you think @meowgorithm @eugener? I'm not too opinionated on this one. Although, the way I have suggested does give the user more ways to break their application's layout, so maybe it's not worth the flexibility. |
That being said, I am also fully onboard with the current PR as it is. I think it is currently in a shippable state. |
We will need to offer at least the basic ANSI styling options for this (bold, underline, strikethrough, reverse, and so on) so it probably makes sense to pass a style. It would also give people more control over the spacing around the title. And we do have mechanisms to keep help prevent people from breaking stuff (see Enforcing Rules in the README as well as the various unset methods). So if we go down this route you'd either pass a styled string: borderEverything := lipgloss.NewStyle().
Bold(true).
Underline(true).
Render("Hello, Borders")
style := lipgloss.NewStyle().
BorderTitle(borderEverything).
Border(lipgloss.DoubleBorder()) Or you'd separate concerns a bit more and set the style and the string separately: borderTitleStyle := lipgloss.NewStyle().
Bold(true).
Underline(true)
style := lipgloss.NewStyle().
BorderTitleStyle(borderStyle).
BorderTitle("Hello, Borders").
Border(lipgloss.DoubleBorder()) And, in this scenario, I'd keep the very good |
…inates the need all other methods and add an ability to style the title itself.
@maaslalani @meowgorithm Thank you both for very insightful suggestions! |
I think using the |
This is great @eugener; thank you. Thinking on this some more, I would argue that it we will want to split out the style from the value both to be explicit, and to separate style from data for re-use as I expect a common use case to be rendering several similar looking boxes with different titles. Consider the following: titleStyle := lipgloss.NewStyle().
Bold(true).
Reverse(true)
mrBoxStyle := lipgloss.NewStyle().
BorderTitleStyle(borderStyle).
BorderTitle("Mr. Box").
Border(lipgloss.RoundedBorder())
mrsBoxStyle := mrBoxStyle.Copy().BorderTitle(“Mrs. Box”) More realistically, in a view this would look something like: boxA := boxStyle.Copy().BorderTitle(“Mr. Box”).Render(fancyData)
boxB := boxStyle.Copy().BorderTitle(“Mrs. Box”).Render(moreFancyData) This is, of course, doable in the current implementation but a bit more roundabout: mrTitle := lipgloss.NewStyle().
Bold(true).
Reverse(true).
SetString("Mr. Box")
mrsTitle := mrTitle.Copy().SetString(“Mrs. Box”)
mrBox := lipgloss.NewStyle().
BorderTitle(mrBox).
Border(lipgloss.RoundedBorder())
mrsBox := mrBox.Copy().BorderTitle(mrsTitle) And in a view this would look more like: boxA := boxStyle.BorderTitle(titleStyle.Copy().SetString(“Mr. Box”)).Render(fancyData)
boxB := boxStyle.BorderTitle(titleStyle.Copy().SetString(“Mrs. Box”)).Render(moreFancyData) |
@meowgorithm Agree! This makes border styles a lot more reusable. Will rework it as you suggest. |
Sounds good. Thanks for all your hard work on this, @eugener! |
The API is now reworked, including docs, example and readme. Hopefully I did not miss anything. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is fantastic @eugener. Taking a look now!
example/main.go
Outdated
@@ -239,7 +246,7 @@ func main() { | |||
|
|||
dialog := lipgloss.Place(width, 9, | |||
lipgloss.Center, lipgloss.Center, | |||
dialogBoxStyle.Render(ui), | |||
dialogBoxStyle.Copy().BorderTitle(" Question ").Render(ui), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would probably use Padding(0, 1)
instead of manually adding spaces to demonstrate the BorderTitleStyle
best practices.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Currently this does not work as I use actual text to calculate the required text width.
@maaslalani Do you know of any API to calculate the screen width of styled text?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe it might be GetHorizontalFrame
to calculate all the padding and margin horizontally and then add the width of the text.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd additionally add logic where, if horizontal padding is unset on the style it defaults to Padding(0, 1)
:
╭ Title ───
However if horizontal padding is set, accept it at face value. For example, PaddingLeft(0).PaddingRight(3)
would render as:
╭Title ───
borders.go
Outdated
@@ -296,6 +324,13 @@ func (s Style) applyBorder(str string) string { | |||
return out.String() | |||
} | |||
|
|||
func repeatStr(s string, count int) string { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is sort of a nitpick so feel free to ignore, but instead of having a wrapper around strings.Repeat
called repeatStr
I would do something like this:
strings.Repeat(border.Top, max(0, value))
Where max
is:
func max(a, b int) int {
if a > b {
return a
}
return b
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can use the max
defined here:
Lines 460 to 465 in 0ce5550
func max(a, b int) int { | |
if a > b { | |
return a | |
} | |
return b | |
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good suggestion... coming out with the next update :)
That is a matter of opinion :) Let's vote on this? |
Hey @eugener, we appreciate the awesome work you've put into this. We'll play around with this now as it is and some different options we have to achieve this functionality that we were toying around with and review this PR. Since this is a big change (changing the API), we want to make sure we're doing the correct approach so that we don't need to break it later on, so we might take a bit of extra time reviewing it. |
Introduce default padding if one is not present.
All the suggestions are implemented. The code is now in your hands (let me know how I can help). |
Love this! looking forward to seeing it released ❤️ |
Is there any plan to merge this or add similar functionality? |
Hey, thanks for your patience on this. We're still deciding what the public API should look like; the current solution in this PR includes some nested styles that we need to consider. In the meantime, we've got this gist that demonstrates how you can achieve this with the existing Lipgloss API. https://gist.github.com/meowgorithm/1777377a43373f563476a2bcb7d89306 |
Adds new Border Title API (requested in the issue #87):
func (s Style) BorderTitle(title string) Style
func (s Style) BorderTitleAlignment(alignment Position) Style
func (s Style) BorderTitleBackground(color TerminalColor) Style
func (s Style) BorderTitleForeground(color TerminalColor) Style
func (s Style) GetBorderTitle() string
func (s Style) GetBorderTitleAlignment() Position
func (s Style) GetBorderTitleBackground() TerminalColor
func (s Style) GetBorderTitleForeground() TerminalColor
Updated example:
