mirror of
https://github.com/adoyle0/thaw.git
synced 2025-01-22 22:09:22 -05:00
feat: adds Link component
This commit is contained in:
parent
7b29f7da37
commit
5879a2df86
10 changed files with 244 additions and 6 deletions
|
@ -86,13 +86,14 @@ fn TheRouter() -> impl IntoView {
|
||||||
<Route path=path!("/image") view=ImageMdPage/>
|
<Route path=path!("/image") view=ImageMdPage/>
|
||||||
<Route path=path!("/input") view=InputMdPage/>
|
<Route path=path!("/input") view=InputMdPage/>
|
||||||
<Route path=path!("/layout") view=LayoutMdPage/>
|
<Route path=path!("/layout") view=LayoutMdPage/>
|
||||||
|
<Route path=path!("/link") view=LinkMdPage/>
|
||||||
<Route path=path!("/loading-bar") view=LoadingBarMdPage/>
|
<Route path=path!("/loading-bar") view=LoadingBarMdPage/>
|
||||||
<Route path=path!("/message-bar") view=MessageBarMdPage/>
|
<Route path=path!("/message-bar") view=MessageBarMdPage/>
|
||||||
<Route path=path!("/nav") view=NavMdPage/>
|
<Route path=path!("/nav") view=NavMdPage/>
|
||||||
<Route path=path!("/pagination") view=PaginationMdPage/>
|
|
||||||
<Route path=path!("/popover") view=PopoverMdPage/>
|
|
||||||
}.into_inner()}
|
}.into_inner()}
|
||||||
{view!{
|
{view!{
|
||||||
|
<Route path=path!("/pagination") view=PaginationMdPage/>
|
||||||
|
<Route path=path!("/popover") view=PopoverMdPage/>
|
||||||
<Route path=path!("/progress-bar") view=ProgressBarMdPage/>
|
<Route path=path!("/progress-bar") view=ProgressBarMdPage/>
|
||||||
<Route path=path!("/radio") view=RadioMdPage/>
|
<Route path=path!("/radio") view=RadioMdPage/>
|
||||||
<Route path=path!("/scrollbar") view=ScrollbarMdPage/>
|
<Route path=path!("/scrollbar") view=ScrollbarMdPage/>
|
||||||
|
@ -107,10 +108,10 @@ fn TheRouter() -> impl IntoView {
|
||||||
<Route path=path!("/tag") view=TagMdPage/>
|
<Route path=path!("/tag") view=TagMdPage/>
|
||||||
<Route path=path!("/text") view=TextMdPage/>
|
<Route path=path!("/text") view=TextMdPage/>
|
||||||
<Route path=path!("/textarea") view=TextareaMdPage/>
|
<Route path=path!("/textarea") view=TextareaMdPage/>
|
||||||
<Route path=path!("/time-picker") view=TimePickerMdPage/>
|
|
||||||
<Route path=path!("/toast") view=ToastMdPage />
|
|
||||||
}.into_inner()}
|
}.into_inner()}
|
||||||
{view!{
|
{view!{
|
||||||
|
<Route path=path!("/time-picker") view=TimePickerMdPage/>
|
||||||
|
<Route path=path!("/toast") view=ToastMdPage />
|
||||||
<Route path=path!("/tooltip") view=TooltipMdPage />
|
<Route path=path!("/tooltip") view=TooltipMdPage />
|
||||||
<Route path=path!("/upload") view=UploadMdPage/>
|
<Route path=path!("/upload") view=UploadMdPage/>
|
||||||
}.into_inner()}
|
}.into_inner()}
|
||||||
|
|
|
@ -220,6 +220,10 @@ pub(crate) fn gen_nav_data() -> Vec<NavGroupOption> {
|
||||||
value: "/components/layout",
|
value: "/components/layout",
|
||||||
label: "Layout",
|
label: "Layout",
|
||||||
},
|
},
|
||||||
|
NavItemOption {
|
||||||
|
value: "/components/link",
|
||||||
|
label: "Link",
|
||||||
|
},
|
||||||
NavItemOption {
|
NavItemOption {
|
||||||
value: "/components/loading-bar",
|
value: "/components/loading-bar",
|
||||||
label: "Loading Bar",
|
label: "Loading Bar",
|
||||||
|
|
|
@ -47,6 +47,7 @@ pub fn include_md(_token_stream: proc_macro::TokenStream) -> proc_macro::TokenSt
|
||||||
"ImageMdPage" => "../../thaw/src/image/docs/mod.md",
|
"ImageMdPage" => "../../thaw/src/image/docs/mod.md",
|
||||||
"InputMdPage" => "../../thaw/src/input/docs/mod.md",
|
"InputMdPage" => "../../thaw/src/input/docs/mod.md",
|
||||||
"LayoutMdPage" => "../../thaw/src/layout/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",
|
"LoadingBarMdPage" => "../../thaw/src/loading_bar/docs/mod.md",
|
||||||
"MenuMdPage" => "../../thaw/src/menu/docs/mod.md",
|
"MenuMdPage" => "../../thaw/src/menu/docs/mod.md",
|
||||||
"MessageBarMdPage" => "../../thaw/src/message_bar/docs/mod.md",
|
"MessageBarMdPage" => "../../thaw/src/message_bar/docs/mod.md",
|
||||||
|
|
|
@ -160,9 +160,9 @@ fn iter_nodes<'a>(
|
||||||
let NodeLink { url, title } = node_link;
|
let NodeLink { url, title } = node_link;
|
||||||
|
|
||||||
quote!(
|
quote!(
|
||||||
<a href=#url title=#title>
|
<Link href=#url attr:title=#title>
|
||||||
#(#children)*
|
#(#children)*
|
||||||
</a>
|
</Link>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
NodeValue::Image(_) => quote!("Image todo!!!"),
|
NodeValue::Image(_) => quote!("Image todo!!!"),
|
||||||
|
|
|
@ -24,6 +24,7 @@ mod icon;
|
||||||
mod image;
|
mod image;
|
||||||
mod input;
|
mod input;
|
||||||
mod layout;
|
mod layout;
|
||||||
|
mod link;
|
||||||
mod loading_bar;
|
mod loading_bar;
|
||||||
mod menu;
|
mod menu;
|
||||||
mod message_bar;
|
mod message_bar;
|
||||||
|
@ -75,6 +76,7 @@ pub use icon::*;
|
||||||
pub use image::*;
|
pub use image::*;
|
||||||
pub use input::*;
|
pub use input::*;
|
||||||
pub use layout::*;
|
pub use layout::*;
|
||||||
|
pub use link::*;
|
||||||
pub use loading_bar::*;
|
pub use loading_bar::*;
|
||||||
pub use menu::*;
|
pub use menu::*;
|
||||||
pub use message_bar::*;
|
pub use message_bar::*;
|
||||||
|
|
79
thaw/src/link/docs/mod.md
Normal file
79
thaw/src/link/docs/mod.md
Normal 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
69
thaw/src/link/link.css
Normal 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
70
thaw/src/link/link.rs
Normal 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
3
thaw/src/link/mod.rs
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
mod link;
|
||||||
|
|
||||||
|
pub use link::*;
|
|
@ -68,6 +68,9 @@ pub struct ColorTheme {
|
||||||
pub color_brand_stroke_1: String,
|
pub color_brand_stroke_1: String,
|
||||||
pub color_brand_stroke_2: String,
|
pub color_brand_stroke_2: String,
|
||||||
pub color_brand_stroke_2_contrast: 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,
|
pub color_stroke_focus_2: String,
|
||||||
|
|
||||||
|
@ -188,6 +191,9 @@ impl ColorTheme {
|
||||||
color_brand_stroke_1: "#0f6cbd".into(),
|
color_brand_stroke_1: "#0f6cbd".into(),
|
||||||
color_brand_stroke_2: "#b4d6fa".into(),
|
color_brand_stroke_2: "#b4d6fa".into(),
|
||||||
color_brand_stroke_2_contrast: "#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(),
|
color_stroke_focus_2: "#000000".into(),
|
||||||
|
|
||||||
|
@ -308,6 +314,9 @@ impl ColorTheme {
|
||||||
color_brand_stroke_1: "#479ef5".into(),
|
color_brand_stroke_1: "#479ef5".into(),
|
||||||
color_brand_stroke_2: "#0e4775".into(),
|
color_brand_stroke_2: "#0e4775".into(),
|
||||||
color_brand_stroke_2_contrast: "#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(),
|
color_stroke_focus_2: "#ffffff".into(),
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue