mirror of
https://github.com/leptos-rs/leptos
synced 2024-11-10 06:44:17 +00:00
feat: Added `<ProtectedRoute/> component to route file (#741)
This commit is contained in:
parent
9ed3390b81
commit
7aa4d9e6db
1 changed files with 86 additions and 38 deletions
|
@ -34,44 +34,7 @@ where
|
|||
F: Fn(Scope) -> E + 'static,
|
||||
P: std::fmt::Display,
|
||||
{
|
||||
fn inner(
|
||||
cx: Scope,
|
||||
children: Option<Children>,
|
||||
path: String,
|
||||
view: Rc<dyn Fn(Scope) -> View>,
|
||||
ssr_mode: SsrMode,
|
||||
) -> RouteDefinition {
|
||||
let children = children
|
||||
.map(|children| {
|
||||
children(cx)
|
||||
.as_children()
|
||||
.iter()
|
||||
.filter_map(|child| {
|
||||
child
|
||||
.as_transparent()
|
||||
.and_then(|t| t.downcast_ref::<RouteDefinition>())
|
||||
})
|
||||
.cloned()
|
||||
.collect::<Vec<_>>()
|
||||
})
|
||||
.unwrap_or_default();
|
||||
|
||||
let id = ROUTE_ID.with(|id| {
|
||||
let next = id.get() + 1;
|
||||
id.set(next);
|
||||
next
|
||||
});
|
||||
|
||||
RouteDefinition {
|
||||
id,
|
||||
path,
|
||||
children,
|
||||
view,
|
||||
ssr_mode,
|
||||
}
|
||||
}
|
||||
|
||||
inner(
|
||||
define_route(
|
||||
cx,
|
||||
children,
|
||||
path.to_string(),
|
||||
|
@ -80,6 +43,91 @@ where
|
|||
)
|
||||
}
|
||||
|
||||
/// Describes a route that is guarded by a certain condition. This works the same way as
|
||||
/// [`<Route/>`](Route), except that if the `condition` function evaluates to `false`, it
|
||||
/// redirects to `redirect_path` instead of displaying its `view`.
|
||||
#[component(transparent)]
|
||||
pub fn ProtectedRoute<P, E, F, C>(
|
||||
cx: Scope,
|
||||
/// The path fragment that this route should match. This can be static (`users`),
|
||||
/// include a parameter (`:id`) or an optional parameter (`:id?`), or match a
|
||||
/// wildcard (`user/*any`).
|
||||
path: P,
|
||||
/// The path that will be redirected to if the condition is `false`.
|
||||
redirect_path: P,
|
||||
/// Condition function that returns a boolean.
|
||||
condition: C,
|
||||
/// View that will be exposed if the condition is `true`.
|
||||
view: F,
|
||||
/// The mode that this route prefers during server-side rendering. Defaults to out-of-order streaming.
|
||||
#[prop(optional)]
|
||||
ssr: SsrMode,
|
||||
/// `children` may be empty or include nested routes.
|
||||
#[prop(optional)]
|
||||
children: Option<Children>,
|
||||
) -> impl IntoView
|
||||
where
|
||||
E: IntoView,
|
||||
F: Fn(Scope) -> E + 'static,
|
||||
P: std::fmt::Display + 'static,
|
||||
C: Fn(Scope) -> bool + 'static,
|
||||
{
|
||||
use crate::{Redirect, RedirectProps};
|
||||
let redirect_path = redirect_path.to_string();
|
||||
|
||||
define_route(
|
||||
cx,
|
||||
children,
|
||||
path.to_string(),
|
||||
Rc::new(move |cx| {
|
||||
if condition(cx) {
|
||||
view(cx).into_view(cx)
|
||||
} else {
|
||||
view! { cx, <Redirect path=redirect_path.clone()/> }
|
||||
.into_view(cx)
|
||||
}
|
||||
}),
|
||||
ssr,
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn define_route(
|
||||
cx: Scope,
|
||||
children: Option<Children>,
|
||||
path: String,
|
||||
view: Rc<dyn Fn(Scope) -> View>,
|
||||
ssr_mode: SsrMode,
|
||||
) -> RouteDefinition {
|
||||
let children = children
|
||||
.map(|children| {
|
||||
children(cx)
|
||||
.as_children()
|
||||
.iter()
|
||||
.filter_map(|child| {
|
||||
child
|
||||
.as_transparent()
|
||||
.and_then(|t| t.downcast_ref::<RouteDefinition>())
|
||||
})
|
||||
.cloned()
|
||||
.collect::<Vec<_>>()
|
||||
})
|
||||
.unwrap_or_default();
|
||||
|
||||
let id = ROUTE_ID.with(|id| {
|
||||
let next = id.get() + 1;
|
||||
id.set(next);
|
||||
next
|
||||
});
|
||||
|
||||
RouteDefinition {
|
||||
id,
|
||||
path,
|
||||
children,
|
||||
view,
|
||||
ssr_mode,
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoView for RouteDefinition {
|
||||
fn into_view(self, cx: Scope) -> View {
|
||||
Transparent::new(self).into_view(cx)
|
||||
|
|
Loading…
Reference in a new issue