Skip to main content Skills Marketplace Descubra e explore skills de IA criadas pela comunidade.
Instalar com Codex ou Claude Copie este prompt, cole no Codex, Claude ou outro assistente e deixe que ele revise a página da skill e instale para você.
Copiar promptMostrar detalhes do prompt Um comando direto ignora o prompt de revisão. Verifique a origem antes de executá-lo.
npx skills add https://github.com/BEKO2210/Firstbrain --skill robius-widget-patternsO comando permanece em uma só linha. Role horizontalmente para revisá-lo antes de copiar.
Prefere uma cópia local? Baixe os arquivos disponíveis atualmente no SkillsMP.
Baixar Zip Baixando... Ocupações relacionadas SOC
Baseado na classificação ocupacional SOC
name robius-widget-patterns description | type skill created 2026-02-27T00:00:00.000Z domain software-development category architecture risk unknown source community tags ["skill","software-development","architecture","robius","widget"]
Robius Widget Patterns Skill
Best practices for designing reusable Makepad widgets based on Robrix and Moly codebase patterns.
Source codebases:
Robrix : Matrix chat client - Avatar, RoomsList, RoomScreen widgets
Moly : AI chat application - Slot, ChatLine, PromptInput, AdaptiveView widgets
When to Use
Use this skill when:
Creating reusable Makepad widgets
Designing widget component APIs
Implementing text/image toggle patterns
Dynamic styling in Makepad
Keywords: robrix widget, makepad component, reusable widget, widget design pattern
Production Patterns
For production-ready widget patterns, see the _base/ directory:
Pattern Description 01-widget-extension Add helper methods to widget references 02-modal-overlay Popups, dialogs using DrawList2d overlay 03-collapsible Expandable/collapsible sections 04-list-template Dynamic lists with LivePtr templates 05-lru-view-cache Memory-efficient view caching 14-callout-tooltip Tooltips with arrow positioning 20-redraw-optimization Efficient redraw patterns 15-dock-studio-layout IDE-style resizable panels 16-hover-effect Hover effects with instance variables 17-row-based-grid-layout Dynamic grid layouts 18-drag-drop-reorder Drag-and-drop widget reordering 19-pageflip-optimization PageFlip 切换优化,即刻销毁/缓存模式 21-collapsible-row-portal-list Auto-grouping consecutive items in portal lists with FoldHeader 22-dropdown-overlay Dropdown popups using DrawList2d overlay (no layout push)
Standard Widget Structure
use makepad_widgets::*;
live_design! {
use link::theme::*;
use link::widgets::*;
MyWidget = {{MyWidget}} {
width: Fill, height: Fit,
flow: Down,
inner_view = <View> {
}
}
}
{
view: View,
some_property: ,
default_val: ,
internal_state: State,
animator: Animator,
}
{
(& , cx: & Cx, event: &Event, scope: & Scope) {
.view. (cx, event, scope);
}
(& , cx: & Cx2d, scope: & Scope, walk: Walk) DrawStep {
.view. (cx, scope, walk)
}
}
pub
#[derive(Live, LiveHook, Widget)]
pub
struct
MyWidget
#[deref]
#[live]
f64
#[live(100.0)]
f64
#[rust]
#[animator]
impl
Widget
for
MyWidget
fn
handle_event
mut
self
mut
mut
self
handle_event
fn
draw_walk
mut
self
mut
mut
->
self
draw_walk
Text/Image Toggle Pattern A common pattern for widgets that show either text or an image (like avatars):
live_design! {
pub Avatar = {{Avatar}} {
width: 36.0 , height: 36.0 ,
align: { x: 0.5 , y: 0.5 }
flow: Overlay,
text_view = <View> {
visible: true ,
show_bg: true ,
draw_bg: {
uniform background_color: #888888
fn pixel (self ) -> vec4 {
let sdf = Sdf2d::viewport (self .pos * self .rect_size);
let c = self .rect_size * 0.5 ;
sdf.circle (c.x, c.x, c.x)
sdf.fill_keep (self .background_color);
return sdf.result
}
}
text = <Label> {
text: "?"
}
}
img_view = <View> {
visible: false ,
img = <Image> {
fit: Stretch,
width: Fill, height: Fill,
}
}
}
}
#[derive(LiveHook, Live, Widget)]
pub struct Avatar {
#[deref] view: View,
#[rust] info: Option <UserInfo>,
}
impl Avatar {
pub fn show_text <T: AsRef <str >>(
&mut self ,
cx: &mut Cx,
bg_color: Option <Vec4>,
info: Option <AvatarTextInfo>,
username: T,
) {
self .info = info.map (|i| i.into ());
let first_char = utils::first_letter (username.as_ref ())
.unwrap_or ("?" ).to_uppercase ();
self .label (ids!(text_view.text)).set_text (cx, &first_char);
self .view (ids!(text_view)).set_visible (cx, true );
self .view (ids!(img_view)).set_visible (cx, false );
if let Some (color) = bg_color {
self .view (ids!(text_view)).apply_over (cx, live! {
draw_bg: { background_color: (color) }
});
}
}
pub fn show_image <F, E>(
&mut self ,
cx: &mut Cx,
info: Option <AvatarImageInfo>,
image_set_fn: F,
) -> Result <(), E>
where
F: FnOnce (&mut Cx, ImageRef) -> Result <(), E>
{
let img_ref = self .image (ids!(img_view.img));
let res = image_set_fn (cx, img_ref);
if res.is_ok () {
self .view (ids!(img_view)).set_visible (cx, true );
self .view (ids!(text_view)).set_visible (cx, false );
self .info = info.map (|i| i.into ());
}
res
}
pub fn status (&mut self ) -> DisplayStatus {
if self .view (ids!(img_view)).visible () {
DisplayStatus::Image
} else {
DisplayStatus::Text
}
}
}
Dynamic Styling with apply_over Apply dynamic styles at runtime:
self .view (ids!(content)).apply_over (cx, live! {
draw_bg: { color: #ff0000 }
});
self .view (ids!(message)).apply_over (cx, live! {
padding: { left: 20 , right: 20 }
margin: { top: 10 }
});
let highlight_color = if is_selected { vec4 (1.0 , 0.0 , 0.0 , 1.0 ) } else { vec4 (0.5 , 0.5 , 0.5 , 1.0 ) };
self .view (ids!(item)).apply_over (cx, live! {
draw_bg: { color: (highlight_color) }
});
Widget Reference Pattern Implement *Ref methods for external API:
impl AvatarRef {
pub fn show_text <T: AsRef <str >>(
&self ,
cx: &mut Cx,
bg_color: Option <Vec4>,
info: Option <AvatarTextInfo>,
username: T,
) {
if let Some (mut inner) = self .borrow_mut () {
inner.show_text (cx, bg_color, info, username);
}
}
pub fn show_image <F, E>(
&self ,
cx: &mut Cx,
info: Option <AvatarImageInfo>,
image_set_fn: F,
) -> Result <(), E>
where
F: FnOnce (&mut Cx, ImageRef) -> Result <(), E>
{
if let Some (mut inner) = self .borrow_mut () {
inner.show_image (cx, info, image_set_fn)
} else {
Ok (())
}
}
}
Collapsible/Expandable Pattern live_design! {
pub CollapsibleSection = {{CollapsibleSection}} {
flow: Down,
header = <View> {
cursor: Hand,
icon = <Icon> { }
title = <Label> { text: "Section" }
}
content = <View> {
visible: false ,
}
}
}
#[derive(Live, LiveHook, Widget)]
pub struct CollapsibleSection {
#[deref] view: View,
#[rust] is_expanded: bool ,
}
impl CollapsibleSection {
pub fn toggle (&mut self , cx: &mut Cx) {
self .is_expanded = !self .is_expanded;
self .view (ids!(content)).set_visible (cx, self .is_expanded);
let rotation = if self .is_expanded { 90.0 } else { 0.0 };
self .view (ids!(header.icon)).apply_over (cx, live! {
draw_icon: { rotation: (rotation) }
});
self .redraw (cx);
}
}
Loading State Pattern live_design! {
pub LoadableContent = {{LoadableContent}} {
flow: Overlay,
content = <View> {
visible: true ,
}
loading_overlay = <View> {
visible: false ,
show_bg: true ,
draw_bg: { color: #00000088 }
align: { x: 0.5 , y: 0.5 }
<BouncingDots> { }
}
error_view = <View> {
visible: false ,
error_label = <Label> { }
}
}
}
#[derive(Live, LiveHook, Widget)]
pub struct LoadableContent {
#[deref] view: View,
#[rust] state: LoadingState,
}
pub enum LoadingState {
Idle,
Loading,
Loaded,
Error (String ),
}
impl LoadableContent {
pub fn set_state (&mut self , cx: &mut Cx, state: LoadingState) {
self .state = state;
match &self .state {
LoadingState::Idle | LoadingState::Loaded => {
self .view (ids!(content)).set_visible (cx, true );
self .view (ids!(loading_overlay)).set_visible (cx, false );
self .view (ids!(error_view)).set_visible (cx, false );
}
LoadingState::Loading => {
self .view (ids!(content)).set_visible (cx, true );
self .view (ids!(loading_overlay)).set_visible (cx, true );
self .view (ids!(error_view)).set_visible (cx, false );
}
LoadingState::Error (msg) => {
self .view (ids!(content)).set_visible (cx, false );
self .view (ids!(loading_overlay)).set_visible (cx, false );
self .view (ids!(error_view)).set_visible (cx, true );
self .label (ids!(error_view.error_label)).set_text (cx, msg);
}
}
self .redraw (cx);
}
}
PortalList Item Pattern live_design! {
pub ItemsList = {{ItemsList}} {
list = <PortalList> {
keep_invisible: false ,
auto_tail: false ,
width: Fill, height: Fill,
flow: Down,
item_entry = <ItemEntry> {}
header = <SectionHeader> {}
empty = <View> {}
}
}
}
impl Widget for ItemsList {
fn draw_walk (&mut self , cx: &mut Cx2d, scope: &mut Scope, walk: Walk) -> DrawStep {
while let Some (item) = self .view.draw_walk (cx, scope, walk).step () {
if let Some (mut list) = item.as_portal_list ().borrow_mut () {
list.set_item_range (cx, 0 , self .items.len ());
while let Some (item_id) = list.next_visible_item (cx) {
let item = list.item (cx, item_id, live_id!(item_entry));
self .populate_item (cx, item, &self .items[item_id]);
item.draw_all (cx, scope);
}
}
}
DrawStep::done ()
}
}
Best Practices
Use #[deref] for delegation : Delegate to inner View for standard behavior
Separate DSL properties (#[live]) from Rust state (#[rust])
Implement both inner methods and *Ref wrappers
Use apply_over for dynamic runtime styling
Use flow: Overlay for toggle/swap patterns
Use set_visible() to toggle between alternative views
Always call redraw(cx) after state changes
Reference Files
references/widget-patterns.md - Additional widget patterns (Robrix)
references/styling-patterns.md - Dynamic styling patterns (Robrix)
references/moly-widget-patterns.md - Moly-specific patterns
Slot widget for runtime content replacement
MolyRoot conditional rendering wrapper
AdaptiveView for responsive Mobile/Desktop layouts
Chat line variants (UserLine, BotLine, ErrorLine, etc.)
CommandTextInput with action buttons
Sidebar navigation with radio buttons
Connections
Domain: [[Software Entwicklung]]
Kategorie: [[Software Architektur]]
Navigation: [[Skills Uebersicht]], [[Home]]