Introduces an `AnimationMode` enum with `Reactive`, `Continuous`, and `NoAnimation` variants to allow fine-grained control over GIF playback across the UI. This supports performance optimizations and accessibility features, such as disabling animations when requested. - Plumbs AnimationMode through image rendering paths - Replaces hardcoded gif frame logic with reusable `process_gif_frame` - Supports customizable FPS in Continuous mode - Enables global animation opt-out via `NoteOptions::NoAnimations` - Applies mode-specific logic in profile pictures, posts, media carousels, and viewer Animation behavior by context ----------------------------- - Profile pictures: Reactive (render only on interaction/activity) - PostView: NoAnimation if disabled in NoteOptions, else Continuous (uncapped) - Media carousels: NoAnimation or Continuous (capped at 24fps) - Viewer/gallery: Always Continuous (full animation) In the future, we can customize these by power settings. Signed-off-by: William Casarin <jb55@jb55.com>
NoteDeck UI
UI component library for NoteDeck - a Nostr client built with EGUI.
Overview
The notedeck_ui crate provides a set of reusable UI components for building a Nostr client. It offers consistent styling, behavior, and rendering of Nostr-specific elements like notes, profiles, mentions, and media content.
This library is built on top of egui, a simple, fast, and highly portable immediate mode GUI library for Rust.
Features
- 📝 Note display with rich content, media, and interactions
- 👤 Profile components (display name, pictures, banners)
- 🔗 Mention system with hover previews
- 🖼️ Image handling with caching and lazy loading
- 📺 GIF playback support
- 💸 Zap interactions (Bitcoin Lightning tips)
- 🎨 Theming and consistent styling
Components
Notes
The NoteView widget is the core component for displaying Nostr notes:
// Example: Render a note
let mut note_view = NoteView::new(
note_context,
current_account,
¬e,
NoteOptions::default()
);
ui.add(&mut note_view);
NoteView supports various display options:
// Create a preview style note
note_view
.preview_style() // Apply preview styling
.textmode(true) // Use text-only mode
.actionbar(false) // Hide action bar
.small_pfp(true) // Use small profile picture
.note_previews(false) // Disable nested note previews
.show(ui);
Profiles
Profile components include profile pictures, banners, and display names:
// Display a profile picture
ui.add(ProfilePic::new(images_cache, profile_picture_url).size(48.0));
// Display a profile preview
ui.add(ProfilePreview::new(profile_record, images_cache));
Mentions
The mention component links to user profiles:
// Display a mention with hover preview
let mention_response = Mention::new(ndb, img_cache, txn, pubkey)
.size(16.0) // Set text size
.selectable(true) // Allow selection
.show(ui);
// Handle click actions
if let Some(action) = mention_response.inner {
// Handle profile navigation
}
Media
Support for images, GIFs, and other media types:
// Render an image
render_images(
ui,
img_cache,
image_url,
ImageType::Content,
cache_type,
on_loading_callback,
on_error_callback,
on_success_callback
);
Styling
The UI components adapt to the current theme (light/dark mode) and use consistent styling defined in the colors.rs module:
// Color constants
pub const ALMOST_WHITE: Color32 = Color32::from_rgb(0xFA, 0xFA, 0xFA);
pub const MID_GRAY: Color32 = Color32::from_rgb(0xbd, 0xbd, 0xbd);
pub const PINK: Color32 = Color32::from_rgb(0xE4, 0x5A, 0xC9);
pub const TEAL: Color32 = Color32::from_rgb(0x77, 0xDC, 0xE1);
Dependencies
This crate depends on:
egui- Core UI libraryegui_extras- Additional widgets and functionalityehttp- HTTP client for fetching contentnostrdb- Nostr database and typesenostr- Nostr protocol implementationimage- Image processing librarypoll-promise- Async promise handlingtokio- Async runtime