Lip Gloss

TUIStylingTerminalCSS-likeGo

GitHub概要

charmbracelet/lipgloss

Style definitions for nice terminal layouts 👄

スター9,305
ウォッチ35
フォーク259
作成日:2021年3月1日
言語:Go
ライセンス:MIT License

トピックス

cligogolanghacktoberfestlayoutstyletui

スター履歴

charmbracelet/lipgloss Star History
データ取得日時: 2025/7/25 11:09

Lip Gloss

Lip Glossは、Charmbraceletが開発したターミナルアプリケーション向けのスタイリングライブラリです。CSSに似た直感的なAPIで、ターミナルに美しいレイアウトとスタイルを適用できます。Bubble TeaやCharmエコシステムの一部として、多くのプロジェクトで使用されています。

特徴

CSSライクなスタイリング

  • プロパティ: 色、パディング、マージン、ボーダー
  • レイアウト: Flexbox風の配置、位置調整
  • テキスト装飾: 太字、斜体、下線、取り消し線
  • アニメーション: 点滅、フェード

高度な機能

  • アダプティブカラー: ターミナルの能力に応じた色調整
  • グラデーション: グラデーション背景
  • レスポンシブ: ターミナルサイズに応じた調整
  • スタイル継承: CSSのようなスタイル継承

ユーティリティ

  • テーブルレンダリング: 美しいテーブル作成
  • ジョイン機能: 要素の結合
  • 折り返しと省略: テキスト処理
  • カスタムレンダラー: 拡張可能な描画システム

パフォーマンス

  • ゼロアロケーション: スタイルの再利用
  • 効率的なレンダリング: 最小限のANSIコード
  • キャッシュ: スタイル計算のキャッシュ
  • 軽量: 最小限の依存関係

基本的な使用方法

インストール

go get github.com/charmbracelet/lipgloss

Hello World

package main

import (
    "fmt"
    "github.com/charmbracelet/lipgloss"
)

func main() {
    // 基本的なスタイル
    style := lipgloss.NewStyle().
        Bold(true).
        Foreground(lipgloss.Color("#FAFAFA")).
        Background(lipgloss.Color("#7D56F4")).
        PaddingTop(2).
        PaddingLeft(4).
        Width(22)
    
    fmt.Println(style.Render("Hello, Lip Gloss!"))
}

スタイルの組み合わせ

package main

import (
    "fmt"
    "github.com/charmbracelet/lipgloss"
)

func main() {
    // ベーススタイル
    var baseStyle = lipgloss.NewStyle().
        PaddingLeft(1).
        PaddingRight(1)
    
    // タイトルスタイル
    titleStyle := baseStyle.Copy().
        Bold(true).
        Foreground(lipgloss.Color("#FF00FF")).
        MarginTop(1).
        MarginBottom(1)
    
    // コンテンツスタイル
    contentStyle := baseStyle.Copy().
        Foreground(lipgloss.Color("#CCCCCC")).
        Padding(1, 2)
    
    // ボーダースタイル
    borderStyle := lipgloss.NewStyle().
        Border(lipgloss.RoundedBorder()).
        BorderForeground(lipgloss.Color("62")).
        Padding(1, 2)
    
    // レンダリング
    title := titleStyle.Render("ウェルカム")
    content := contentStyle.Render("これはLip Glossでスタイルされた\nコンテンツです。")
    
    // 結合
    output := lipgloss.JoinVertical(lipgloss.Left, title, content)
    
    fmt.Println(borderStyle.Render(output))
}

レイアウトと位置調整

package main

import (
    "fmt"
    "github.com/charmbracelet/lipgloss"
)

