Rough out multi-pane layout
- Introduce nested routing for series. - Rough out add and view routes. - Add buttons to access new routes.
This commit is contained in:
parent
c7e4983e46
commit
ddb06d2993
6 changed files with 172 additions and 99 deletions
99
src/app.rs
99
src/app.rs
|
@ -1,99 +0,0 @@
|
|||
use crate::error_template::{AppError, ErrorTemplate};
|
||||
use leptos::*;
|
||||
use leptos_meta::*;
|
||||
use leptos_router::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
#[cfg(feature = "ssr")]
|
||||
use sqlx::FromRow;
|
||||
use uuid::Uuid;
|
||||
|
||||
#[component]
|
||||
pub fn App() -> impl IntoView {
|
||||
// Provides context that manages stylesheets, titles, meta tags, etc.
|
||||
provide_meta_context();
|
||||
|
||||
view! {
|
||||
|
||||
|
||||
// injects a stylesheet into the document <head>
|
||||
// id=leptos means cargo-leptos will hot-reload this stylesheet
|
||||
<Stylesheet id="leptos" href="/pkg/watch.css"/>
|
||||
<Link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css"
|
||||
rel="stylesheet"
|
||||
integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH"
|
||||
crossorigin="anonymous"
|
||||
/>
|
||||
|
||||
// sets the document title
|
||||
<Title text="Watch"/>
|
||||
|
||||
// content for this welcome page
|
||||
<Router fallback=|| {
|
||||
let mut outside_errors = Errors::default();
|
||||
outside_errors.insert_with_default_key(AppError::NotFound);
|
||||
view! {
|
||||
<ErrorTemplate outside_errors/>
|
||||
}
|
||||
.into_view()
|
||||
}>
|
||||
<main class="container">
|
||||
<Routes>
|
||||
<Route path="" view=HomePage/>
|
||||
</Routes>
|
||||
</main>
|
||||
</Router>
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[cfg_attr(feature = "ssr", derive(FromRow))]
|
||||
struct Series {
|
||||
id: Uuid,
|
||||
name: String,
|
||||
}
|
||||
|
||||
#[server]
|
||||
pub async fn get_all() -> Result<Vec<String>, ServerFnError> {
|
||||
use sqlx::{Pool, Postgres};
|
||||
use tokio_stream::StreamExt;
|
||||
|
||||
let pool: Pool<Postgres> = expect_context();
|
||||
|
||||
let mut r = sqlx::query_as::<_, Series>("select * from series;").fetch(&pool);
|
||||
|
||||
let mut found = Vec::new();
|
||||
while let Some(series) = r.try_next().await? {
|
||||
found.push(series.name);
|
||||
}
|
||||
|
||||
Ok(found)
|
||||
}
|
||||
|
||||
/// Renders the home page of your application.
|
||||
#[component]
|
||||
fn HomePage() -> impl IntoView {
|
||||
// Creates a reactive value to update the button
|
||||
let load = create_resource(|| (), |_| async move { get_all().await });
|
||||
|
||||
view! {
|
||||
<h1>"What We're Watching"</h1>
|
||||
<div class="card">
|
||||
<Suspense fallback=|| view!{ <div>"Loading..."</div> }>
|
||||
<ul>
|
||||
{load().map(format_series)}
|
||||
</ul>
|
||||
</Suspense>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
||||
fn format_series(data: Result<Vec<String>, ServerFnError>) -> Vec<impl IntoView> {
|
||||
data.unwrap_or_default()
|
||||
.into_iter()
|
||||
.map(|d| {
|
||||
view! {
|
||||
<li>{d}</li>
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
}
|
18
src/app/home.rs
Normal file
18
src/app/home.rs
Normal file
|
@ -0,0 +1,18 @@
|
|||
use super::series::SeriesList;
|
||||
use leptos::*;
|
||||
use leptos_router::*;
|
||||
|
||||
#[component]
|
||||
pub fn HomePage() -> impl IntoView {
|
||||
view! {
|
||||
<h1 class="mt-3 mb-5">"What We're Watching"</h1>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<SeriesList />
|
||||
</div>
|
||||
<div class="col">
|
||||
<Outlet />
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
}
|
53
src/app/mod.rs
Normal file
53
src/app/mod.rs
Normal file
|
@ -0,0 +1,53 @@
|
|||
use self::{
|
||||
home::HomePage,
|
||||
series::{add::AddSeries, view::ViewSeries},
|
||||
};
|
||||
use crate::error_template::{AppError, ErrorTemplate};
|
||||
use leptos::*;
|
||||
use leptos_meta::*;
|
||||
use leptos_router::*;
|
||||
|
||||
mod home;
|
||||
mod series;
|
||||
|
||||
#[component]
|
||||
pub fn App() -> impl IntoView {
|
||||
// Provides context that manages stylesheets, titles, meta tags, etc.
|
||||
provide_meta_context();
|
||||
|
||||
view! {
|
||||
|
||||
|
||||
// injects a stylesheet into the document <head>
|
||||
// id=leptos means cargo-leptos will hot-reload this stylesheet
|
||||
<Stylesheet id="leptos" href="/pkg/watch.css"/>
|
||||
<Link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css"
|
||||
rel="stylesheet"
|
||||
integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH"
|
||||
crossorigin="anonymous"
|
||||
/>
|
||||
|
||||
// sets the document title
|
||||
<Title text="Watch"/>
|
||||
|
||||
// content for this welcome page
|
||||
<Router fallback=|| {
|
||||
let mut outside_errors = Errors::default();
|
||||
outside_errors.insert_with_default_key(AppError::NotFound);
|
||||
view! {
|
||||
<ErrorTemplate outside_errors/>
|
||||
}
|
||||
.into_view()
|
||||
}>
|
||||
<main class="container">
|
||||
<Routes>
|
||||
<Route path="" view=HomePage>
|
||||
<Route path="add" view=AddSeries />
|
||||
<Route path="view/:id" view=ViewSeries />
|
||||
<Route path="" view=|| () />
|
||||
</Route>
|
||||
</Routes>
|
||||
</main>
|
||||
</Router>
|
||||
}
|
||||
}
|
15
src/app/series/add.rs
Normal file
15
src/app/series/add.rs
Normal file
|
@ -0,0 +1,15 @@
|
|||
use leptos::*;
|
||||
|
||||
#[component]
|
||||
pub fn AddSeries() -> impl IntoView {
|
||||
view! {
|
||||
<div class="card p-3">
|
||||
<div class="card-heading">
|
||||
<h2>Add Series</h2>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
To Do
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
}
|
71
src/app/series/mod.rs
Normal file
71
src/app/series/mod.rs
Normal file
|
@ -0,0 +1,71 @@
|
|||
use leptos::*;
|
||||
use leptos_router::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
#[cfg(feature = "ssr")]
|
||||
use sqlx::FromRow;
|
||||
use uuid::Uuid;
|
||||
|
||||
pub mod add;
|
||||
pub mod view;
|
||||
|
||||
#[component]
|
||||
pub fn SeriesList() -> impl IntoView {
|
||||
let load = create_resource(|| (), |_| async move { get_all().await });
|
||||
view! {
|
||||
<Suspense fallback=|| view!{ <div>"Loading..."</div> }>
|
||||
<ul class="list-group mb-3">
|
||||
{load().map(format_series)}
|
||||
</ul>
|
||||
</Suspense>
|
||||
<div>
|
||||
<A href="add"
|
||||
attr:class="btn btn-primary"
|
||||
>
|
||||
Add Series
|
||||
</A>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
||||
fn format_series(data: Result<Vec<Series>, ServerFnError>) -> impl IntoView {
|
||||
data.unwrap_or_default()
|
||||
.into_iter()
|
||||
.map(|d| {
|
||||
view! {
|
||||
<li class="list-group-item">
|
||||
<A href=format!("view/{}", d.id)
|
||||
attr:class="btn btn-sm btn-secondary"
|
||||
attr:style="float: right"
|
||||
>
|
||||
View Series
|
||||
</A>
|
||||
{d.name}
|
||||
</li>
|
||||
}
|
||||
})
|
||||
.collect_view()
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[cfg_attr(feature = "ssr", derive(FromRow))]
|
||||
pub struct Series {
|
||||
id: Uuid,
|
||||
name: String,
|
||||
}
|
||||
|
||||
#[server]
|
||||
pub async fn get_all() -> Result<Vec<Series>, ServerFnError> {
|
||||
use sqlx::{Pool, Postgres};
|
||||
use tokio_stream::StreamExt;
|
||||
|
||||
let pool: Pool<Postgres> = expect_context();
|
||||
|
||||
let mut r = sqlx::query_as::<_, Series>("select * from series;").fetch(&pool);
|
||||
|
||||
let mut found = Vec::new();
|
||||
while let Some(series) = r.try_next().await? {
|
||||
found.push(series);
|
||||
}
|
||||
|
||||
Ok(found)
|
||||
}
|
15
src/app/series/view.rs
Normal file
15
src/app/series/view.rs
Normal file
|
@ -0,0 +1,15 @@
|
|||
use leptos::*;
|
||||
|
||||
#[component]
|
||||
pub fn ViewSeries() -> impl IntoView {
|
||||
view! {
|
||||
<div class="card p-3">
|
||||
<div class="card-heading">
|
||||
<h2>View Series</h2>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
View Series
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue