notedeck

One damus client to rule them all
git clone git://jb55.com/notedeck
Log | Files | Refs | README | LICENSE

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     &note,         // 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, &note, 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 ```