Source Code
//! Layout Patterns Example
//!
//! This example demonstrates different layout approaches in GPUI:
//!
//! 1. Flexbox - Row and column layouts with alignment
//! 2. Grid - Two-dimensional layouts with spans
//! 3. Common patterns - Sidebar, header/footer, centering
#[path = "../prelude.rs"]
mod example_prelude;
use example_prelude::init_example;
use gpui::{
App, Application, Bounds, Colors, Context, Div, Hsla, Render, Rgba, Window, WindowBounds,
WindowOptions, div, prelude::*, px, size,
};
// Helper: Colored block for visualization
fn block(label: &'static str, color: Hsla, text_color: Rgba) -> Div {
div()
.flex()
.items_center()
.justify_center()
.bg(color)
.border_1()
.border_color(gpui::white().opacity(0.3))
.rounded_md()
.text_xs()
.text_color(text_color)
.child(label)
}
// Flexbox Examples
fn flexbox_row_example(colors: &Colors) -> impl IntoElement {
let text_muted = colors.text_muted;
let text = colors.selected_text;
div()
.flex()
.flex_col()
.gap_2()
.child(
div()
.text_xs()
.text_color(text_muted)
.child("flex().flex_row().gap_2()"),
)
.child(
div()
.flex()
.flex_row()
.gap_2()
.child(block("A", gpui::red(), text).size_8())
.child(block("B", gpui::green(), text).size_8())
.child(block("C", gpui::blue(), text).size_8()),
)
}
fn flexbox_column_example(colors: &Colors) -> impl IntoElement {
let text_muted = colors.text_muted;
let text = colors.selected_text;
div()
.flex()
.flex_col()
.gap_2()
.child(
div()
.text_xs()
.text_color(text_muted)
.child("flex().flex_col().gap_2()"),
)
.child(
div()
.h_24()
.flex()
.flex_col()
.gap_2()
.child(block("A", gpui::red(), text).h_6())
.child(block("B", gpui::green(), text).h_6())
.child(block("C", gpui::blue(), text).h_6()),
)
}
fn flexbox_justify_example(colors: &Colors) -> impl IntoElement {
let text_muted = colors.text_muted;
let text = colors.selected_text;
let surface = colors.surface;
div()
.flex()
.flex_col()
.gap_2()
.child(
div()
.text_xs()
.text_color(text_muted)
.child("justify_between / justify_center / justify_end"),
)
.child(
div()
.flex()
.flex_col()
.gap_1()
.child(
div()
.flex()
.justify_between()
.p_1()
.bg(surface)
.rounded_sm()
.child(block("Start", gpui::red(), text).px_2().py_1())
.child(block("End", gpui::blue(), text).px_2().py_1()),
)
.child(
div()
.flex()
.justify_center()
.p_1()
.bg(surface)
.rounded_sm()
.child(block("Center", gpui::green(), text).px_2().py_1()),
)
.child(
div()
.flex()
.justify_end()
.p_1()
.bg(surface)
.rounded_sm()
.child(block("End", gpui::yellow(), text).px_2().py_1()),
),
)
}
fn flexbox_grow_example(colors: &Colors) -> impl IntoElement {
let text_muted = colors.text_muted;
let text = colors.selected_text;
div()
.flex()
.flex_col()
.gap_2()
.child(
div()
.text_xs()
.text_color(text_muted)
.child("flex_1 (grow) vs flex_none (fixed)"),
)
.child(
div()
.flex()
.gap_2()
.child(block("fixed", gpui::red(), text).flex_none().w_16().h_8())
.child(block("flex_1 (grows)", gpui::green(), text).flex_1().h_8())
.child(block("fixed", gpui::blue(), text).flex_none().w_16().h_8()),
)
}
// Grid Examples
fn grid_basic_example(colors: &Colors) -> impl IntoElement {
let text_muted = colors.text_muted;
let text = colors.selected_text;
div()
.flex()
.flex_col()
.gap_2()
.child(
div()
.text_xs()
.text_color(text_muted)
.child("grid().grid_cols(3).gap_1()"),
)
.child(
div()
.grid()
.grid_cols(3)
.gap_1()
.child(block("1", gpui::red(), text).h_8())
.child(block("2", gpui::green(), text).h_8())
.child(block("3", gpui::blue(), text).h_8())
.child(block("4", gpui::yellow(), text).h_8())
.child(block("5", gpui::red(), text).h_8())
.child(block("6", gpui::green(), text).h_8()),
)
}
fn grid_span_example(colors: &Colors) -> impl IntoElement {
let text_muted = colors.text_muted;
let text = colors.selected_text;
div()
.flex()
.flex_col()
.gap_2()
.child(
div()
.text_xs()
.text_color(text_muted)
.child("col_span / row_span"),
)
.child(
div()
.grid()
.grid_cols(4)
.grid_rows(3)
.gap_1()
.child(
block("Header (col_span_full)", gpui::red(), text)
.col_span_full()
.h_6(),
)
.child(
block("Side", gpui::green(), text)
.col_span(1)
.row_span(2)
.h_full(),
)
.child(
block("Content (col_span 3)", gpui::blue(), text)
.col_span(3)
.row_span(2)
.h_full(),
),
)
}
// Common Layout Patterns
fn app_shell_pattern(colors: &Colors) -> impl IntoElement {
let text_muted = colors.text_muted;
let text = colors.text;
let surface = colors.surface;
let surface_hover = colors.surface_hover;
let background = colors.background;
let border = colors.border;
div()
.flex()
.flex_col()
.gap_2()
.child(
div()
.text_xs()
.text_color(text_muted)
.child("App Shell: Header + Sidebar + Content"),
)
.child(
div()
.h_32()
.flex()
.flex_col()
.border_1()
.border_color(border)
.rounded_md()
.overflow_hidden()
.child(
div()
.h_6()
.flex()
.items_center()
.px_2()
.bg(surface_hover)
.text_xs()
.text_color(text)
.child("Header"),
)
.child(
div()
.flex_1()
.flex()
.child(
div()
.w_16()
.bg(surface)
.flex()
.items_center()
.justify_center()
.text_xs()
.text_color(text_muted)
.child("Side"),
)
.child(
div()
.flex_1()
.bg(background)
.flex()
.items_center()
.justify_center()
.text_xs()
.text_color(text_muted)
.child("Content"),
),
),
)
}
fn centered_pattern(colors: &Colors) -> impl IntoElement {
let text_muted = colors.text_muted;
let text = colors.selected_text;
let surface = colors.surface;
let accent = colors.accent;
div()
.flex()
.flex_col()
.gap_2()
.child(
div()
.text_xs()
.text_color(text_muted)
.child("Centering: items_center + justify_center"),
)
.child(
div()
.h_20()
.flex()
.items_center()
.justify_center()
.bg(surface)
.rounded_md()
.child(
div()
.px_4()
.py_2()
.bg(accent)
.rounded_md()
.text_xs()
.text_color(text)
.child("Perfectly Centered"),
),
)
}
fn stack_pattern(colors: &Colors) -> impl IntoElement {
let text_muted = colors.text_muted;
let surface = colors.surface;
div()
.flex()
.flex_col()
.gap_2()
.child(
div()
.text_xs()
.text_color(text_muted)
.child("Stack: Overlapping with absolute positioning"),
)
.child(
div()
.h_20()
.relative()
.bg(surface)
.rounded_md()
.child(
div()
.absolute()
.top_2()
.left_2()
.size_10()
.bg(gpui::red().opacity(0.7))
.rounded_md(),
)
.child(
div()
.absolute()
.top_4()
.left_4()
.size_10()
.bg(gpui::green().opacity(0.7))
.rounded_md(),
)
.child(
div()
.absolute()
.top_6()
.left_6()
.size_10()
.bg(gpui::blue().opacity(0.7))
.rounded_md(),
),
)
}
// Main Application View
struct LayoutExample;
impl Render for LayoutExample {
fn render(&mut self, window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
let colors = Colors::for_appearance(window);
div()
.id("main")
.size_full()
.p_4()
.bg(colors.background)
.overflow_scroll()
.child(
div()
.flex()
.flex_col()
.gap_4()
.max_w(px(600.))
.child(
div()
.flex()
.flex_col()
.gap_1()
.child(
div()
.text_xl()
.font_weight(gpui::FontWeight::BOLD)
.text_color(colors.text)
.child("Layout Patterns"),
)
.child(
div()
.text_sm()
.text_color(colors.text_muted)
.child("Flexbox, Grid, and common layout patterns in GPUI"),
),
)
.child(section(
&colors,
"Flexbox: Row",
flexbox_row_example(&colors),
))
.child(section(
&colors,
"Flexbox: Column",
flexbox_column_example(&colors),
))
.child(section(
&colors,
"Flexbox: Justify Content",
flexbox_justify_example(&colors),
))
.child(section(
&colors,
"Flexbox: Grow/Shrink",
flexbox_grow_example(&colors),
))
.child(section(&colors, "Grid: Basic", grid_basic_example(&colors)))
.child(section(&colors, "Grid: Spans", grid_span_example(&colors)))
.child(section(
&colors,
"Pattern: App Shell",
app_shell_pattern(&colors),
))
.child(section(
&colors,
"Pattern: Centering",
centered_pattern(&colors),
))
.child(section(&colors, "Pattern: Stack", stack_pattern(&colors))),
)
}
}
fn section(colors: &Colors, title: &'static str, content: impl IntoElement) -> impl IntoElement {
let surface: Hsla = colors.surface.into();
div()
.flex()
.flex_col()
.gap_2()
.p_3()
.bg(surface.opacity(0.5))
.rounded_lg()
.child(
div()
.text_sm()
.font_weight(gpui::FontWeight::SEMIBOLD)
.text_color(colors.text)
.child(title),
)
.child(content)
}
fn main() {
Application::new().run(|cx: &mut App| {
let bounds = Bounds::centered(None, size(px(650.), px(700.)), cx);
cx.open_window(
WindowOptions {
window_bounds: Some(WindowBounds::Windowed(bounds)),
..Default::default()
},
|_, cx| cx.new(|_| LayoutExample),
)
.expect("Failed to open window");
init_example(cx, "Layout");
});
}