mirror of
https://github.com/adoyle0/thaw.git
synced 2025-02-02 08:34:15 -05:00
refactor: avatar
This commit is contained in:
parent
824ca9c4b1
commit
d00e970a6a
7 changed files with 208 additions and 62 deletions
|
@ -1,11 +1,54 @@
|
|||
# Avatar
|
||||
|
||||
```rust demo
|
||||
view! {
|
||||
<Avatar />
|
||||
}
|
||||
```
|
||||
|
||||
### Name
|
||||
|
||||
```rust demo
|
||||
view! {
|
||||
<Avatar name="Ashley McCarthy" />
|
||||
}
|
||||
```
|
||||
|
||||
### Image
|
||||
|
||||
```rust demo
|
||||
view! {
|
||||
<Avatar src="https://s3.bmp.ovh/imgs/2021/10/723d457d627fe706.jpg" />
|
||||
}
|
||||
```
|
||||
|
||||
### Shape
|
||||
|
||||
```rust demo
|
||||
view! {
|
||||
<Avatar shape=AvatarShape::Square />
|
||||
}
|
||||
```
|
||||
|
||||
### Size
|
||||
|
||||
```rust demo
|
||||
view! {
|
||||
<Space>
|
||||
<Avatar src="https://s3.bmp.ovh/imgs/2021/10/723d457d627fe706.jpg"/>
|
||||
<Avatar src="https://s3.bmp.ovh/imgs/2021/10/723d457d627fe706.jpg" round=true/>
|
||||
<Avatar src="https://s3.bmp.ovh/imgs/2021/10/723d457d627fe706.jpg" size=50/>
|
||||
<Avatar initials="16" size=16 />
|
||||
<Avatar initials="20" size=20 />
|
||||
<Avatar initials="24" size=24 />
|
||||
<Avatar initials="28" size=28 />
|
||||
<Avatar initials="32" size=32 />
|
||||
<Avatar initials="36" size=36 />
|
||||
<Avatar initials="40" size=40 />
|
||||
<Avatar initials="48" size=48 />
|
||||
<Avatar initials="56" size=56 />
|
||||
<Avatar initials="64" size=64 />
|
||||
<Avatar initials="72" size=72 />
|
||||
<Avatar initials="96" size=96 />
|
||||
<Avatar initials="120" size=120 />
|
||||
<Avatar initials="128" size=128 />
|
||||
</Space>
|
||||
}
|
||||
```
|
||||
|
|
|
@ -1,13 +1,55 @@
|
|||
.thaw-avatar {
|
||||
display: inline-block;
|
||||
width: var(--thaw-size);
|
||||
height: var(--thaw-size);
|
||||
background-color: var(--thaw-background-color);
|
||||
border-radius: var(--thaw-border-radius);
|
||||
flex-shrink: 0;
|
||||
position: relative;
|
||||
vertical-align: middle;
|
||||
border-radius: var(--borderRadiusCircular);
|
||||
font-family: var(--fontFamilyBase);
|
||||
font-weight: var(--fontWeightSemibold);
|
||||
font-size: var(--fontSizeBase300);
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
}
|
||||
|
||||
.thaw-avatar img {
|
||||
.thaw-avatar--square {
|
||||
border-radius: var(--borderRadiusMedium);
|
||||
}
|
||||
|
||||
.thaw-avatar__icon,
|
||||
.thaw-avatar__initials {
|
||||
position: absolute;
|
||||
box-sizing: border-box;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: var(--thaw-border-radius);
|
||||
line-height: 1;
|
||||
border: var(--strokeWidthThin) solid var(--colorTransparentStroke);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
text-align: center;
|
||||
user-select: none;
|
||||
border-radius: inherit;
|
||||
|
||||
background-color: var(--colorNeutralBackground6);
|
||||
color: var(--colorNeutralForeground3);
|
||||
}
|
||||
|
||||
.thaw-avatar__icon {
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.thaw-avatar__image {
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: inherit;
|
||||
object-fit: cover;
|
||||
vertical-align: top;
|
||||
|
||||
background-color: var(--colorNeutralBackground6);
|
||||
color: var(--colorNeutralForeground3);
|
||||
}
|
||||
|
|
|
@ -1,45 +1,107 @@
|
|||
mod theme;
|
||||
|
||||
pub use theme::AvatarTheme;
|
||||
|
||||
use crate::{use_theme, Theme};
|
||||
use leptos::*;
|
||||
use thaw_components::OptionComp;
|
||||
use thaw_utils::{class_list, mount_style, OptionalProp};
|
||||
use thaw_utils::{class_list, mount_style, OptionalProp, StoredMaybeSignal};
|
||||
|
||||
#[component]
|
||||
pub fn Avatar(
|
||||
#[prop(optional, into)] src: Option<MaybeSignal<String>>,
|
||||
#[prop(optional, into)] round: MaybeSignal<bool>,
|
||||
#[prop(default = MaybeSignal::Static(30), into)] size: MaybeSignal<u16>,
|
||||
/// The Avatar's image.
|
||||
#[prop(optional, into)]
|
||||
src: Option<MaybeSignal<String>>,
|
||||
/// The name of the person or entity represented by this Avatar.
|
||||
#[prop(optional, into)]
|
||||
name: Option<MaybeSignal<String>>,
|
||||
/// Custom initials.
|
||||
#[prop(optional, into)]
|
||||
initials: Option<MaybeSignal<String>>,
|
||||
/// The avatar can have a circular or square shape.
|
||||
#[prop(optional, into)]
|
||||
shape: MaybeSignal<AvatarShape>,
|
||||
/// Size of the avatar in pixels.
|
||||
#[prop(optional, into)] size: Option<MaybeSignal<u8>>,
|
||||
#[prop(optional, into)] class: OptionalProp<MaybeSignal<String>>,
|
||||
) -> impl IntoView {
|
||||
let theme = use_theme(Theme::light);
|
||||
let css_vars = create_memo(move |_| {
|
||||
let mut css_vars = String::new();
|
||||
css_vars.push_str(&format!("--thaw-size: {}px;", size.get()));
|
||||
css_vars.push_str(&format!(
|
||||
"--thaw-border-radius: {};",
|
||||
if round.get() { "50%" } else { "3px" }
|
||||
));
|
||||
theme.with(|theme| {
|
||||
css_vars.push_str(&format!(
|
||||
"--thaw-background-color: {}",
|
||||
theme.avatar.background_color
|
||||
));
|
||||
});
|
||||
css_vars
|
||||
});
|
||||
mount_style("avatar", include_str!("./avatar.css"));
|
||||
|
||||
let style = move || {
|
||||
let size = size?.get();
|
||||
|
||||
let mut style = format!("width: {0}px; height: {0}px;", size);
|
||||
|
||||
if let Some(font_size) = match size {
|
||||
0..=24 => Some(100),
|
||||
25..=28 => Some(200),
|
||||
29..=40 => None,
|
||||
41..=56 => Some(400),
|
||||
57..=96 => Some(500),
|
||||
97..=128 => Some(600),
|
||||
_ => Some(600),
|
||||
} {
|
||||
style.push_str(&format!("font-size: var(--fontSizeBase{});", font_size))
|
||||
}
|
||||
|
||||
Some(style)
|
||||
};
|
||||
|
||||
let is_show_default_icon = src.is_none() && initials.is_none() && name.is_none();
|
||||
let name: Option<StoredMaybeSignal<_>> = name.map(|n| n.into());
|
||||
|
||||
view! {
|
||||
<span
|
||||
class=class_list!["thaw-avatar", class.map(| c | move || c.get())]
|
||||
style=move || css_vars.get()
|
||||
class=class_list!["thaw-avatar", move || format!("thaw-avatar--{}", shape.get().as_str()), class.map(| c | move || c.get())]
|
||||
style=style
|
||||
role="img"
|
||||
aria-label=move || name.as_ref().map(|n| n.get())
|
||||
>
|
||||
{
|
||||
move || {
|
||||
if let Some(initials) = initials.as_ref().map_or_else(|| name.as_ref().map(|n| initials_name(n.get())), |i| Some(i.get())) {
|
||||
view! {
|
||||
<span class="thaw-avatar__initials">
|
||||
{initials}
|
||||
</span>
|
||||
}.into()
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
<OptionComp value=src let:src>
|
||||
<img src=move || src.get()/>
|
||||
<img src=move || src.get() class="thaw-avatar__image"/>
|
||||
</OptionComp>
|
||||
{
|
||||
if is_show_default_icon {
|
||||
view! {
|
||||
<span aria-hidden="true" class="thaw-avatar__icon">
|
||||
<svg fill="currentColor" aria-hidden="true" width="1em" height="1em" viewBox="0 0 20 20">
|
||||
<path d="M10 2a4 4 0 1 0 0 8 4 4 0 0 0 0-8ZM7 6a3 3 0 1 1 6 0 3 3 0 0 1-6 0Zm-2 5a2 2 0 0 0-2 2c0 1.7.83 2.97 2.13 3.8A9.14 9.14 0 0 0 10 18c1.85 0 3.58-.39 4.87-1.2A4.35 4.35 0 0 0 17 13a2 2 0 0 0-2-2H5Zm-1 2a1 1 0 0 1 1-1h10a1 1 0 0 1 1 1c0 1.3-.62 2.28-1.67 2.95A8.16 8.16 0 0 1 10 17a8.16 8.16 0 0 1-4.33-1.05A3.36 3.36 0 0 1 4 13Z" fill="currentColor"></path>
|
||||
</svg>
|
||||
</span>
|
||||
}.into()
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
</span>
|
||||
}
|
||||
}
|
||||
|
||||
// TODO
|
||||
fn initials_name(name: String) -> String {
|
||||
name.split_at(2).0.to_string().to_ascii_uppercase()
|
||||
}
|
||||
|
||||
#[derive(Default, Clone)]
|
||||
pub enum AvatarShape {
|
||||
#[default]
|
||||
Circular,
|
||||
Square,
|
||||
}
|
||||
|
||||
impl AvatarShape {
|
||||
pub fn as_str(&self) -> &'static str {
|
||||
match self {
|
||||
Self::Circular => "circular",
|
||||
Self::Square => "square",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,20 +0,0 @@
|
|||
use crate::theme::ThemeMethod;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct AvatarTheme {
|
||||
pub background_color: String,
|
||||
}
|
||||
|
||||
impl ThemeMethod for AvatarTheme {
|
||||
fn light() -> Self {
|
||||
Self {
|
||||
background_color: "#f7f7f7".into(),
|
||||
}
|
||||
}
|
||||
|
||||
fn dark() -> Self {
|
||||
Self {
|
||||
background_color: "#424245".into(),
|
||||
}
|
||||
}
|
||||
}
|
|
@ -6,6 +6,7 @@ pub struct ColorTheme {
|
|||
pub color_neutral_background_1: String,
|
||||
pub color_neutral_background_1_hover: String,
|
||||
pub color_neutral_background_1_pressed: String,
|
||||
pub color_neutral_background_6: String,
|
||||
|
||||
pub color_neutral_foreground_disabled: String,
|
||||
pub color_neutral_foreground_1: String,
|
||||
|
@ -16,6 +17,7 @@ pub struct ColorTheme {
|
|||
pub color_neutral_foreground_2_pressed: String,
|
||||
pub color_neutral_foreground_2_brand_hover: String,
|
||||
pub color_neutral_foreground_2_brand_pressed: String,
|
||||
pub color_neutral_foreground_3: String,
|
||||
pub color_neutral_foreground_4: String,
|
||||
pub color_neutral_foreground_on_brand: String,
|
||||
|
||||
|
@ -47,6 +49,8 @@ impl ColorTheme {
|
|||
color_neutral_background_1: "#fff".into(),
|
||||
color_neutral_background_1_hover: "#f5f5f5".into(),
|
||||
color_neutral_background_1_pressed: "#e0e0e0".into(),
|
||||
color_neutral_background_6: "#e6e6e6".into(),
|
||||
|
||||
color_neutral_foreground_disabled: "#bdbdbd".into(),
|
||||
color_neutral_foreground_1: "#242424".into(),
|
||||
color_neutral_foreground_1_hover: "#242424".into(),
|
||||
|
@ -56,6 +60,7 @@ impl ColorTheme {
|
|||
color_neutral_foreground_2_pressed: "#242424".into(),
|
||||
color_neutral_foreground_2_brand_hover: "#0f6cbd".into(),
|
||||
color_neutral_foreground_2_brand_pressed: "#115ea3".into(),
|
||||
color_neutral_foreground_3: "#616161".into(),
|
||||
color_neutral_foreground_4: "#707070".into(),
|
||||
color_neutral_foreground_on_brand: "#fff".into(),
|
||||
|
||||
|
@ -87,6 +92,8 @@ impl ColorTheme {
|
|||
color_neutral_background_1: "#292929".into(),
|
||||
color_neutral_background_1_hover: "#3d3d3d".into(),
|
||||
color_neutral_background_1_pressed: "#1f1f1f".into(),
|
||||
color_neutral_background_6: "#333333".into(),
|
||||
|
||||
color_neutral_foreground_disabled: "#5c5c5c".into(),
|
||||
color_neutral_foreground_1: "#fff".into(),
|
||||
color_neutral_foreground_1_hover: "#fff".into(),
|
||||
|
@ -96,6 +103,7 @@ impl ColorTheme {
|
|||
color_neutral_foreground_2_pressed: "#fff".into(),
|
||||
color_neutral_foreground_2_brand_hover: "#479ef5".into(),
|
||||
color_neutral_foreground_2_brand_pressed: "#2886de".into(),
|
||||
color_neutral_foreground_3: "#adadad".into(),
|
||||
color_neutral_foreground_4: "#999999".into(),
|
||||
color_neutral_foreground_on_brand: "#fff".into(),
|
||||
|
||||
|
|
|
@ -20,9 +20,16 @@ pub struct CommonTheme {
|
|||
pub color_error_hover: String,
|
||||
pub color_error_active: String,
|
||||
|
||||
pub font_size_base_100: String,
|
||||
pub font_size_base_200: String,
|
||||
pub font_size_base_300: String,
|
||||
pub font_size_base_400: String,
|
||||
pub font_size_base_500: String,
|
||||
pub font_size_base_600: String,
|
||||
pub font_size_base_700: String,
|
||||
pub font_size_base_800: String,
|
||||
pub font_size_base_900: String,
|
||||
pub font_size_base_1000: String,
|
||||
|
||||
pub line_height_base_200: String,
|
||||
pub line_height_base_300: String,
|
||||
|
@ -81,9 +88,16 @@ impl CommonTheme {
|
|||
color_error_hover: "".into(),
|
||||
color_error_active: "".into(),
|
||||
|
||||
font_size_base_100: "10px".into(),
|
||||
font_size_base_200: "12px".into(),
|
||||
font_size_base_300: "14px".into(),
|
||||
font_size_base_400: "16px".into(),
|
||||
font_size_base_500: "20px".into(),
|
||||
font_size_base_600: "24px".into(),
|
||||
font_size_base_700: "28px".into(),
|
||||
font_size_base_800: "32px".into(),
|
||||
font_size_base_900: "40px".into(),
|
||||
font_size_base_1000: "60px".into(),
|
||||
|
||||
line_height_base_200: "16px".into(),
|
||||
line_height_base_300: "20px".into(),
|
||||
|
|
|
@ -4,7 +4,7 @@ mod common;
|
|||
use self::common::CommonTheme;
|
||||
use crate::{
|
||||
mobile::{NavBarTheme, TabbarTheme},
|
||||
AlertTheme, AnchorTheme, AutoCompleteTheme, AvatarTheme, BackTopTheme, BreadcrumbTheme,
|
||||
AlertTheme, AnchorTheme, AutoCompleteTheme, BackTopTheme, BreadcrumbTheme,
|
||||
CalendarTheme, CollapseTheme, ColorPickerTheme, DatePickerTheme, InputTheme, MenuTheme,
|
||||
MessageTheme, PopoverTheme, ProgressTheme, ScrollbarTheme, SelectTheme, SkeletionTheme,
|
||||
SliderTheme, SpinnerTheme, SwitchTheme, TableTheme, TagTheme, TimePickerTheme, TypographyTheme,
|
||||
|
@ -29,7 +29,6 @@ pub struct Theme {
|
|||
pub alert: AlertTheme,
|
||||
pub skeletion: SkeletionTheme,
|
||||
pub tag: TagTheme,
|
||||
pub avatar: AvatarTheme,
|
||||
pub message: MessageTheme,
|
||||
pub select: SelectTheme,
|
||||
pub slider: SliderTheme,
|
||||
|
@ -65,7 +64,6 @@ impl Theme {
|
|||
alert: AlertTheme::light(),
|
||||
skeletion: SkeletionTheme::light(),
|
||||
tag: TagTheme::light(),
|
||||
avatar: AvatarTheme::light(),
|
||||
message: MessageTheme::light(),
|
||||
select: SelectTheme::light(),
|
||||
slider: SliderTheme::light(),
|
||||
|
@ -100,7 +98,6 @@ impl Theme {
|
|||
alert: AlertTheme::dark(),
|
||||
skeletion: SkeletionTheme::dark(),
|
||||
tag: TagTheme::dark(),
|
||||
avatar: AvatarTheme::dark(),
|
||||
message: MessageTheme::dark(),
|
||||
select: SelectTheme::dark(),
|
||||
slider: SliderTheme::dark(),
|
||||
|
|
Loading…
Add table
Reference in a new issue