func main() {
    // ターミナルサイズの取得
    width := 80
    height := 24
    
    // ヘッダー
    headerStyle := lipgloss.NewStyle().
        Background(lipgloss.Color("62")).
        Foreground(lipgloss.Color("230")).
        Bold(true).
        Align(lipgloss.Center).
        Width(width).
        Padding(0, 1)
    
    header := headerStyle.Render("🌈 My Application")
    
    // サイドバー
    sidebarStyle := lipgloss.NewStyle().
        Border(lipgloss.NormalBorder(), false, true, false, false).
        BorderForeground(lipgloss.Color("240")).
        Width(20).
        Height(height - 4).
        Padding(1)
    
    sidebar := sidebarStyle.Render("Menu\n\n• Home\n• About\n• Contact")
    
    // メインコンテンツ
    mainStyle := lipgloss.NewStyle().
        Width(width - 22).
        Height(height - 4).
        Padding(2).
        Align(lipgloss.Center, lipgloss.Center)
    
    main := mainStyle.Render("メインコンテンツエリア")
    
    // フッター
    footerStyle := lipgloss.NewStyle().
        Background(lipgloss.Color("235")).
        Foreground(lipgloss.Color("241")).
        Align(lipgloss.Center).
        Width(width)
    
    footer := footerStyle.Render("Press q to quit")
    
    // レイアウトの組み立て
    body := lipgloss.JoinHorizontal(lipgloss.Top, sidebar, main)
    doc := lipgloss.JoinVertical(lipgloss.Left, header, body, footer)
    
    fmt.Println(doc)
}

テーブルの作成

package main

import (
    "fmt"
    "github.com/charmbracelet/lipgloss"
    "github.com/charmbracelet/lipgloss/table"
)

func main() {
    // テーブルデータ
    rows := [][]string{
        {"ID", "Name", "Age", "City"},
        {"1", "Alice", "30", "New York"},
        {"2", "Bob", "25", "Los Angeles"},
        {"3", "Charlie", "35", "Chicago"},
    }
    
    // テーブル作成
    t := table.New().
        Border(lipgloss.NormalBorder()).
        BorderStyle(lipgloss.NewStyle().Foreground(lipgloss.Color("99")))
    
    // ヘッダースタイル
    headerStyle := lipgloss.NewStyle().
        Bold(true).
        Foreground(lipgloss.Color("230")).
        Background(lipgloss.Color("63")).
        Align(lipgloss.Center)
    
    // 偶数行スタイル
    evenRowStyle := lipgloss.NewStyle().
        Foreground(lipgloss.Color("245"))
    
    // 奇数行スタイル
    oddRowStyle := lipgloss.NewStyle().
        Foreground(lipgloss.Color("250"))
    
    // テーブルにスタイル適用
    t.Headers(rows[0]...).
        StyleFunc(func(row, col int) lipgloss.Style {
            if row == 0 {
                return headerStyle
            }
            if row%2 == 0 {
                return evenRowStyle
            }
            return oddRowStyle
        })
    
    // データ追加
    for _, row := range rows[1:] {
        t.Row(row...)
    }
    
    fmt.Println(t)
}

グラデーションとアニメーション

package main

import (
    "fmt"
    "github.com/charmbracelet/lipgloss"
)

func main() {
    // グラデーションスタイル
    gradientStyle := lipgloss.NewStyle().
        Bold(true).
        Foreground(lipgloss.Color("#FF00FF")).
        Background(lipgloss.Color("#FFD700")).
        Width(40).
        Align(lipgloss.Center).
        Margin(1)
    
    // 点滅スタイル
    blinkStyle := lipgloss.NewStyle().
        Blink(true).
        Foreground(lipgloss.Color("#FF0000")).
        Bold(true)
    
    // 下線スタイル
    underlineStyle := lipgloss.NewStyle().
        Underline(true).
        UnderlineSpaces(true).
        Foreground(lipgloss.Color("#00FF00"))
    
    // リバーススタイル
    reverseStyle := lipgloss.NewStyle().
        Reverse(true).
        Padding(0, 2)
    
    fmt.Println(gradientStyle.Render("グラデーション背景"))
    fmt.Println(blinkStyle.Render("点滅テキスト"))
    fmt.Println(underlineStyle.Render("下線付きテキスト"))
    fmt.Println(reverseStyle.Render("反転テキスト"))
}

高度な機能

アダプティブカラー

// ターミナルの能力に応じた色選択
adaptiveColor := lipgloss.AdaptiveColor{
    Light: "#000000",
    Dark:  "#FFFFFF",
}

style := lipgloss.NewStyle().
    Foreground(adaptiveColor)

カスタムボーダー

// カスタムボーダーの定義
customBorder := lipgloss.Border{
    Top:         "━",
    Bottom:      "━",
    Left:        "┃",
    Right:       "┃",
    TopLeft:     "┏",
    TopRight:    "┓",
    BottomLeft:  "┗",
    BottomRight: "┛",
}

style := lipgloss.NewStyle().
    Border(customBorder).
    BorderForeground(lipgloss.Color("63"))

レスポンシブデザイン

func responsiveLayout(width int) string {
    var style lipgloss.Style
    
    if width < 40 {
        // モバイルレイアウト
        style = lipgloss.NewStyle().
            Width(width).
            Padding(1)
    } else if width < 80 {
        // タブレットレイアウト
        style = lipgloss.NewStyle().
            Width(width).
            Padding(2).
            Margin(1)
    } else {
        // デスクトップレイアウト
        style = lipgloss.NewStyle().
            Width(width / 2).
            Padding(3).
            Margin(2).
            Border(lipgloss.NormalBorder())
    }
    
    return style.Render("コンテンツ")
}

コンポーネント化

// ボタンコンポーネント
func Button(label string, primary bool) string {
    style := lipgloss.NewStyle().
        Padding(0, 3).
        Bold(true).
        Border(lipgloss.RoundedBorder())
    
    if primary {
        style = style.
            Foreground(lipgloss.Color("#FFFFFF")).
            Background(lipgloss.Color("#7D56F4")).
            BorderForeground(lipgloss.Color("#7D56F4"))
    } else {
        style = style.
            Foreground(lipgloss.Color("#7D56F4")).
            BorderForeground(lipgloss.Color("#7D56F4"))
    }
    
    return style.Render(label)
}

// カードコンポーネント
func Card(title, content string) string {
    titleStyle := lipgloss.NewStyle().
        Bold(true).
        Foreground(lipgloss.Color("#FF00FF")).
        MarginBottom(1)
    
    contentStyle := lipgloss.NewStyle().
        Foreground(lipgloss.Color("#CCCCCC"))
    
    cardStyle := lipgloss.NewStyle().
        Border(lipgloss.RoundedBorder()).
        BorderForeground(lipgloss.Color("#666666")).
        Padding(1, 2).
        Width(40)
    
    card := lipgloss.JoinVertical(
        lipgloss.Left,
        titleStyle.Render(title),
        contentStyle.Render(content),
    )
    
    return cardStyle.Render(card)
}

エコシステム

Charmbraceletツール

  • Bubble Tea: TUIフレームワーク
  • Bubbles: TUIコンポーネント集
  • Glamour: Markdownレンダラー
  • Glow: Markdownビューア

採用例

  • gh: GitHub CLI
  • lazygit: Git TUI
  • soft-serve: Gitサーバー
  • mods: AIチャットCLI

利点

  • 直感的: CSSライクなAPI
  • 美しい: プロフェッショナルな見た目
  • 柔軟: コンポーネント化が容易
  • 効率的: パフォーマンスを重視
  • 活発: Charmbraceletによる継続的な開発

制約事項

  • スタイリング専用: インタラクティブ機能はなし
  • フレームワーク依存: 単体でTUIアプリは作れない
  • レイアウト制限: 複雑なレイアウトは手動計算

他のライブラリとの比較

項目Lip Glosstviewtermui
用途スタイリング完全TUIダッシュボード
APICSSライクウィジェットウィジェット
学習コスト
柔軟性非常に高
エコシステムCharmbracelet独立独立

まとめ

Lip Glossは、ターミナルアプリケーションに美しいスタイルを適用するための優れたライブラリです。CSSに似た直感的なAPIにより、開発者は簡単にプロフェッショナルな見た目のターミナルUIを作成できます。単体では完全なTUIアプリケーションを構築できませんが、Bubble Teaと組み合わせることで、最もモダンで美しいTUIアプリケーションを実現できます。