Skip to content

Commit

Permalink
test(examples): added full page layout demo
Browse files Browse the repository at this point in the history
  • Loading branch information
arctic-hen7 committed Aug 27, 2022
1 parent 41590b1 commit fb00daf
Show file tree
Hide file tree
Showing 12 changed files with 232 additions and 0 deletions.
File renamed without changes.
3 changes: 3 additions & 0 deletions examples/demos/full_page_layout/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
dist/
target_engine/
target_wasm/
22 changes: 22 additions & 0 deletions examples/demos/full_page_layout/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
[package]
name = "perseus-example-full-page-layout"
version = "0.4.0-beta.7"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
perseus = { path = "../../../packages/perseus", features = [ "hydrate" ] }
sycamore = "=0.8.0-beta.7"
serde = { version = "1", features = ["derive"] }
serde_json = "1"

[target.'cfg(not(target_arch = "wasm32"))'.dev-dependencies]
fantoccini = "0.17"

[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
tokio = { version = "1", features = [ "macros", "rt", "rt-multi-thread" ] }
# This is an internal convenience crate that exposes all integrations through features for testing
perseus-integration = { path = "../../../packages/perseus-integration", default-features = false }

[target.'cfg(target_arch = "wasm32")'.dependencies]
7 changes: 7 additions & 0 deletions examples/demos/full_page_layout/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Full Page Layout Example

Perseus currently has some UI quirks, which can make building full-page layouts (i.e. those with headers and footers) a little difficult. This example uses a simple stylesheet to make an app with a sticky header and footer, that can support content of any height, using CSS Grid for flexibility and convenience.

*Note: the UI quirks that make this a little tricky will be resolved by the time v0.4.0 becomes stable.*

**Warning:** there is currently a strange page transition bug when going between the index and long pages...
28 changes: 28 additions & 0 deletions examples/demos/full_page_layout/src/components/layout.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
use sycamore::prelude::*;

// NOTE: None of the code in this file is Perseus-specific! This could easily be
// applied to any Sycamore app.

#[component]
pub fn Layout<G: Html>(cx: Scope, props: LayoutProps<G>) -> View<G> {
view! { cx,
// These elements are styled with bright colors for demonstration purposes
header(style = "background-color: red; color: white; padding: 1rem") {
p { (props.title) }
}
main(style = "padding: 1rem") {
(props.children)
}
footer(style = "background-color: black; color: white; padding: 1rem") {
p { "Hey there, I'm a footer!" }
}
}
}

#[derive(Prop)]
pub struct LayoutProps<G: Html> {
/// The title of the page, which will be displayed in the header.
pub title: String,
/// The content to put inside the layout.
pub children: View<G>,
}
1 change: 1 addition & 0 deletions examples/demos/full_page_layout/src/components/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub mod layout;
32 changes: 32 additions & 0 deletions examples/demos/full_page_layout/src/error_pages.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
use perseus::{ErrorPages, Html};
use sycamore::view;

pub fn get_error_pages<G: Html>() -> ErrorPages<G> {
let mut error_pages = ErrorPages::new(
|cx, url, status, err, _| {
view! { cx,
p { (format!("An error with HTTP code {} occurred at '{}': '{}'.", status, url, err)) }
}
},
|cx, _, _, _, _| {
view! { cx,
title { "Error" }
}
},
);
error_pages.add_page(
404,
|cx, _, _, _, _| {
view! { cx,
p { "Page not found." }
}
},
|cx, _, _, _, _| {
view! { cx,
title { "Not Found" }
}
},
);

error_pages
}
30 changes: 30 additions & 0 deletions examples/demos/full_page_layout/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
mod components;
mod error_pages;
mod templates;

use perseus::{Html, PerseusApp, PerseusRoot};
use sycamore::prelude::view;

#[perseus::main(perseus_integration::dflt_server)]
pub fn main<G: Html>() -> PerseusApp<G> {
PerseusApp::new()
.template(crate::templates::index::get_template)
.template(crate::templates::long::get_template)
.error_pages(crate::error_pages::get_error_pages)
.index_view(|cx| {
view! { cx,
html {
head {
meta(charset = "UTF-8")
meta(name = "viewport", content = "width=device-width, initial-scale=1.0")
// Perseus automatically resolves `/.perseus/static/` URLs to the contents of the `static/` directory at the project root
link(rel = "stylesheet", href = ".perseus/static/style.css")
}
body {
// Quirk: this creates a wrapper `<div>` around the root `<div>` by necessity
PerseusRoot()
}
}
}
})
}
29 changes: 29 additions & 0 deletions examples/demos/full_page_layout/src/templates/index.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
use crate::components::layout::Layout;
use perseus::Template;
use sycamore::prelude::{view, Html, Scope, SsrNode, View};

#[perseus::template_rx]
pub fn index_page<G: Html>(cx: Scope) -> View<G> {
view! { cx,
Layout {
title: "Index".to_string(),
children: view! { cx,
// Anything we put in here will be rendered inside the `<main>` block of the layout
p { "Hello World!" }
br {}
a(href = "long") { "Long page" }
}
}
}
}

#[perseus::head]
pub fn head(cx: Scope) -> View<SsrNode> {
view! { cx,
title { "Index Page" }
}
}

pub fn get_template<G: Html>() -> Template<G> {
Template::new("index").template(index_page).head(head)
}
30 changes: 30 additions & 0 deletions examples/demos/full_page_layout/src/templates/long.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
use crate::components::layout::Layout;
use perseus::Template;
use sycamore::prelude::{view, Html, Scope, SsrNode, View};

#[perseus::template_rx]
pub fn long_page<G: Html>(cx: Scope) -> View<G> {
view! { cx,
Layout {
title: "Long".to_string(),
children: view! { cx,
a(href = "") { "Index" }
br {}
p {
("This is a test. ".repeat(5000))
}
}
}
}
}

#[perseus::head]
pub fn head(cx: Scope) -> View<SsrNode> {
view! { cx,
title { "Long Page" }
}
}

pub fn get_template<G: Html>() -> Template<G> {
Template::new("long").template(long_page).head(head)
}
2 changes: 2 additions & 0 deletions examples/demos/full_page_layout/src/templates/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
pub mod index;
pub mod long;
48 changes: 48 additions & 0 deletions examples/demos/full_page_layout/static/style.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/* This removes the margins inserted by default around pages */
* {
margin: 0;
}

/* This makes all the elements that wrap our code take up the whole page, so that we can put things at the bottom.
* Without this, the footer would be just beneath the content if the content doesn't fill the whole page (try disabling this).
*
* Quirk: we have to deal with the wrapper around `#root` created by `PerseusRoot` as well as the wrapper inside it (both will be gone by v0.4.0 stabilization)
*/
html, body, body > div, #root, #root > div {
height: 100%;
}
/* This makes the `<div>` that wraps our whole app use CSS Grid to display three sections: the header, content, and footer.
* Quirk: soon, this will just be `#root`
*/
#root > div {
display: grid;
grid-template-columns: 1fr;
/* The header will be automatically sized, the footer will be as small as possible, and the content will take up the rest of the space in the middle */
grid-template-rows: auto 1fr min-content;
grid-template-areas:
'header'
'main'
'footer';
}
header {
/* Put this in the right place in the grid */
grid-area: header;
/* Make this float over the content so it persists as we scroll */
position: fixed;
top: 0;
z-index: 99;
/* Make this span the whole page */
width: 100%;
}
main {
/* Put this in the right place in the grid */
grid-area: main;
/* The header is positioned 'floating' over the content, so we have to make sure this doesn't go behind the header, or it would be invisible.
* You may need to adjust this based on screen size, depending on how the header expands.
*/
margin-top: 5rem;
}
footer {
/* Put this in the right place in the grid */
grid-area: footer;
}

0 comments on commit fb00daf

Please sign in to comment.