Skip to main content Skills Marketplace Découvrez et explorez les compétences IA créées par la communauté.
Installer avec Codex ou Claude Copiez ce prompt, collez-le dans Codex, Claude ou un autre assistant, puis laissez-le vérifier la page du skill et l'installer pour vous.
Copier le promptAfficher les détails du prompt Une commande directe contourne le prompt de vérification. Examinez la source avant de l'exécuter.
npx skills add https://github.com/BEKO2210/Firstbrain --skill robius-widget-patternsLa commande reste sur une seule ligne. Faites défiler horizontalement pour la vérifier avant de la copier.
Vous préférez une copie locale ? Téléchargez les fichiers actuellement disponibles dans SkillsMP.
Télécharger Zip Téléchargement... Métiers associés SOC
Basé sur la classification professionnelle 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]]