components.md (8476B)
1 # NoteDeck UI Component Guide 2 3 This guide provides detailed documentation for the major UI components in the NoteDeck UI library. 4 5 ## Table of Contents 6 7 - [Notes](#notes) 8 - [NoteView](#noteview) 9 - [NoteContents](#notecontents) 10 - [NoteOptions](#noteoptions) 11 - [Profiles](#profiles) 12 - [ProfilePic](#profilepic) 13 - [ProfilePreview](#profilepreview) 14 - [Mentions](#mentions) 15 - [Media Handling](#media-handling) 16 - [Images](#images) 17 - [GIF Animation](#gif-animation) 18 - [Widgets & Utilities](#widgets--utilities) 19 20 ## Notes 21 22 ### NoteView 23 24 The `NoteView` component is the main container for displaying Nostr notes, handling the layout of profile pictures, author information, content, and interactive elements. 25 26 #### Usage 27 28 ```rust 29 let mut note_view = NoteView::new( 30 note_context, // NoteContext with DB, cache, etc. 31 current_acc, // Current user account (Option<KeypairUnowned>) 32 ¬e, // Reference to Note 33 options // NoteOptions (display configuration) 34 ); 35 36 // Configure display options 37 note_view 38 .actionbar(true) // Show/hide action bar 39 .small_pfp(false) // Use small profile picture 40 .medium_pfp(true) // Use medium profile picture 41 .wide(false) // Use wide layout 42 .frame(true) // Display with a frame 43 .note_previews(true) // Enable embedded note previews 44 .selectable_text(true); // Allow text selection 45 46 // Render the note view 47 let note_response = note_view.show(ui); 48 49 // Handle user actions 50 if let Some(action) = note_response.action { 51 match action { 52 NoteAction::Note(note_id) => { /* Note was clicked */ }, 53 NoteAction::Profile(pubkey) => { /* Profile was clicked */ }, 54 NoteAction::Reply(note_id) => { /* User clicked reply */ }, 55 NoteAction::Quote(note_id) => { /* User clicked quote */ }, 56 NoteAction::Zap(zap_action) => { /* User initiated zap */ }, 57 NoteAction::Hashtag(tag) => { /* Hashtag was clicked */ }, 58 NoteAction::Context(ctx_selection) => { /* Context menu option selected */ }, 59 } 60 } 61 ``` 62 63 #### Layouts 64 65 `NoteView` supports two main layouts: 66 67 1. **Standard Layout** - Default compact display 68 2. **Wide Layout** - More spacious layout with profile picture on the left 69 70 Use the `.wide(true)` option to enable the wide layout. 71 72 #### Preview Style 73 74 For displaying note previews (e.g., when a note is referenced in another note), use the preview style: 75 76 ```rust 77 let mut note_view = NoteView::new(note_context, current_acc, ¬e, options) 78 .preview_style(); // Applies preset options for preview display 79 ``` 80 81 ### NoteContents 82 83 `NoteContents` handles rendering the actual content of a note, including text, mentions, hashtags, URLs, and embedded media. 84 85 ```rust 86 let mut contents = NoteContents::new( 87 note_context, 88 current_acc, 89 transaction, 90 note, 91 note_options 92 ); 93 94 ui.add(&mut contents); 95 96 // Check for content interactions 97 if let Some(action) = contents.action() { 98 // Handle content action (e.g., clicked mention/hashtag) 99 } 100 ``` 101 102 ### NoteOptions 103 104 `NoteOptions` is a bitflag-based configuration system for controlling how notes are displayed: 105 106 ```rust 107 // Create with default options 108 let mut options = NoteOptions::default(); 109 110 // Or customize from scratch 111 let mut options = NoteOptions::new(is_universe_timeline); 112 113 // Configure options 114 options.set_actionbar(true); // Show action buttons 115 options.set_small_pfp(true); // Use small profile picture 116 options.set_medium_pfp(false); // Don't use medium profile picture 117 options.set_note_previews(true); // Enable note previews 118 options.set_wide(false); // Use compact layout 119 options.set_selectable_text(true); // Allow text selection 120 options.set_textmode(false); // Don't use text-only mode 121 options.set_options_button(true); // Show options button 122 options.set_hide_media(false); // Show media content 123 options.set_scramble_text(false); // Don't scramble text 124 options.set_is_preview(false); // This is not a preview 125 ``` 126 127 ## Profiles 128 129 ### ProfilePic 130 131 `ProfilePic` displays a circular profile picture with optional border and configurable size. 132 133 ```rust 134 // Basic usage 135 ui.add(ProfilePic::new(img_cache, profile_url)); 136 137 // Customized 138 ui.add( 139 ProfilePic::new(img_cache, profile_url) 140 .size(48.0) 141 .border(Stroke::new(2.0, Color32::WHITE)) 142 ); 143 144 // From profile record 145 if let Some(profile_pic) = ProfilePic::from_profile(img_cache, profile) { 146 ui.add(profile_pic); 147 } 148 ``` 149 150 Standard sizes: 151 - `ProfilePic::default_size()` - 38px 152 - `ProfilePic::medium_size()` - 32px 153 - `ProfilePic::small_size()` - 24px 154 155 ### ProfilePreview 156 157 `ProfilePreview` shows a detailed profile card with banner, profile picture, display name, username, and about text. 158 159 ```rust 160 // Full preview 161 ui.add(ProfilePreview::new(profile, img_cache)); 162 163 // Simple preview 164 ui.add(SimpleProfilePreview::new( 165 Some(profile), // Option<&ProfileRecord> 166 img_cache, 167 is_nsec // Whether this is a full keypair 168 )); 169 ``` 170 171 ## Mentions 172 173 The `Mention` component renders a clickable @username reference with hover preview. 174 175 ```rust 176 let mention_response = Mention::new(ndb, img_cache, txn, pubkey) 177 .size(16.0) // Text size 178 .selectable(false) // Disable text selection 179 .show(ui); 180 181 // Handle mention click 182 if let Some(action) = mention_response.inner { 183 // Usually NoteAction::Profile 184 } 185 ``` 186 187 ## Media Handling 188 189 ### Images 190 191 Images are managed through the `render_images` function, which handles loading, caching, and displaying images: 192 193 ```rust 194 render_images( 195 ui, 196 img_cache, 197 url, 198 ImageType::Content, // Or ImageType::Profile(size) 199 MediaCacheType::Image, 200 |ui| { 201 // Show while loading 202 ui.spinner(); 203 }, 204 |ui, error| { 205 // Show on error 206 ui.label(format!("Error: {}", error)); 207 }, 208 |ui, url, img, gifs| { 209 // Show successful image 210 let texture = handle_repaint(ui, retrieve_latest_texture(url, gifs, img)); 211 ui.image(texture); 212 } 213 ); 214 ``` 215 216 For profile images, use `ImageType::Profile(size)` to automatically crop, resize, and round the image. 217 218 ### GIF Animation 219 220 GIFs are supported through the animation system. The process for displaying GIFs is: 221 222 1. Load and decode GIF in background thread 223 2. Send frames to UI thread through channels 224 3. Render frames with timing control 225 226 ```rust 227 // Display a GIF 228 render_images( 229 ui, 230 img_cache, 231 gif_url, 232 ImageType::Content, 233 MediaCacheType::Gif, 234 /* callbacks as above */ 235 ); 236 237 // Get the current frame texture 238 let texture = handle_repaint( 239 ui, 240 retrieve_latest_texture(url, gifs, renderable_media) 241 ); 242 ``` 243 244 ## Widgets & Utilities 245 246 ### Username 247 248 Displays a user's name with options for abbreviation and color: 249 250 ```rust 251 ui.add( 252 Username::new(profile, pubkey) 253 .pk_colored(true) // Color based on pubkey 254 .abbreviated(16) // Max length before abbreviation 255 ); 256 ``` 257 258 ### Animations 259 260 Use animation helpers for interactive elements: 261 262 ```rust 263 // Basic hover animation 264 let (rect, size, response) = hover_expand( 265 ui, 266 id, // Unique ID for the animation 267 base_size, // Base size 268 expand_size, // Amount to expand by 269 anim_speed // Animation speed 270 ); 271 272 // Small hover expand (common pattern) 273 let (rect, size, response) = hover_expand_small(ui, id); 274 275 // Advanced helper 276 let helper = AnimationHelper::new(ui, "animation_name", max_size); 277 let current_size = helper.scale_1d_pos(min_size); 278 ``` 279 280 ### Pulsing Effects 281 282 For elements that need attention: 283 284 ```rust 285 // Create pulsing image 286 let pulsing_image = ImagePulseTint::new( 287 &ctx, // EGUI Context 288 id, // Animation ID 289 image, // Base image 290 &[255, 183, 87], // Tint color 291 alpha_min, // Minimum alpha 292 alpha_max // Maximum alpha 293 ) 294 .with_speed(0.35) // Animation speed 295 .animate(); // Apply animation 296 297 ui.add(pulsing_image); 298 ``` 299 300 ### Context Menus 301 302 Create menus for additional actions: 303 304 ```rust 305 // Add context menu to any response 306 response.context_menu(|ui| { 307 if ui.button("Copy Link").clicked() { 308 ui.ctx().copy_text(url.to_owned()); 309 ui.close_menu(); 310 } 311 }); 312 ``` 313 314 The `NoteContextButton` component provides a standard context menu for notes: 315 316 ```rust 317 let resp = ui.add(NoteContextButton::new(note_key)); 318 if let Some(action) = NoteContextButton::menu(ui, resp) { 319 // Handle context action 320 } 321 ```