diff --git a/examples/ssr_modes_axum/src/app.rs b/examples/ssr_modes_axum/src/app.rs
index 33faa0d57..be343bb6f 100644
--- a/examples/ssr_modes_axum/src/app.rs
+++ b/examples/ssr_modes_axum/src/app.rs
@@ -1,17 +1,9 @@
-use lazy_static::lazy_static;
use leptos::prelude::*;
-use leptos_meta::MetaTags;
-use leptos_meta::*;
+use leptos_meta::{provide_meta_context, MetaTags, Stylesheet, Title};
use leptos_router::{
- components::{FlatRoutes, ProtectedRoute, Route, Router},
- hooks::use_params,
- params::Params,
- ParamSegment, SsrMode, StaticSegment,
+ components::{ProtectedParentRoute, Route, Router, Routes, A},
+ StaticSegment,
};
-use serde::{Deserialize, Serialize};
-#[cfg(feature = "ssr")]
-use std::sync::atomic::{AtomicBool, Ordering};
-use thiserror::Error;
pub fn shell(options: LeptosOptions) -> impl IntoView {
view! {
@@ -31,90 +23,34 @@ pub fn shell(options: LeptosOptions) -> impl IntoView {
}
}
-#[cfg(feature = "ssr")]
-static IS_ADMIN: AtomicBool = AtomicBool::new(true);
-
-#[server]
-pub async fn is_admin() -> Result {
- Ok(IS_ADMIN.load(Ordering::Relaxed))
-}
-
-#[server]
-pub async fn set_is_admin(is_admin: bool) -> Result<(), ServerFnError> {
- IS_ADMIN.store(is_admin, Ordering::Relaxed);
- Ok(())
-}
-
#[component]
pub fn App() -> impl IntoView {
- // Provides context that manages stylesheets, titles, meta tags, etc.
provide_meta_context();
- let fallback = || view! { "Page not found." }.into_view();
- let toggle_admin = ServerAction::::new();
- let is_admin =
- Resource::new(move || toggle_admin.version().get(), |_| is_admin());
+
+ let x = untrack(|| "foo");
view! {
-
-
-
- "Home"
- "Admin"
-
-
-
-
-
- {move || {
- if is_admin.get().and_then(Result::ok).unwrap_or_default() {
- "Log Out"
- } else {
- "Log In"
- }
- }}
-
-
-
-
+ "Home"
+ " | "
+ "Dashboard"
+ " | "
+ "Profile"
-
- // We’ll load the home page with out-of-order streaming and
+
-
- // We'll load the posts with async rendering, so they can set
- // the title and metadata *after* loading the data
-
-
-
-
-
+ "Protected Content" }
+ condition=move || Some(false)
+ redirect_path=|| "/".to_string()
+ >
+
+
+
+
}
@@ -122,209 +58,24 @@ pub fn App() -> impl IntoView {
#[component]
fn HomePage() -> impl IntoView {
- // load the posts
- let posts = Resource::new(|| (), |_| list_post_metadata());
- let posts = move || {
- posts
- .get()
- .map(|n| n.unwrap_or_default())
- .unwrap_or_default()
- };
-
- let posts2 = Resource::new(|| (), |_| list_post_metadata());
- let posts2 = Resource::new(
- || (),
- move |_| async move { posts2.await.as_ref().map(Vec::len).unwrap_or(0) },
- );
-
view! {
- "My Great Blog"
- "Loading posts..."
}>
- "number of posts: " {Suspend::new(async move { posts2.await })}
-
- "Loading posts..." }>
-
-
- }
-}
-
-#[derive(Params, Copy, Clone, Debug, PartialEq, Eq)]
-pub struct PostParams {
- id: Option,
-}
-
-#[component]
-fn Post() -> impl IntoView {
- let query = use_params::();
- let id = move || {
- query.with(|q| {
- q.as_ref()
- .map(|q| q.id.unwrap_or_default())
- .map_err(|_| PostError::InvalidId)
- })
- };
- let post_resource = Resource::new_blocking(id, |id| async move {
- match id {
- Err(e) => Err(e),
- Ok(id) => get_post(id)
- .await
- .map(|data| data.ok_or(PostError::PostNotFound))
- .map_err(|_| PostError::ServerError),
- }
- });
- let comments_resource = Resource::new(id, |id| async move {
- match id {
- Err(e) => Err(e),
- Ok(id) => {
- get_comments(id).await.map_err(|_| PostError::ServerError)
- }
- }
- });
-
- let post_view = Suspend::new(async move {
- match post_resource.await {
- Ok(Ok(post)) => {
- Ok(view! {
- {post.title.clone()}
- {post.content.clone()}
-
- // since we're using async rendering for this page,
- // this metadata should be included in the actual HTML
- // when it's first served
-
-
- })
- }
- _ => Err(PostError::ServerError),
- }
- });
- let comments_view = Suspend::new(async move {
- match comments_resource.await {
- Ok(comments) => Ok(view! {
- "Comments"
-
- {comments
- .into_iter()
- .map(|comment| view! { {comment} })
- .collect_view()}
-
-
- }),
- _ => Err(PostError::ServerError),
- }
- });
-
- view! {
- "The world's best content."
- "Loading post..." }>
-
- "Something went wrong."
-
- {move || {
- errors
- .get()
- .into_iter()
- .map(|(_, error)| view! { {error.to_string()} })
- .collect::>()
- }}
-
-
-
- }
- }>{post_view}
-
- "Loading comments..." }>{comments_view}
+ "Welcome to the Home Page"
+ "This page is accessible to everyone."
}
}
#[component]
-pub fn Admin() -> impl IntoView {
- view! { "You can only see this page if you're logged in."
}
+fn DashboardPage() -> impl IntoView {
+ view! {
+ "Dashboard"
+ "This is a protected page. You should only see this if you're authenticated."
+ }
}
-// Dummy API
-lazy_static! {
- static ref POSTS: Vec = vec![
- Post {
- id: 0,
- title: "My first post".to_string(),
- content: "This is my first post".to_string(),
- },
- Post {
- id: 1,
- title: "My second post".to_string(),
- content: "This is my second post".to_string(),
- },
- Post {
- id: 2,
- title: "My third post".to_string(),
- content: "This is my third post".to_string(),
- },
- ];
-}
-
-#[derive(Error, Debug, Copy, Clone, PartialEq, Eq, Serialize, Deserialize)]
-pub enum PostError {
- #[error("Invalid post ID.")]
- InvalidId,
- #[error("Post not found.")]
- PostNotFound,
- #[error("Server error.")]
- ServerError,
-}
-
-#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
-pub struct Post {
- id: usize,
- title: String,
- content: String,
-}
-
-#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
-pub struct PostMetadata {
- id: usize,
- title: String,
-}
-
-#[server]
-pub async fn list_post_metadata() -> Result, ServerFnError> {
- tokio::time::sleep(std::time::Duration::from_secs(1)).await;
- Ok(POSTS
- .iter()
- .map(|data| PostMetadata {
- id: data.id,
- title: data.title.clone(),
- })
- .collect())
-}
-
-#[server]
-pub async fn get_post(id: usize) -> Result, ServerFnError> {
- tokio::time::sleep(std::time::Duration::from_secs(1)).await;
- Ok(POSTS.iter().find(|post| post.id == id).cloned())
-}
-
-#[server]
-pub async fn get_comments(id: usize) -> Result, ServerFnError> {
- tokio::time::sleep(std::time::Duration::from_secs(2)).await;
- _ = id;
- Ok(vec!["Some comment".into(), "Some other comment".into()])
+#[component]
+fn ProfilePage() -> impl IntoView {
+ view! {
+ "Profile"
+ "This is another protected page. You should only see this if you're authenticated."
+ }
}
diff --git a/leptos/src/lib.rs b/leptos/src/lib.rs
index 9ff269bb7..7bb7e6bed 100644
--- a/leptos/src/lib.rs
+++ b/leptos/src/lib.rs
@@ -168,7 +168,7 @@ pub mod prelude {
pub use leptos_server::*;
pub use oco_ref::*;
pub use reactive_graph::{
- actions::*, computed::*, effect::*, owner::*, signal::*,
+ actions::*, computed::*, effect::*, owner::*, signal::*, untrack,
wrappers::read::*,
};
pub use server_fn::{self, ServerFnError};
diff --git a/router/src/components.rs b/router/src/components.rs
index 2b198aab2..538efd750 100644
--- a/router/src/components.rs
+++ b/router/src/components.rs
@@ -443,6 +443,7 @@ pub fn Redirect(
) where
P: core::fmt::Display + 'static,
{
+ leptos::logging::log!("running Redirect component");
// TODO resolve relative path
let path = path.to_string();