dioxus-community / dioxus-free-icons

Use free svg icons in your Dioxus projects easily with dioxus-free-icons.
Other
79 stars 21 forks source link

How to use icons in for loops? #49

Open nxy7 opened 4 months ago

nxy7 commented 4 months ago

Here's what I'm trying to do

image

I've tried using tuples, boxing the Icons, but nothing seems to work. Actually IDK if that's possible but maybe it would be nice to provide IconShape implementation for anything that can be dereferenced into IconShape (but that's separate issue)?

Is it possible to create vector of icons and display it?

marc2332 commented 4 months ago

Hey 👋🏻

Can you share the full error and the definition of NavbarLink?

marc2332 commented 4 months ago

Also of GenericIcon

nxy7 commented 4 months ago

I've tried multiple things so definition of NavbarLink is not very relevant here. Here's what I've tried:

pub struct NavbarLink {
    pub name: String,
    pub route: DashboardRouter,
    pub icon: &'static dyn IconShape,
}
and
pub struct NavbarLink {
    pub name: String,
    pub route: DashboardRouter,
    pub icon: Box<dyn IconShape>,
}

Boxing shape results in:

the trait bound `std::boxed::Box<dioxus_free_icons::icons::ld_icons::LdAArrowUp>: dioxus_free_icons::IconShape` is not satisfied
the following other types implement trait `dioxus_free_icons::IconShape`:
  dioxus_free_icons::icons::ld_icons::LdAArrowDown
  dioxus_free_icons::icons::ld_icons::LdAArrowUp
  dioxus_free_icons::icons::ld_icons::LdALargeSmall
  dioxus_free_icons::icons::ld_icons::LdAccessibility
  dioxus_free_icons::icons::ld_icons::LdActivity
  dioxus_free_icons::icons::ld_icons::LdAirVent
  dioxus_free_icons::icons::ld_icons::LdAirplay
  dioxus_free_icons::icons::ld_icons::LdAlarmClock
and 1448 others

I've tried to make my own GenericIcon to provide implementation for Box

#[derive(Clone)]
pub struct GenericIcon(Box<dyn IconShape>);
impl IconShape for GenericIcon {
    fn view_box(&self) -> &str {
        self.0.view_box()
    }

    fn xmlns(&self) -> &str {
        self.0.xmlns()
    }

    fn child_elements(&self) -> Element {
        self.0.child_elements()
    }
}

but that doesn't work since IconShape doesn't imply Clone and I think Icon needs to be Clone to be used in rsx! (?)

the trait bound `dyn dioxus_free_icons::IconShape: std::clone::Clone` is not satisfied
required for `std::boxed::Box<dyn dioxus_free_icons::IconShape>` to implement `std::clone::Clone`

Basically I'd like to know any way to have vector of Icons in any generic form that can be used atm (or if that's not doable rn).

marc2332 commented 4 months ago

Can you paste your code?

nxy7 commented 4 months ago

I guess that would be the minimal example (I got rid of NavbarItem and GenericIcon as they don't really matter here)

use dioxus_free_icons::{Icon, IconShape};

use crate::{prelude::*, router::DashboardRouter};

#[component]
pub fn DashboardLayout() -> Element {
    rsx! {
        DashboardNavbar {}
        Outlet::<DashboardRouter> {}
    }
}

#[component]
fn DashboardNavbar() -> Element {
    use dioxus_free_icons::icons::ld_icons::*;
    let navbar_items: Vec<(&str, DashboardRouter, Box<dyn IconShape>)> = vec![
        (
            "One Link",
            DashboardRouter::Dashboard {},
            Box::new(LdAArrowUp),
        ),
        (
            "Another Link",
            DashboardRouter::Dashboard {},
            Box::new(LdAArrowDown),
        ),
    ];

    rsx! {
        nav {
            ul {
                for link in navbar_items {
                    li {
                        Icon { width: 30, height: 30, fill: "black", icon: link.2 }
                        Link { to: link.1, {link.0} }
                    }
                }
            }
        }
    }
}

which gives me the following error

the trait bound `std::boxed::Box<dyn dioxus_free_icons::IconShape>: dioxus_free_icons::IconShape` is not satisfied
the following other types implement trait `dioxus_free_icons::IconShape`:
  dioxus_free_icons::icons::ld_icons::LdAArrowDown
  dioxus_free_icons::icons::ld_icons::LdAArrowUp
  dioxus_free_icons::icons::ld_icons::LdALargeSmall
  dioxus_free_icons::icons::ld_icons::LdAccessibility
  dioxus_free_icons::icons::ld_icons::LdActivity
  dioxus_free_icons::icons::ld_icons::LdAirVent
  dioxus_free_icons::icons::ld_icons::LdAirplay
  dioxus_free_icons::icons::ld_icons::LdAlarmClock
and 1448 others
marc2332 commented 4 months ago

Could you try something like this?

use dioxus_free_icons::{Icon, IconShape};

use crate::{prelude::*, router::DashboardRouter};

#[component]
pub fn DashboardLayout() -> Element {
    rsx! {
        DashboardNavbar {}
        Outlet::<DashboardRouter> {}
    }
}

#[component]
fn DashboardNavbar() -> Element {
    use dioxus_free_icons::icons::ld_icons::*;
    let navbar_items: Vec<(&str, DashboardRouter, props)> = vec![
        (
            "One Link",
            DashboardRouter::Dashboard {},
            IconProps { icon: LdAArrowUp },
        ),
        (
            "Another Link",
            DashboardRouter::Dashboard {},
            IconProps { icon: LdAArrowDown },
        ),
    ];

    rsx! {
        nav {
            ul {
                for (title, route, icon_props) in navbar_items {
                    li {
                        Icon { width: 30, height: 30, fill: "black", ..icon_props }
                        Link { to: route, "{title}" }
                    }
                }
            }
        }
    }
}
nxy7 commented 4 months ago

I don't think I can do that as IconProps is generic over IconShape, so each new IconProp would be another type, right? Because of this I can't get this to work. F.e. something like

    let prop = IconProps {
        icon: LdAArrowDown,
        height: 20,
        width: 20,
        fill: "".into(),
        class: "".into(),
        title: "".to_owned().into(),
    };
    let another_prop = IconProps {
        icon: LdALargeSmall,
        height: 20,
        width: 20,
        fill: "".into(),
        class: "".into(),
        title: "".to_owned().into(),
    };
    let vec = vec![prop, another_prop];

will result in

mismatched types
expected struct `dioxus_free_icons::IconProps<dioxus_free_icons::icons::ld_icons::LdAArrowDown>`
   found struct `dioxus_free_icons::IconProps<dioxus_free_icons::icons::ld_icons::LdALargeSmall>`

I think that there should be some IconShape implementation for smart pointers, maybe something like

impl<T> IconShape for Box<T>
where
    T: IconShape,
{
    fn view_box(&self) -> &str {
        self.view_box()
    }

    fn xmlns(&self) -> &str {
        self.xmlns()
    }

    fn child_elements(&self) -> Element {
        self.child_elements()
    }
}

would be enough so we could have vector of Boxed icons?

marc2332 commented 4 months ago
impl<T> 
where
    T: IconShape,
{
    fn view_box(&self) -> &str {
        self.view_box()
    }

    fn xmlns(&self) -> &str {
        self.xmlns()
    }

    fn child_elements(&self) -> Element {
        self.child_elements()
    }
}

Yeah, seems like implementing IconShape for Box<T> is the way to go