feat: adds Link component

This commit is contained in:
luoxiao 2024-08-24 23:11:50 +08:00
parent 7b29f7da37
commit 5879a2df86
10 changed files with 244 additions and 6 deletions

View file

@ -86,13 +86,14 @@ fn TheRouter() -> impl IntoView {
<Route path=path!("/image") view=ImageMdPage/>
<Route path=path!("/input") view=InputMdPage/>
<Route path=path!("/layout") view=LayoutMdPage/>
<Route path=path!("/link") view=LinkMdPage/>
<Route path=path!("/loading-bar") view=LoadingBarMdPage/>
<Route path=path!("/message-bar") view=MessageBarMdPage/>
<Route path=path!("/nav") view=NavMdPage/>
<Route path=path!("/pagination") view=PaginationMdPage/>
<Route path=path!("/popover") view=PopoverMdPage/>
}.into_inner()}
{view!{
<Route path=path!("/pagination") view=PaginationMdPage/>
<Route path=path!("/popover") view=PopoverMdPage/>
<Route path=path!("/progress-bar") view=ProgressBarMdPage/>
<Route path=path!("/radio") view=RadioMdPage/>
<Route path=path!("/scrollbar") view=ScrollbarMdPage/>
@ -107,10 +108,10 @@ fn TheRouter() -> impl IntoView {
<Route path=path!("/tag") view=TagMdPage/>
<Route path=path!("/text") view=TextMdPage/>
<Route path=path!("/textarea") view=TextareaMdPage/>
<Route path=path!("/time-picker") view=TimePickerMdPage/>
<Route path=path!("/toast") view=ToastMdPage />
}.into_inner()}
{view!{
<Route path=path!("/time-picker") view=TimePickerMdPage/>
<Route path=path!("/toast") view=ToastMdPage />
<Route path=path!("/tooltip") view=TooltipMdPage />
<Route path=path!("/upload") view=UploadMdPage/>
}.into_inner()}

View file

@ -220,6 +220,10 @@ pub(crate) fn gen_nav_data() -> Vec<NavGroupOption> {
value: "/components/layout",
label: "Layout",
},
NavItemOption {
value: "/components/link",
label: "Link",
},
NavItemOption {
value: "/components/loading-bar",
label: "Loading Bar",

View file

@ -47,6 +47,7 @@ pub fn include_md(_token_stream: proc_macro::TokenStream) -> proc_macro::TokenSt
"ImageMdPage" => "../../thaw/src/image/docs/mod.md",
"InputMdPage" => "../../thaw/src/input/docs/mod.md",
"LayoutMdPage" => "../../thaw/src/layout/docs/mod.md",
"LinkMdPage" => "../../thaw/src/link/docs/mod.md",
"LoadingBarMdPage" => "../../thaw/src/loading_bar/docs/mod.md",
"MenuMdPage" => "../../thaw/src/menu/docs/mod.md",
"MessageBarMdPage" => "../../thaw/src/message_bar/docs/mod.md",

View file

@ -160,9 +160,9 @@ fn iter_nodes<'a>(
let NodeLink { url, title } = node_link;
quote!(
<a href=#url title=#title>
<Link href=#url attr:title=#title>
#(#children)*
</a>
</Link>
)
}
NodeValue::Image(_) => quote!("Image todo!!!"),

View file

@ -24,6 +24,7 @@ mod icon;
mod image;
mod input;
mod layout;
mod link;
mod loading_bar;
mod menu;
mod message_bar;
@ -75,6 +76,7 @@ pub use icon::*;
pub use image::*;
pub use input::*;
pub use layout::*;
pub use link::*;
pub use loading_bar::*;
pub use menu::*;
pub use message_bar::*;

79
thaw/src/link/docs/mod.md Normal file
View file

@ -0,0 +1,79 @@
# Link
```rust demo
view! {
<Space>
<Link href="http://example.com">
"This is a link"
</Link>
<Link>
"This is a link"
</Link>
<Link span=true>
"This is a link"
</Link>
</Space>
}
```
### Inline
```rust demo
view! {
<div>
"This is an "
<Link href="http://example.com" inline=true>
"inline link"
</Link>
" used alongside other text."
</div>
}
```
### Disabled
```rust demo
view! {
<Space>
<Link href="http://example.com" disabled=true>
"This is a link"
</Link>
<Link disabled=true>
"This is a link"
</Link>
<Link span=true disabled=true>
"This is a link"
</Link>
</Space>
}
```
### Disabled Focusable
```rust demo
view! {
<Space>
<Link href="http://example.com" disabled_focusable=true>
"This is a link"
</Link>
<Link disabled_focusable=true>
"This is a link"
</Link>
<Link span=true disabled_focusable=true>
"This is a link"
</Link>
</Space>
}
```
### Link Props
| Name | Type | Default | Description |
| --- | --- | --- | --- |
| class | `MaybeProp<String>` | `Default::default()` | |
| span | `bool` | `false` | |
| href | `Option<MaybeSignal<String>>` | `None` | |
| inline | `MaybeSignal<bool>` | `false` | If true, changes styling when the link is being used alongside other text content. |
| disabled | `MaybeSignal<bool>` | `false` | Whether the link is disabled. |
| disabled_focusable | `MaybeSignal<bool>` | `false` | When set, allows the link to be focusable even when it has been disabled. |
| children | `Children` | | |

69
thaw/src/link/link.css Normal file
View file

@ -0,0 +1,69 @@
.thaw-link {
display: inline;
background-color: transparent;
color: var(--colorBrandForegroundLink);
font-size: inherit;
font-weight: var(--fontWeightRegular);
font-family: var(--fontFamilyBase);
text-align: left;
overflow: inherit;
padding: 0px;
margin: 0px;
user-select: text;
text-overflow: inherit;
text-decoration-thickness: var(--strokeWidthThin);
text-decoration-line: none;
box-sizing: border-box;
cursor: pointer;
}
.thaw-link--disabled {
color: var(--colorNeutralForegroundDisabled);
}
button.thaw-link {
border-style: none;
font-size: var(--fontSizeBase300);
}
span.thaw-link,
.thaw-link--inline {
text-decoration-line: underline;
}
.thaw-link:hover {
color: var(--colorBrandForegroundLinkHover);
text-decoration-line: underline;
}
.thaw-link--disabled:hover {
color: var(--colorNeutralForegroundDisabled);
}
.thaw-link--disabled:not(span):hover {
text-decoration-line: none;
}
.thaw-link:active {
color: var(--colorBrandForegroundLinkPressed);
text-decoration-line: underline;
}
.thaw-link--disabled:active {
color: var(--colorNeutralForegroundDisabled);
}
.thaw-link--disabled:not(span):active {
text-decoration-line: none;
}
.thaw-link:focus-visible {
outline-style: none;
}
.thaw-link:not(.thaw-link--disabled):focus-visible,
.thaw-link--disabled-focusable:focus-visible {
text-decoration-style: double;
text-decoration-line: underline;
text-decoration-color: var(--colorStrokeFocus2);
}

70
thaw/src/link/link.rs Normal file
View file

@ -0,0 +1,70 @@
use leptos::{either::EitherOf3, prelude::*};
use thaw_utils::{class_list, mount_style};
#[component]
pub fn Link(
#[prop(optional, into)] class: MaybeProp<String>,
#[prop(optional)] span: bool,
/// If true, changes styling when the link is being used alongside other text content.
#[prop(optional, into)]
inline: MaybeSignal<bool>,
#[prop(optional, into)] href: Option<MaybeSignal<String>>,
/// Whether the link is disabled.
#[prop(optional, into)]
disabled: MaybeSignal<bool>,
/// When set, allows the link to be focusable even when it has been disabled.
#[prop(optional, into)]
disabled_focusable: MaybeSignal<bool>,
children: Children,
) -> impl IntoView {
mount_style("link", include_str!("./link.css"));
let link_disabled = Memo::new(move |_| disabled.get() || disabled_focusable.get());
let class = class_list![
"thaw-link",
("thaw-link--inline", move || inline.get()),
("thaw-link--disabled", move || link_disabled.get()),
("thaw-link--disabled-focusable", move || link_disabled.get()),
class
];
let tabindex = Memo::new(move |_| {
if disabled_focusable.get() {
Some("0")
} else if disabled.get() {
Some("-1")
} else {
None
}
});
if let Some(href) = href {
EitherOf3::A(view! {
<a
role="link"
class=class
href=href
tabindex=tabindex
aria-disabled=move || link_disabled.get().then_some("true")
>
{children()}
</a>
})
} else if span {
EitherOf3::B(view! {
<span class=class>
{children()}
</span>
})
} else {
EitherOf3::C(view! {
<button
class=class
disabled=move || disabled.get().then_some("")
aria-disabled=move || link_disabled.get().then_some("true")
>
{children()}
</button>
})
}
}

3
thaw/src/link/mod.rs Normal file
View file

@ -0,0 +1,3 @@
mod link;
pub use link::*;

View file

@ -68,6 +68,9 @@ pub struct ColorTheme {
pub color_brand_stroke_1: String,
pub color_brand_stroke_2: String,
pub color_brand_stroke_2_contrast: String,
pub color_brand_foreground_link: String,
pub color_brand_foreground_link_hover: String,
pub color_brand_foreground_link_pressed: String,
pub color_stroke_focus_2: String,
@ -188,6 +191,9 @@ impl ColorTheme {
color_brand_stroke_1: "#0f6cbd".into(),
color_brand_stroke_2: "#b4d6fa".into(),
color_brand_stroke_2_contrast: "#b4d6fa".into(),
color_brand_foreground_link: "#115ea3".into(),
color_brand_foreground_link_hover: "#0f548c".into(),
color_brand_foreground_link_pressed: "#0c3b5e".into(),
color_stroke_focus_2: "#000000".into(),
@ -308,6 +314,9 @@ impl ColorTheme {
color_brand_stroke_1: "#479ef5".into(),
color_brand_stroke_2: "#0e4775".into(),
color_brand_stroke_2_contrast: "#0e4775".into(),
color_brand_foreground_link: "#479ef5".into(),
color_brand_foreground_link_hover: "#62abf5".into(),
color_brand_foreground_link_pressed: "#2886de".into(),
color_stroke_focus_2: "#ffffff".into(),