ccab39f140
Re-sincroniza las fuentes desde el monorepo (estaba en vello 0.5/wgpu 24 y con la estructura vieja de eventloop) y suma el 3D: - bump del workspace a vello 0.7 / wgpu 27 / parley 0.6, + accesskit 0.24 / accesskit_winit 0.33 / vello_hybrid 0.0.9. - nuevos crates: llimphi-3d (voxels ray-march + mallas en un depth compartido, montable dentro de un View 2D vía set_viewport+scissor) y llimphi-voxel (world-gen, personajes, director de escenas) + shared/foreign-vox (puente .vox). - README: sección "Not just 2D — a 3D voxel engine" + GIF (docs/llimphi_voxel.gif). - excluido modules/allichay (arrastra deps fuera del alcance del front-door). - cargo check --workspace: verde. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
171 lines
5.0 KiB
Rust
171 lines
5.0 KiB
Rust
//! `llimphi-widget-card` — container card-shape para entries de
|
|
//! timeline, info cards, dashboards, etc.
|
|
//!
|
|
//! Aporta la **forma**: padding consistente (12/8), `radius` 4, gap
|
|
//! pequeño entre children, y opcionalmente un accent vertical
|
|
//! (4 px) pegado a la izquierda para entries semánticas (verde =
|
|
//! OK, rojo = error, ámbar = warning, etc).
|
|
//!
|
|
//! Análogo Llimphi al `nahual-widget-card` GPUI.
|
|
|
|
#![forbid(unsafe_code)]
|
|
|
|
use llimphi_ui::llimphi_layout::taffy::{
|
|
prelude::{length, percent, FlexDirection, Size, Style},
|
|
Rect,
|
|
};
|
|
use llimphi_ui::llimphi_raster::peniko::Color;
|
|
use llimphi_ui::{Shadow, View};
|
|
use llimphi_theme::elevation;
|
|
use llimphi_widget_panel::{panel_signature_painter, PanelStyle};
|
|
|
|
#[derive(Debug, Clone, Copy)]
|
|
pub struct CardPalette {
|
|
pub bg: Color,
|
|
}
|
|
|
|
impl Default for CardPalette {
|
|
fn default() -> Self {
|
|
Self::from_theme(&llimphi_theme::Theme::dark())
|
|
}
|
|
}
|
|
|
|
impl CardPalette {
|
|
pub fn from_theme(t: &llimphi_theme::Theme) -> Self {
|
|
Self { bg: t.bg_panel }
|
|
}
|
|
}
|
|
|
|
/// Opciones del card.
|
|
#[derive(Debug, Clone, Copy)]
|
|
pub struct CardOptions {
|
|
/// Accent vertical a la izquierda (4 px). `None` = sin accent.
|
|
pub accent: Option<Color>,
|
|
pub padding: f32,
|
|
pub gap: f32,
|
|
pub radius: f64,
|
|
/// Firma visual del panel (gradient sutil + hairline accent en el
|
|
/// top). `Some(style)` reemplaza el fill plano del body por el
|
|
/// painter de la firma — usar para cards prominentes (dashboards,
|
|
/// timeline entries grandes) donde se nota el "tallado". `None`
|
|
/// mantiene el fill sólido del `CardPalette` (default).
|
|
pub signature: Option<PanelStyle>,
|
|
}
|
|
|
|
impl Default for CardOptions {
|
|
fn default() -> Self {
|
|
Self {
|
|
accent: None,
|
|
padding: 12.0,
|
|
gap: 4.0,
|
|
radius: 4.0,
|
|
signature: None,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl CardOptions {
|
|
/// Variante con firma visual derivada del theme. El `radius` del
|
|
/// card se alinea al del `PanelStyle` para que la silueta del
|
|
/// gradiente coincida con las esquinas del nodo.
|
|
pub fn with_signature(t: &llimphi_theme::Theme) -> Self {
|
|
let style = PanelStyle::from_theme(t);
|
|
Self {
|
|
accent: None,
|
|
padding: 12.0,
|
|
gap: 4.0,
|
|
radius: style.radius,
|
|
signature: Some(style),
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Compone un card: bg + radius + padding + flex-column con gap entre
|
|
/// children. Si `opts.accent` está presente, hay una franja vertical
|
|
/// de 4 px del color del accent pegada al borde izquierdo.
|
|
pub fn card_view<Msg: Clone + 'static>(
|
|
children: Vec<View<Msg>>,
|
|
opts: CardOptions,
|
|
palette: &CardPalette,
|
|
) -> View<Msg> {
|
|
let pad = opts.padding;
|
|
let body_style = Style {
|
|
flex_direction: FlexDirection::Column,
|
|
size: Size {
|
|
width: percent(1.0_f32),
|
|
height: llimphi_ui::llimphi_layout::taffy::prelude::Dimension::auto(),
|
|
},
|
|
flex_grow: 1.0,
|
|
padding: Rect {
|
|
left: length(pad),
|
|
right: length(pad),
|
|
top: length(pad * 0.66),
|
|
bottom: length(pad * 0.66),
|
|
},
|
|
gap: Size {
|
|
width: length(0.0_f32),
|
|
height: length(opts.gap),
|
|
},
|
|
..Default::default()
|
|
};
|
|
let body = if let Some(style) = opts.signature {
|
|
View::new(body_style)
|
|
.paint_with(panel_signature_painter(style))
|
|
.radius(opts.radius)
|
|
.clip(true)
|
|
.children(children)
|
|
} else {
|
|
View::new(body_style)
|
|
.fill(palette.bg)
|
|
.radius(opts.radius)
|
|
.children(children)
|
|
};
|
|
|
|
let Some(accent) = opts.accent else {
|
|
return body;
|
|
};
|
|
|
|
let accent_strip = View::new(Style {
|
|
size: Size {
|
|
width: length(4.0_f32),
|
|
height: percent(1.0_f32),
|
|
},
|
|
..Default::default()
|
|
})
|
|
.fill(accent)
|
|
.radius(opts.radius);
|
|
|
|
View::new(Style {
|
|
flex_direction: FlexDirection::Row,
|
|
size: Size {
|
|
width: percent(1.0_f32),
|
|
height: llimphi_ui::llimphi_layout::taffy::prelude::Dimension::auto(),
|
|
},
|
|
..Default::default()
|
|
})
|
|
.children(vec![accent_strip, body])
|
|
}
|
|
|
|
/// Variante elevada — la misma forma de `card_view` pero con sombra
|
|
/// del nivel `elev` (token de [`llimphi_theme::elevation`]). Default
|
|
/// pensado: `elevation::E2` (card flotante sobre el panel). El accent
|
|
/// strip — si está presente — queda detrás de la sombra; el visual
|
|
/// dominante es el body. Útil para dashboards y entries destacadas
|
|
/// que necesitan separación clara del fondo del panel.
|
|
pub fn card_elevated_view<Msg: Clone + 'static>(
|
|
children: Vec<View<Msg>>,
|
|
opts: CardOptions,
|
|
palette: &CardPalette,
|
|
elev: elevation::Elev,
|
|
) -> View<Msg> {
|
|
let (a, blur, dy) = elev;
|
|
let shadow = Shadow {
|
|
color: Color::from_rgba8(0, 0, 0, a),
|
|
blur,
|
|
dx: 0.0,
|
|
dy,
|
|
spread: 0.0,
|
|
};
|
|
card_view(children, opts, palette).shadow(shadow)
|
|
}
|