Start reorganizing examples (#10)

* Update crate name

* wip

* reduce to just the gpui crate

* Fix misisng example images

* Delete ownership_post.rs

* Update Cargo.toml

* Update README.md

* bump to 0.3.3

* organize

* organize

* Add more learn examples

* Delete _ownership_and_data_flow.rs

* wip learn examples

* Fix colors

* tidy

* Move _template up

* add animation example

* Update examples

* remove legacy examples from toml

* Delete examples.toml
This commit is contained in:
Nate Butler
2025-12-28 23:14:33 -05:00
committed by GitHub
parent 6a74dbe3f4
commit 18aeb44a54
295 changed files with 5174 additions and 23483 deletions
+473
View File
@@ -0,0 +1,473 @@
use std::{ops::Range, rc::Rc, time::Duration};
use gpui::{
App, Application, Bounds, Context, MouseDownEvent, MouseMoveEvent, MouseUpEvent, Pixels, Point,
Render, SharedString, UniformListScrollHandle, Window, WindowBounds, WindowOptions, canvas,
div, point, prelude::*, px, rgb, size, uniform_list,
};
const TOTAL_ITEMS: usize = 10000;
const SCROLLBAR_THUMB_WIDTH: Pixels = px(8.);
const SCROLLBAR_THUMB_HEIGHT: Pixels = px(100.);
pub struct Quote {
name: SharedString,
symbol: SharedString,
last_done: f64,
prev_close: f64,
open: f64,
high: f64,
low: f64,
timestamp: Duration,
volume: i64,
turnover: f64,
ttm: f64,
market_cap: f64,
float_cap: f64,
shares: f64,
pb: f64,
pe: f64,
eps: f64,
dividend: f64,
dividend_yield: f64,
dividend_per_share: f64,
dividend_date: SharedString,
dividend_payment: f64,
}
impl Quote {
pub fn random() -> Self {
use rand::Rng;
let mut rng = rand::rng();
// simulate a base price in a realistic range
let prev_close = rng.random_range(100.0..200.0);
let change = rng.random_range(-5.0..5.0);
let last_done = prev_close + change;
let open = prev_close + rng.random_range(-3.0..3.0);
let high = (prev_close + rng.random_range::<f64, _>(0.0..10.0)).max(open);
let low = (prev_close - rng.random_range::<f64, _>(0.0..10.0)).min(open);
let timestamp = Duration::from_secs(rng.random_range(0..86400));
let volume = rng.random_range(1_000_000..100_000_000);
let turnover = last_done * volume as f64;
let symbol = {
let mut ticker = String::new();
if rng.random_bool(0.5) {
ticker.push_str(&format!(
"{:03}.{}",
rng.random_range(100..1000),
rng.random_range(0..10)
));
} else {
ticker.push_str(&format!(
"{}{}",
rng.random_range('A'..='Z'),
rng.random_range('A'..='Z')
));
}
ticker.push_str(&format!(".{}", rng.random_range('A'..='Z')));
ticker
};
let name = format!(
"{} {} - #{}",
symbol,
rng.random_range(1..100),
rng.random_range(10000..100000)
);
let ttm = rng.random_range(0.0..10.0);
let market_cap = rng.random_range(1_000_000.0..10_000_000.0);
let float_cap = market_cap + rng.random_range(1_000.0..10_000.0);
let shares = rng.random_range(100.0..1000.0);
let pb = market_cap / shares;
let pe = market_cap / shares;
let eps = market_cap / shares;
let dividend = rng.random_range(0.0..10.0);
let dividend_yield = rng.random_range(0.0..10.0);
let dividend_per_share = rng.random_range(0.0..10.0);
let dividend_date = SharedString::new(format!(
"{}-{}-{}",
rng.random_range(2000..2023),
rng.random_range(1..12),
rng.random_range(1..28)
));
let dividend_payment = rng.random_range(0.0..10.0);
Self {
name: name.into(),
symbol: symbol.into(),
last_done,
prev_close,
open,
high,
low,
timestamp,
volume,
turnover,
pb,
pe,
eps,
ttm,
market_cap,
float_cap,
shares,
dividend,
dividend_yield,
dividend_per_share,
dividend_date,
dividend_payment,
}
}
fn change(&self) -> f64 {
(self.last_done - self.prev_close) / self.prev_close * 100.0
}
fn change_color(&self) -> gpui::Hsla {
if self.change() > 0.0 {
gpui::green()
} else {
gpui::red()
}
}
fn turnover_ratio(&self) -> f64 {
self.volume as f64 / self.turnover * 100.0
}
}
#[derive(IntoElement)]
struct TableRow {
ix: usize,
quote: Rc<Quote>,
}
impl TableRow {
fn new(ix: usize, quote: Rc<Quote>) -> Self {
Self { ix, quote }
}
fn render_cell(&self, key: &str, width: Pixels, color: gpui::Hsla) -> impl IntoElement {
div()
.whitespace_nowrap()
.truncate()
.w(width)
.px_1()
.child(match key {
"id" => div().child(format!("{}", self.ix)),
"symbol" => div().child(self.quote.symbol.clone()),
"name" => div().child(self.quote.name.clone()),
"last_done" => div()
.text_color(color)
.child(format!("{:.3}", self.quote.last_done)),
"prev_close" => div()
.text_color(color)
.child(format!("{:.3}", self.quote.prev_close)),
"change" => div()
.text_color(color)
.child(format!("{:.2}%", self.quote.change())),
"timestamp" => div()
.text_color(color)
.child(format!("{:?}", self.quote.timestamp.as_secs())),
"open" => div()
.text_color(color)
.child(format!("{:.2}", self.quote.open)),
"low" => div()
.text_color(color)
.child(format!("{:.2}", self.quote.low)),
"high" => div()
.text_color(color)
.child(format!("{:.2}", self.quote.high)),
"ttm" => div()
.text_color(color)
.child(format!("{:.2}", self.quote.ttm)),
"eps" => div()
.text_color(color)
.child(format!("{:.2}", self.quote.eps)),
"market_cap" => {
div().child(format!("{:.2} M", self.quote.market_cap / 1_000_000.0))
}
"float_cap" => div().child(format!("{:.2} M", self.quote.float_cap / 1_000_000.0)),
"turnover" => div().child(format!("{:.2} M", self.quote.turnover / 1_000_000.0)),
"volume" => div().child(format!("{:.2} M", self.quote.volume as f64 / 1_000_000.0)),
"turnover_ratio" => div().child(format!("{:.2}%", self.quote.turnover_ratio())),
"pe" => div().child(format!("{:.2}", self.quote.pe)),
"pb" => div().child(format!("{:.2}", self.quote.pb)),
"shares" => div().child(format!("{:.2}", self.quote.shares)),
"dividend" => div().child(format!("{:.2}", self.quote.dividend)),
"yield" => div().child(format!("{:.2}%", self.quote.dividend_yield)),
"dividend_per_share" => {
div().child(format!("{:.2}", self.quote.dividend_per_share))
}
"dividend_date" => div().child(format!("{}", self.quote.dividend_date)),
"dividend_payment" => div().child(format!("{:.2}", self.quote.dividend_payment)),
_ => div().child("--"),
})
}
}
const FIELDS: [(&str, f32); 24] = [
("id", 64.),
("symbol", 64.),
("name", 180.),
("last_done", 80.),
("prev_close", 80.),
("open", 80.),
("low", 80.),
("high", 80.),
("ttm", 50.),
("market_cap", 96.),
("float_cap", 96.),
("turnover", 120.),
("volume", 100.),
("turnover_ratio", 96.),
("pe", 64.),
("pb", 64.),
("eps", 64.),
("shares", 96.),
("dividend", 64.),
("yield", 64.),
("dividend_per_share", 64.),
("dividend_date", 96.),
("dividend_payment", 64.),
("timestamp", 120.),
];
impl RenderOnce for TableRow {
fn render(self, _window: &mut Window, _cx: &mut App) -> impl IntoElement {
let color = self.quote.change_color();
div()
.flex()
.flex_row()
.border_b_1()
.border_color(rgb(0xE0E0E0))
.bg(if self.ix.is_multiple_of(2) {
rgb(0xFFFFFF)
} else {
rgb(0xFAFAFA)
})
.py_0p5()
.px_2()
.children(FIELDS.map(|(key, width)| self.render_cell(key, px(width), color)))
}
}
struct DataTable {
/// Use `Rc` to share the same quote data across multiple items, avoid cloning.
quotes: Vec<Rc<Quote>>,
visible_range: Range<usize>,
scroll_handle: UniformListScrollHandle,
/// The position in thumb bounds when dragging start mouse down.
drag_position: Option<Point<Pixels>>,
}
impl DataTable {
fn new() -> Self {
Self {
quotes: Vec::new(),
visible_range: 0..0,
scroll_handle: UniformListScrollHandle::new(),
drag_position: None,
}
}
fn generate(&mut self) {
self.quotes = (0..TOTAL_ITEMS).map(|_| Rc::new(Quote::random())).collect();
}
fn table_bounds(&self) -> Bounds<Pixels> {
self.scroll_handle.0.borrow().base_handle.bounds()
}
fn scroll_top(&self) -> Pixels {
self.scroll_handle.0.borrow().base_handle.offset().y
}
fn scroll_height(&self) -> Pixels {
self.scroll_handle
.0
.borrow()
.last_item_size
.unwrap_or_default()
.contents
.height
}
fn render_scrollbar(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
let scroll_height = self.scroll_height();
let table_bounds = self.table_bounds();
let table_height = table_bounds.size.height;
if table_height == px(0.) {
return div().id("scrollbar");
}
let percentage = -self.scroll_top() / scroll_height;
let offset_top = (table_height * percentage).clamp(
px(4.),
(table_height - SCROLLBAR_THUMB_HEIGHT - px(4.)).max(px(4.)),
);
let entity = cx.entity();
let scroll_handle = self.scroll_handle.0.borrow().base_handle.clone();
div()
.id("scrollbar")
.absolute()
.top(offset_top)
.right_1()
.h(SCROLLBAR_THUMB_HEIGHT)
.w(SCROLLBAR_THUMB_WIDTH)
.bg(rgb(0xC0C0C0))
.hover(|this| this.bg(rgb(0xA0A0A0)))
.rounded_lg()
.child(
canvas(
|_, _, _| (),
move |thumb_bounds, _, window, _| {
window.on_mouse_event({
let entity = entity.clone();
move |ev: &MouseDownEvent, _, _, cx| {
if !thumb_bounds.contains(&ev.position) {
return;
}
entity.update(cx, |this, _| {
this.drag_position = Some(
ev.position - thumb_bounds.origin - table_bounds.origin,
);
})
}
});
window.on_mouse_event({
let entity = entity.clone();
move |_: &MouseUpEvent, _, _, cx| {
entity.update(cx, |this, _| {
this.drag_position = None;
})
}
});
window.on_mouse_event(move |ev: &MouseMoveEvent, _, _, cx| {
if !ev.dragging() {
return;
}
let Some(drag_pos) = entity.read(cx).drag_position else {
return;
};
let inside_offset = drag_pos.y;
let percentage = ((ev.position.y - table_bounds.origin.y
+ inside_offset)
/ (table_bounds.size.height))
.clamp(0., 1.);
let offset_y = ((scroll_height - table_bounds.size.height)
* percentage)
.clamp(px(0.), scroll_height - SCROLLBAR_THUMB_HEIGHT);
scroll_handle.set_offset(point(px(0.), -offset_y));
cx.notify(entity.entity_id());
})
},
)
.size_full(),
)
}
}
impl Render for DataTable {
fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
div()
.bg(gpui::white())
.text_sm()
.size_full()
.p_4()
.gap_2()
.flex()
.flex_col()
.child(format!(
"Total {} items, visible range: {:?}",
self.quotes.len(),
self.visible_range
))
.child(
div()
.flex()
.flex_col()
.flex_1()
.overflow_hidden()
.border_1()
.border_color(rgb(0xE0E0E0))
.rounded_sm()
.child(
div()
.flex()
.flex_row()
.w_full()
.overflow_hidden()
.border_b_1()
.border_color(rgb(0xE0E0E0))
.text_color(rgb(0x555555))
.bg(rgb(0xF0F0F0))
.py_1()
.px_2()
.text_xs()
.children(FIELDS.map(|(key, width)| {
div()
.whitespace_nowrap()
.flex_shrink_0()
.truncate()
.px_1()
.w(px(width))
.child(key.replace("_", " ").to_uppercase())
})),
)
.child(
div()
.relative()
.size_full()
.child(
uniform_list(
"items",
self.quotes.len(),
cx.processor(move |this, range: Range<usize>, _, _| {
this.visible_range = range.clone();
let mut items = Vec::with_capacity(range.end - range.start);
for i in range {
if let Some(quote) = this.quotes.get(i) {
items.push(TableRow::new(i, quote.clone()));
}
}
items
}),
)
.size_full()
.track_scroll(&self.scroll_handle),
)
.child(self.render_scrollbar(window, cx)),
),
)
}
}
fn main() {
Application::new().run(|cx: &mut App| {
cx.open_window(
WindowOptions {
focus: true,
window_bounds: Some(WindowBounds::Windowed(Bounds::centered(
None,
size(px(1280.0), px(1000.0)),
cx,
))),
..Default::default()
},
|_, cx| {
cx.new(|_| {
let mut table = DataTable::new();
table.generate();
table
})
},
)
.unwrap();
cx.activate(true);
});
}
+92
View File
@@ -0,0 +1,92 @@
use gpui::{
Application, Background, Bounds, ColorSpace, Context, Path, PathBuilder, Pixels, Render,
TitlebarOptions, Window, WindowBounds, WindowOptions, canvas, div, linear_color_stop,
linear_gradient, point, prelude::*, px, rgb, size,
};
const DEFAULT_WINDOW_WIDTH: Pixels = px(1024.0);
const DEFAULT_WINDOW_HEIGHT: Pixels = px(768.0);
struct PaintingViewer {
default_lines: Vec<(Path<Pixels>, Background)>,
_painting: bool,
}
impl PaintingViewer {
fn new(_window: &mut Window, _cx: &mut Context<Self>) -> Self {
let mut lines = vec![];
// draw a lightening bolt ⚡
for _ in 0..2000 {
// draw a ⭐
let mut builder = PathBuilder::fill();
builder.move_to(point(px(350.), px(100.)));
builder.line_to(point(px(370.), px(160.)));
builder.line_to(point(px(430.), px(160.)));
builder.line_to(point(px(380.), px(200.)));
builder.line_to(point(px(400.), px(260.)));
builder.line_to(point(px(350.), px(220.)));
builder.line_to(point(px(300.), px(260.)));
builder.line_to(point(px(320.), px(200.)));
builder.line_to(point(px(270.), px(160.)));
builder.line_to(point(px(330.), px(160.)));
builder.line_to(point(px(350.), px(100.)));
let path = builder.build().unwrap();
lines.push((
path,
linear_gradient(
180.,
linear_color_stop(rgb(0xFACC15), 0.7),
linear_color_stop(rgb(0xD56D0C), 1.),
)
.color_space(ColorSpace::Oklab),
));
}
Self {
default_lines: lines,
_painting: false,
}
}
}
impl Render for PaintingViewer {
fn render(&mut self, window: &mut Window, _: &mut Context<Self>) -> impl IntoElement {
window.request_animation_frame();
let lines = self.default_lines.clone();
div().size_full().child(
canvas(
move |_, _, _| {},
move |_, _, window, _| {
for (path, color) in lines {
window.paint_path(path, color);
}
},
)
.size_full(),
)
}
}
fn main() {
Application::new().run(|cx| {
cx.open_window(
WindowOptions {
titlebar: Some(TitlebarOptions {
title: Some("Vulkan".into()),
..Default::default()
}),
focus: true,
window_bounds: Some(WindowBounds::Windowed(Bounds::centered(
None,
size(DEFAULT_WINDOW_WIDTH, DEFAULT_WINDOW_HEIGHT),
cx,
))),
..Default::default()
},
|window, cx| cx.new(|cx| PaintingViewer::new(window, cx)),
)
.unwrap();
cx.activate(true);
});
}
+115
View File
@@ -0,0 +1,115 @@
use gpui::{
App, AppContext, Application, Bounds, Context, Window, WindowBounds, WindowOptions, div,
linear_color_stop, linear_gradient, pattern_slash, prelude::*, px, rgb, size,
};
struct PatternExample;
impl Render for PatternExample {
fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
div()
.flex()
.flex_col()
.gap_3()
.bg(rgb(0xffffff))
.size(px(600.0))
.justify_center()
.items_center()
.shadow_lg()
.text_xl()
.text_color(rgb(0x000000))
.child("Pattern Example")
.child(
div()
.flex()
.flex_col()
.border_1()
.border_color(gpui::blue())
.child(div().w(px(54.0)).h(px(18.0)).bg(pattern_slash(
gpui::red(),
18.0 / 4.0,
18.0 / 4.0,
)))
.child(div().w(px(54.0)).h(px(18.0)).bg(pattern_slash(
gpui::red(),
18.0 / 4.0,
18.0 / 4.0,
)))
.child(div().w(px(54.0)).h(px(18.0)).bg(pattern_slash(
gpui::red(),
18.0 / 4.0,
18.0 / 4.0,
)))
.child(div().w(px(54.0)).h(px(18.0)).bg(pattern_slash(
gpui::red(),
18.0 / 4.0,
18.0 / 2.0,
))),
)
.child(
div()
.flex()
.flex_col()
.border_1()
.border_color(gpui::blue())
.bg(gpui::green().opacity(0.16))
.child("Elements the same height should align")
.child(div().w(px(256.0)).h(px(56.0)).bg(pattern_slash(
gpui::red(),
56.0 / 6.0,
56.0 / 6.0,
)))
.child(div().w(px(256.0)).h(px(56.0)).bg(pattern_slash(
gpui::green(),
56.0 / 6.0,
56.0 / 6.0,
)))
.child(div().w(px(256.0)).h(px(56.0)).bg(pattern_slash(
gpui::blue(),
56.0 / 6.0,
56.0 / 6.0,
)))
.child(div().w(px(256.0)).h(px(26.0)).bg(pattern_slash(
gpui::yellow(),
56.0 / 6.0,
56.0 / 6.0,
))),
)
.child(
div()
.border_1()
.border_color(gpui::blue())
.w(px(240.0))
.h(px(40.0))
.bg(gpui::red()),
)
.child(
div()
.border_1()
.border_color(gpui::blue())
.w(px(240.0))
.h(px(40.0))
.bg(linear_gradient(
45.,
linear_color_stop(gpui::red(), 0.),
linear_color_stop(gpui::blue(), 1.),
)),
)
}
}
fn main() {
Application::new().run(|cx: &mut App| {
let bounds = Bounds::centered(None, size(px(600.0), px(600.0)), cx);
cx.open_window(
WindowOptions {
window_bounds: Some(WindowBounds::Windowed(bounds)),
..Default::default()
},
|_window, cx| cx.new(|_cx| PatternExample),
)
.unwrap();
cx.activate(true);
});
}
+585
View File
@@ -0,0 +1,585 @@
use gpui::{
App, Application, Bounds, BoxShadow, Context, Div, SharedString, Window, WindowBounds,
WindowOptions, div, hsla, point, prelude::*, px, relative, rgb, size,
};
struct Shadow {}
impl Shadow {
fn base() -> Div {
div()
.size_16()
.bg(rgb(0xffffff))
.rounded_full()
.border_1()
.border_color(hsla(0.0, 0.0, 0.0, 0.1))
}
fn square() -> Div {
div()
.size_16()
.bg(rgb(0xffffff))
.border_1()
.border_color(hsla(0.0, 0.0, 0.0, 0.1))
}
fn rounded_small() -> Div {
div()
.size_16()
.bg(rgb(0xffffff))
.rounded(px(4.))
.border_1()
.border_color(hsla(0.0, 0.0, 0.0, 0.1))
}
fn rounded_medium() -> Div {
div()
.size_16()
.bg(rgb(0xffffff))
.rounded(px(8.))
.border_1()
.border_color(hsla(0.0, 0.0, 0.0, 0.1))
}
fn rounded_large() -> Div {
div()
.size_16()
.bg(rgb(0xffffff))
.rounded(px(12.))
.border_1()
.border_color(hsla(0.0, 0.0, 0.0, 0.1))
}
}
fn example(label: impl Into<SharedString>, example: impl IntoElement) -> impl IntoElement {
let label = label.into();
div()
.flex()
.flex_col()
.justify_center()
.items_center()
.w(relative(1. / 6.))
.border_r_1()
.border_color(hsla(0.0, 0.0, 0.0, 1.0))
.child(
div()
.flex()
.items_center()
.justify_center()
.flex_1()
.py_12()
.child(example),
)
.child(
div()
.w_full()
.border_t_1()
.border_color(hsla(0.0, 0.0, 0.0, 1.0))
.p_1()
.flex()
.items_center()
.child(label),
)
}
impl Render for Shadow {
fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
div()
.id("shadow-example")
.overflow_y_scroll()
.bg(rgb(0xffffff))
.size_full()
.text_xs()
.child(div().flex().flex_col().w_full().children(vec![
div()
.border_b_1()
.border_color(hsla(0.0, 0.0, 0.0, 1.0))
.flex()
.flex_row()
.children(vec![
example(
"Square",
Shadow::square()
.shadow(vec![BoxShadow {
color: hsla(0.0, 0.5, 0.5, 0.3),
offset: point(px(0.), px(8.)),
blur_radius: px(8.),
spread_radius: px(0.),
}]),
),
example(
"Rounded 4",
Shadow::rounded_small()
.shadow(vec![BoxShadow {
color: hsla(0.0, 0.5, 0.5, 0.3),
offset: point(px(0.), px(8.)),
blur_radius: px(8.),
spread_radius: px(0.),
}]),
),
example(
"Rounded 8",
Shadow::rounded_medium()
.shadow(vec![BoxShadow {
color: hsla(0.0, 0.5, 0.5, 0.3),
offset: point(px(0.), px(8.)),
blur_radius: px(8.),
spread_radius: px(0.),
}]),
),
example(
"Rounded 16",
Shadow::rounded_large()
.shadow(vec![BoxShadow {
color: hsla(0.0, 0.5, 0.5, 0.3),
offset: point(px(0.), px(8.)),
blur_radius: px(8.),
spread_radius: px(0.),
}]),
),
example(
"Circle",
Shadow::base()
.shadow(vec![BoxShadow {
color: hsla(0.0, 0.5, 0.5, 0.3),
offset: point(px(0.), px(8.)),
blur_radius: px(8.),
spread_radius: px(0.),
}]),
),
]),
div()
.border_b_1()
.border_color(hsla(0.0, 0.0, 0.0, 1.0))
.flex()
.w_full()
.children(vec![
example("None", Shadow::base()),
// 2Xsmall shadow
example("2X Small", Shadow::base().shadow_2xs()),
// Xsmall shadow
example("Extra Small", Shadow::base().shadow_xs()),
// Small shadow
example("Small", Shadow::base().shadow_sm()),
// Medium shadow
example("Medium", Shadow::base().shadow_md()),
// Large shadow
example("Large", Shadow::base().shadow_lg()),
example("Extra Large", Shadow::base().shadow_xl()),
example("2X Large", Shadow::base().shadow_2xl()),
]),
// Horizontal list of increasing blur radii
div()
.border_b_1()
.border_color(hsla(0.0, 0.0, 0.0, 1.0))
.flex()
.children(vec![
example(
"Blur 0",
Shadow::base().shadow(vec![BoxShadow {
color: hsla(0.0, 0.0, 0.0, 0.3),
offset: point(px(0.), px(8.)),
blur_radius: px(0.),
spread_radius: px(0.),
}]),
),
example(
"Blur 2",
Shadow::base().shadow(vec![BoxShadow {
color: hsla(0.0, 0.0, 0.0, 0.3),
offset: point(px(0.), px(8.)),
blur_radius: px(2.),
spread_radius: px(0.),
}]),
),
example(
"Blur 4",
Shadow::base().shadow(vec![BoxShadow {
color: hsla(0.0, 0.0, 0.0, 0.3),
offset: point(px(0.), px(8.)),
blur_radius: px(4.),
spread_radius: px(0.),
}]),
),
example(
"Blur 8",
Shadow::base().shadow(vec![BoxShadow {
color: hsla(0.0, 0.0, 0.0, 0.3),
offset: point(px(0.), px(8.)),
blur_radius: px(8.),
spread_radius: px(0.),
}]),
),
example(
"Blur 16",
Shadow::base().shadow(vec![BoxShadow {
color: hsla(0.0, 0.0, 0.0, 0.3),
offset: point(px(0.), px(8.)),
blur_radius: px(16.),
spread_radius: px(0.),
}]),
),
]),
// Horizontal list of increasing spread radii
div()
.border_b_1()
.border_color(hsla(0.0, 0.0, 0.0, 1.0))
.flex()
.children(vec![
example(
"Spread 0",
Shadow::base().shadow(vec![BoxShadow {
color: hsla(0.0, 0.0, 0.0, 0.3),
offset: point(px(0.), px(8.)),
blur_radius: px(8.),
spread_radius: px(0.),
}]),
),
example(
"Spread 2",
Shadow::base().shadow(vec![BoxShadow {
color: hsla(0.0, 0.0, 0.0, 0.3),
offset: point(px(0.), px(8.)),
blur_radius: px(8.),
spread_radius: px(2.),
}]),
),
example(
"Spread 4",
Shadow::base().shadow(vec![BoxShadow {
color: hsla(0.0, 0.0, 0.0, 0.3),
offset: point(px(0.), px(8.)),
blur_radius: px(8.),
spread_radius: px(4.),
}]),
),
example(
"Spread 8",
Shadow::base().shadow(vec![BoxShadow {
color: hsla(0.0, 0.0, 0.0, 0.3),
offset: point(px(0.), px(8.)),
blur_radius: px(8.),
spread_radius: px(8.),
}]),
),
example(
"Spread 16",
Shadow::base().shadow(vec![BoxShadow {
color: hsla(0.0, 0.0, 0.0, 0.3),
offset: point(px(0.), px(8.)),
blur_radius: px(8.),
spread_radius: px(16.),
}]),
),
]),
// Square spread examples
div()
.border_b_1()
.border_color(hsla(0.0, 0.0, 0.0, 1.0))
.flex()
.children(vec![
example(
"Square Spread 0",
Shadow::square().shadow(vec![BoxShadow {
color: hsla(0.0, 0.0, 0.0, 0.3),
offset: point(px(0.), px(8.)),
blur_radius: px(8.),
spread_radius: px(0.),
}]),
),
example(
"Square Spread 8",
Shadow::square().shadow(vec![BoxShadow {
color: hsla(0.0, 0.0, 0.0, 0.3),
offset: point(px(0.), px(8.)),
blur_radius: px(8.),
spread_radius: px(8.),
}]),
),
example(
"Square Spread 16",
Shadow::square().shadow(vec![BoxShadow {
color: hsla(0.0, 0.0, 0.0, 0.3),
offset: point(px(0.), px(8.)),
blur_radius: px(8.),
spread_radius: px(16.),
}]),
),
]),
// Rounded large spread examples
div()
.border_b_1()
.border_color(hsla(0.0, 0.0, 0.0, 1.0))
.flex()
.children(vec![
example(
"Rounded Large Spread 0",
Shadow::rounded_large().shadow(vec![BoxShadow {
color: hsla(0.0, 0.0, 0.0, 0.3),
offset: point(px(0.), px(8.)),
blur_radius: px(8.),
spread_radius: px(0.),
}]),
),
example(
"Rounded Large Spread 8",
Shadow::rounded_large().shadow(vec![BoxShadow {
color: hsla(0.0, 0.0, 0.0, 0.3),
offset: point(px(0.), px(8.)),
blur_radius: px(8.),
spread_radius: px(8.),
}]),
),
example(
"Rounded Large Spread 16",
Shadow::rounded_large().shadow(vec![BoxShadow {
color: hsla(0.0, 0.0, 0.0, 0.3),
offset: point(px(0.), px(8.)),
blur_radius: px(8.),
spread_radius: px(16.),
}]),
),
]),
// Directional shadows
div()
.border_b_1()
.border_color(hsla(0.0, 0.0, 0.0, 1.0))
.flex()
.children(vec![
example(
"Left",
Shadow::base().shadow(vec![BoxShadow {
color: hsla(0.0, 0.5, 0.5, 0.3),
offset: point(px(-8.), px(0.)),
blur_radius: px(8.),
spread_radius: px(0.),
}]),
),
example(
"Right",
Shadow::base().shadow(vec![BoxShadow {
color: hsla(0.0, 0.5, 0.5, 0.3),
offset: point(px(8.), px(0.)),
blur_radius: px(8.),
spread_radius: px(0.),
}]),
),
example(
"Top",
Shadow::base().shadow(vec![BoxShadow {
color: hsla(0.0, 0.5, 0.5, 0.3),
offset: point(px(0.), px(-8.)),
blur_radius: px(8.),
spread_radius: px(0.),
}]),
),
example(
"Bottom",
Shadow::base().shadow(vec![BoxShadow {
color: hsla(0.0, 0.5, 0.5, 0.3),
offset: point(px(0.), px(8.)),
blur_radius: px(8.),
spread_radius: px(0.),
}]),
),
]),
// Square directional shadows
div()
.border_b_1()
.border_color(hsla(0.0, 0.0, 0.0, 1.0))
.flex()
.children(vec![
example(
"Square Left",
Shadow::square().shadow(vec![BoxShadow {
color: hsla(0.0, 0.5, 0.5, 0.3),
offset: point(px(-8.), px(0.)),
blur_radius: px(8.),
spread_radius: px(0.),
}]),
),
example(
"Square Right",
Shadow::square().shadow(vec![BoxShadow {
color: hsla(0.0, 0.5, 0.5, 0.3),
offset: point(px(8.), px(0.)),
blur_radius: px(8.),
spread_radius: px(0.),
}]),
),
example(
"Square Top",
Shadow::square().shadow(vec![BoxShadow {
color: hsla(0.0, 0.5, 0.5, 0.3),
offset: point(px(0.), px(-8.)),
blur_radius: px(8.),
spread_radius: px(0.),
}]),
),
example(
"Square Bottom",
Shadow::square().shadow(vec![BoxShadow {
color: hsla(0.0, 0.5, 0.5, 0.3),
offset: point(px(0.), px(8.)),
blur_radius: px(8.),
spread_radius: px(0.),
}]),
),
]),
// Rounded large directional shadows
div()
.border_b_1()
.border_color(hsla(0.0, 0.0, 0.0, 1.0))
.flex()
.children(vec![
example(
"Rounded Large Left",
Shadow::rounded_large().shadow(vec![BoxShadow {
color: hsla(0.0, 0.5, 0.5, 0.3),
offset: point(px(-8.), px(0.)),
blur_radius: px(8.),
spread_radius: px(0.),
}]),
),
example(
"Rounded Large Right",
Shadow::rounded_large().shadow(vec![BoxShadow {
color: hsla(0.0, 0.5, 0.5, 0.3),
offset: point(px(8.), px(0.)),
blur_radius: px(8.),
spread_radius: px(0.),
}]),
),
example(
"Rounded Large Top",
Shadow::rounded_large().shadow(vec![BoxShadow {
color: hsla(0.0, 0.5, 0.5, 0.3),
offset: point(px(0.), px(-8.)),
blur_radius: px(8.),
spread_radius: px(0.),
}]),
),
example(
"Rounded Large Bottom",
Shadow::rounded_large().shadow(vec![BoxShadow {
color: hsla(0.0, 0.5, 0.5, 0.3),
offset: point(px(0.), px(8.)),
blur_radius: px(8.),
spread_radius: px(0.),
}]),
),
]),
// Multiple shadows for different shapes
div()
.border_b_1()
.border_color(hsla(0.0, 0.0, 0.0, 1.0))
.flex()
.children(vec![
example(
"Circle Multiple",
Shadow::base().shadow(vec![
BoxShadow {
color: hsla(0.0 / 360., 1.0, 0.5, 0.3), // Red
offset: point(px(0.), px(-12.)),
blur_radius: px(8.),
spread_radius: px(2.),
},
BoxShadow {
color: hsla(60.0 / 360., 1.0, 0.5, 0.3), // Yellow
offset: point(px(12.), px(0.)),
blur_radius: px(8.),
spread_radius: px(2.),
},
BoxShadow {
color: hsla(120.0 / 360., 1.0, 0.5, 0.3), // Green
offset: point(px(0.), px(12.)),
blur_radius: px(8.),
spread_radius: px(2.),
},
BoxShadow {
color: hsla(240.0 / 360., 1.0, 0.5, 0.3), // Blue
offset: point(px(-12.), px(0.)),
blur_radius: px(8.),
spread_radius: px(2.),
},
]),
),
example(
"Square Multiple",
Shadow::square().shadow(vec![
BoxShadow {
color: hsla(0.0 / 360., 1.0, 0.5, 0.3), // Red
offset: point(px(0.), px(-12.)),
blur_radius: px(8.),
spread_radius: px(2.),
},
BoxShadow {
color: hsla(60.0 / 360., 1.0, 0.5, 0.3), // Yellow
offset: point(px(12.), px(0.)),
blur_radius: px(8.),
spread_radius: px(2.),
},
BoxShadow {
color: hsla(120.0 / 360., 1.0, 0.5, 0.3), // Green
offset: point(px(0.), px(12.)),
blur_radius: px(8.),
spread_radius: px(2.),
},
BoxShadow {
color: hsla(240.0 / 360., 1.0, 0.5, 0.3), // Blue
offset: point(px(-12.), px(0.)),
blur_radius: px(8.),
spread_radius: px(2.),
},
]),
),
example(
"Rounded Large Multiple",
Shadow::rounded_large().shadow(vec![
BoxShadow {
color: hsla(0.0 / 360., 1.0, 0.5, 0.3), // Red
offset: point(px(0.), px(-12.)),
blur_radius: px(8.),
spread_radius: px(2.),
},
BoxShadow {
color: hsla(60.0 / 360., 1.0, 0.5, 0.3), // Yellow
offset: point(px(12.), px(0.)),
blur_radius: px(8.),
spread_radius: px(2.),
},
BoxShadow {
color: hsla(120.0 / 360., 1.0, 0.5, 0.3), // Green
offset: point(px(0.), px(12.)),
blur_radius: px(8.),
spread_radius: px(2.),
},
BoxShadow {
color: hsla(240.0 / 360., 1.0, 0.5, 0.3), // Blue
offset: point(px(-12.), px(0.)),
blur_radius: px(8.),
spread_radius: px(2.),
},
]),
),
]),
]))
}
}
fn main() {
Application::new().run(|cx: &mut App| {
let bounds = Bounds::centered(None, size(px(1000.0), px(800.0)), cx);
cx.open_window(
WindowOptions {
window_bounds: Some(WindowBounds::Windowed(bounds)),
..Default::default()
},
|_, cx| cx.new(|_| Shadow {}),
)
.unwrap();
cx.activate(true);
});
}