-
Notifications
You must be signed in to change notification settings - Fork 230
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
(v2) feat: add compat package #419
base: v2-exp
Are you sure you want to change the base?
Changes from all commits
957a940
e68eda7
5ee3169
8dd2b50
4cd6f14
a89b24a
7cdc043
031ae83
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
package compat | ||
|
||
import ( | ||
"os" | ||
|
||
"github.com/charmbracelet/colorprofile" | ||
"github.com/charmbracelet/lipgloss/v2" | ||
) | ||
|
||
var ( | ||
// HasDarkBackground is true if the terminal has a dark background. | ||
HasDarkBackground = func() bool { | ||
hdb, _ := lipgloss.HasDarkBackground(os.Stdin, os.Stdout) | ||
return hdb | ||
}() | ||
|
||
// Profile is the color profile of the terminal. | ||
Profile = colorprofile.Detect(os.Stdout, os.Environ()) | ||
) | ||
|
||
// AdaptiveColor provides color options for light and dark backgrounds. The | ||
// appropriate color will be returned at runtime based on the darkness of the | ||
// terminal background color. | ||
// | ||
// Example usage: | ||
// | ||
// color := lipgloss.AdaptiveColor{Light: "#0000ff", Dark: "#000099"} | ||
type AdaptiveColor struct { | ||
Light any | ||
Dark any | ||
} | ||
|
||
// RGBA returns the RGBA value of this color. This satisfies the Go Color | ||
// interface. | ||
func (c AdaptiveColor) RGBA() (uint32, uint32, uint32, uint32) { | ||
if HasDarkBackground { | ||
return lipgloss.Color(c.Dark).RGBA() | ||
} | ||
return lipgloss.Color(c.Light).RGBA() | ||
} | ||
|
||
// CompleteColor specifies exact values for truecolor, ANSI256, and ANSI color | ||
// profiles. Automatic color degradation will not be performed. | ||
type CompleteColor struct { | ||
TrueColor any | ||
ANSI256 any | ||
ANSI any | ||
} | ||
|
||
// RGBA returns the RGBA value of this color. This satisfies the Go Color | ||
// interface. | ||
func (c CompleteColor) RGBA() (uint32, uint32, uint32, uint32) { | ||
switch Profile { | ||
Check failure on line 53 in compat/color.go GitHub Actions / lint / lint-soft (ubuntu-latest)
Check failure on line 53 in compat/color.go GitHub Actions / lint / lint-soft (macos-latest)
Check failure on line 53 in compat/color.go GitHub Actions / lint / lint-soft (windows-latest)
Check failure on line 53 in compat/color.go GitHub Actions / lint / lint-soft (ubuntu-latest)
Check failure on line 53 in compat/color.go GitHub Actions / lint / lint-soft (macos-latest)
|
||
case colorprofile.TrueColor: | ||
return lipgloss.Color(c.TrueColor).RGBA() | ||
case colorprofile.ANSI256: | ||
return lipgloss.Color(c.ANSI256).RGBA() | ||
case colorprofile.ANSI: | ||
return lipgloss.Color(c.ANSI).RGBA() | ||
} | ||
return lipgloss.NoColor{}.RGBA() | ||
} | ||
|
||
// CompleteAdaptiveColor specifies exact values for truecolor, ANSI256, and ANSI color | ||
// profiles, with separate options for light and dark backgrounds. Automatic | ||
// color degradation will not be performed. | ||
type CompleteAdaptiveColor struct { | ||
Light CompleteColor | ||
Dark CompleteColor | ||
} | ||
|
||
// RGBA returns the RGBA value of this color. This satisfies the Go Color | ||
// interface. | ||
func (c CompleteAdaptiveColor) RGBA() (uint32, uint32, uint32, uint32) { | ||
if HasDarkBackground { | ||
return c.Dark.RGBA() | ||
} | ||
return c.Light.RGBA() | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
// Package compat is a compatibility layer for Lip Gloss that provides a way to | ||
// deal with the hassle of setting up a writer. It's impure because it uses | ||
// global variables, is not thread-safe, and only works with the default | ||
// standard I/O streams. | ||
// | ||
// In case you want [os.Stderr] to be used as the default writer, you can set | ||
// both [Writer] and [HasDarkBackground] to use [os.Stderr] with | ||
// the following code: | ||
// | ||
// import ( | ||
// "os" | ||
// | ||
// "github.com/charmbracelet/colorprofile" | ||
// "github.com/charmbracelet/lipgloss/v2/impure" | ||
// ) | ||
// | ||
// func init() { | ||
// impure.Writer = colorprofile.NewWriter(os.Stderr, os.Environ()) | ||
// impure.HasDarkBackground, _ = lipgloss.HasDarkBackground(os.Stdin, os.Stderr) | ||
// } | ||
package compat |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,144 @@ | ||
package main | ||
|
||
import ( | ||
"fmt" | ||
"os" | ||
|
||
tea "github.com/charmbracelet/bubbletea/v2" | ||
"github.com/charmbracelet/lipgloss/v2" | ||
"github.com/charmbracelet/lipgloss/v2/compat" | ||
) | ||
|
||
var ( | ||
frameColor = compat.AdaptiveColor{Light: lipgloss.Color("#C5ADF9"), Dark: lipgloss.Color("#864EFF")} | ||
textColor = compat.AdaptiveColor{Light: lipgloss.Color("#696969"), Dark: lipgloss.Color("#bdbdbd")} | ||
keywordColor = compat.AdaptiveColor{Light: lipgloss.Color("#37CD96"), Dark: lipgloss.Color("#22C78A")} | ||
inactiveBgColor = compat.AdaptiveColor{Light: lipgloss.Color(0x988F95), Dark: lipgloss.Color(0x978692)} | ||
inactiveFgColor = compat.AdaptiveColor{Light: lipgloss.Color(0xFDFCE3), Dark: lipgloss.Color(0xFBFAE7)} | ||
) | ||
|
||
// Style definitions. | ||
type styles struct { | ||
frame, | ||
paragraph, | ||
text, | ||
keyword, | ||
activeButton, | ||
inactiveButton lipgloss.Style | ||
} | ||
|
||
// Styles are initialized based on the background color of the terminal. | ||
func newStyles() (s styles) { | ||
// Define some styles. adaptive.Color() can be used to choose the | ||
// appropriate light or dark color based on the detected background color. | ||
s.frame = lipgloss.NewStyle(). | ||
Border(lipgloss.RoundedBorder()). | ||
BorderForeground(frameColor). | ||
Padding(1, 3). | ||
Margin(1, 3) | ||
s.paragraph = lipgloss.NewStyle(). | ||
Width(40). | ||
MarginBottom(1). | ||
Align(lipgloss.Center) | ||
s.text = lipgloss.NewStyle(). | ||
Foreground(textColor) | ||
s.keyword = lipgloss.NewStyle(). | ||
Foreground(keywordColor). | ||
Bold(true) | ||
|
||
s.activeButton = lipgloss.NewStyle(). | ||
Padding(0, 3). | ||
Background(lipgloss.Color(0xFF6AD2)). // you can also use octal format for colors, i.e 0xff38ec. | ||
Foreground(lipgloss.Color(0xFFFCC2)) | ||
s.inactiveButton = s.activeButton. | ||
Background(inactiveBgColor). | ||
Foreground(inactiveFgColor) | ||
return s | ||
} | ||
|
||
type model struct { | ||
styles styles | ||
yes bool | ||
chosen bool | ||
aborted bool | ||
} | ||
|
||
func (m model) Init() (tea.Model, tea.Cmd) { | ||
m.yes = true | ||
m.styles = newStyles() | ||
return m, nil | ||
} | ||
|
||
func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { | ||
switch msg := msg.(type) { | ||
case tea.KeyPressMsg: | ||
switch msg.String() { | ||
case "q", "esc", "ctrl+c": | ||
m.aborted = true | ||
return m, tea.Quit | ||
case "enter": | ||
m.chosen = true | ||
return m, tea.Quit | ||
case "left", "right", "h", "l": | ||
m.yes = !m.yes | ||
case "y": | ||
m.yes = true | ||
m.chosen = true | ||
return m, tea.Quit | ||
case "n": | ||
m.yes = false | ||
m.chosen = true | ||
return m, tea.Quit | ||
} | ||
} | ||
|
||
return m, nil | ||
} | ||
|
||
func (m model) View() string { | ||
if m.chosen || m.aborted { | ||
// We're about to exit, so wipe the UI. | ||
return "" | ||
} | ||
|
||
var ( | ||
s = m.styles | ||
y = "Yes" | ||
n = "No" | ||
) | ||
|
||
if m.yes { | ||
y = s.activeButton.Render(y) | ||
n = s.inactiveButton.Render(n) | ||
} else { | ||
y = s.inactiveButton.Render(y) | ||
n = s.activeButton.Render(n) | ||
} | ||
|
||
return s.frame.Render( | ||
lipgloss.JoinVertical(lipgloss.Center, | ||
s.paragraph.Render( | ||
s.text.Render("Are you sure you want to eat that ")+ | ||
s.keyword.Render("moderatly ripe")+ | ||
s.text.Render(" banana?"), | ||
), | ||
y+" "+n, | ||
), | ||
) | ||
} | ||
|
||
func main() { | ||
m, err := tea.NewProgram(model{}).Run() | ||
if err != nil { | ||
fmt.Fprintf(os.Stderr, "Uh oh: %v", err) | ||
os.Exit(1) | ||
} | ||
|
||
if m := m.(model); m.chosen { | ||
if m.yes { | ||
fmt.Println("Are you sure? It's not ripe yet.") | ||
} else { | ||
fmt.Println("Well, alright. It was probably good, though.") | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
// This example illustrates how to detect the terminal's background color and | ||
// choose either light or dark colors accordingly when using Lip Gloss in a. | ||
// standalone fashion, i.e. independent of Bubble Tea. | ||
// | ||
// For an example of how to do this in a Bubble Tea program, see the | ||
// 'bubbletea' example. | ||
package main | ||
|
||
import ( | ||
"github.com/charmbracelet/lipgloss/v2" | ||
"github.com/charmbracelet/lipgloss/v2/compat" | ||
) | ||
|
||
var ( | ||
frameColor = compat.AdaptiveColor{Light: lipgloss.Color("#C5ADF9"), Dark: lipgloss.Color("#864EFF")} | ||
textColor = compat.AdaptiveColor{Light: lipgloss.Color("#696969"), Dark: lipgloss.Color("#bdbdbd")} | ||
keywordColor = compat.AdaptiveColor{Light: lipgloss.Color("#37CD96"), Dark: lipgloss.Color("#22C78A")} | ||
inactiveBgColor = compat.AdaptiveColor{Light: lipgloss.Color(0x988F95), Dark: lipgloss.Color(0x978692)} | ||
inactiveFgColor = compat.AdaptiveColor{Light: lipgloss.Color(0xFDFCE3), Dark: lipgloss.Color(0xFBFAE7)} | ||
) | ||
|
||
func main() { | ||
// Define some styles. adaptive.Color() can be used to choose the | ||
// appropriate light or dark color based on the detected background color. | ||
frameStyle := lipgloss.NewStyle(). | ||
Border(lipgloss.RoundedBorder()). | ||
BorderForeground(frameColor). | ||
Padding(1, 3). | ||
Margin(1, 3) | ||
paragraphStyle := lipgloss.NewStyle(). | ||
Width(40). | ||
MarginBottom(1). | ||
Align(lipgloss.Center) | ||
textStyle := lipgloss.NewStyle(). | ||
Foreground(textColor) | ||
keywordStyle := lipgloss.NewStyle(). | ||
Foreground(keywordColor). | ||
Bold(true) | ||
|
||
activeButton := lipgloss.NewStyle(). | ||
Padding(0, 3). | ||
Background(lipgloss.Color(0xFF6AD2)). // you can also use octal format for colors, i.e 0xff38ec. | ||
Foreground(lipgloss.Color(0xFFFCC2)) | ||
inactiveButton := activeButton. | ||
Background(inactiveBgColor). | ||
Foreground(inactiveFgColor) | ||
|
||
// Build layout. | ||
text := paragraphStyle.Render( | ||
textStyle.Render("Are you sure you want to eat that ") + | ||
keywordStyle.Render("moderatly ripe") + | ||
textStyle.Render(" banana?"), | ||
) | ||
buttons := activeButton.Render("Yes") + " " + inactiveButton.Render("No") | ||
block := frameStyle.Render( | ||
lipgloss.JoinVertical(lipgloss.Center, text, buttons), | ||
) | ||
|
||
// Print the block to stdout. It's important to use Lip Gloss's print | ||
// functions to ensure that colors are downsampled correctly. If output | ||
// isn't a TTY (i.e. we're logging to a file) colors will be stripped | ||
// entirely. | ||
// | ||
// Note that in Bubble Tea downsampling happens automatically. | ||
lipgloss.Println(block) | ||
} |
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.
compat is not a go module... I think this isn't needed 🤔
same goes for table above 🤔