Skip to content

Commit

Permalink
feat: created new website! 🎉 (#181)
Browse files Browse the repository at this point in the history
* feat(website): completely redesigned landing page

This looks *much* better! Nothing on the docs pages yet.

* docs: fixed bad example inclusion

* chore: updated website for v0.4.0-beta.7

This fixes some of the styling bugs we were encountering.

* refactor: made docs header/footer in line with index page

* feat(website): added support for comparison text

Need to fill these in for each comparison still.

* docs: added comparison text for each current comparison

Also made the '100' emoji on the docs page green.

* chore: wip

* fix: fixed full-page layouts

This includes pushing the footer to the bottom of the page.

* fix: fixed docs container and hamburger menu alignment

* perf(website): switched website to `translator-lightweight`

Translations are now stored as JSON, and the bundle size has been
reduced *dramatically*!

* feat: greatly improved docs container

This now has dual-pane scrolling on desktop and a proper footer.

* chore(website): updated to latest beta and new sycamore

* wip: started on website code examples

* wip: further work on website examples

* feat(website): added website examples

They're still quite long though, so I'll create some switchers for 'highlights'.

* feat: added docs search bar

It doesn't do anything yet.

* feat: added excerpts functionality to make code examples on index page more digestable

* fix: removed broken height transition and fixed corners

* fix: fixed example scrolling issues

* feat: added some finishing touches

There's an issue with the footer though...

* chore(deps): updated to latest beta

* feat: finalized new dark mode

* fix: fixed footer issue

It was due to my not updating the styles for the latest beta, which
removed another wrapper `<div>`.

* refactor: rolled back tiny change in last commit

We probably don't need this `min-content`, but I feel slightly safer
with it.

* feat: added proper website 404 page

* ci: made website build 404 page automatically

* fix: fixed syntax highlighting on initial load of landing page

* feat: made search bar use google as backend

Pending indexing properly by DuckDuckGo etc.

* refactor: appeased `clippy`

* feat: made text contrast work

This involved graying the header and making a filter-based light mode
for the syntaxx highlighting (which triggers contrast ratio false-positives).

* feat: added explanatory tooltip to i18n tile

We can't fit the word 'internationalization' on there, so this is the
next best thing.

* chore: temporarily disabled search bar

We need to set up a proper sitemap first so that search engines can
actually index everything.

* chore: set matrix button as disabled

This should be ready for deployment now!

* chore: fixed outdated repo link
  • Loading branch information
arctic-hen7 authored Sep 21, 2022
1 parent 653ca85 commit b7ace94
Show file tree
Hide file tree
Showing 56 changed files with 1,847 additions and 631 deletions.
3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ members = [
"examples/core/*",
"examples/demos/*",
"examples/comprehensive/*",
# "website",
"examples/website/*",
"website",
# We have the CLI subcrates as workspace members so we can actively develop on them
# They also can't be a workspace until nested workspaces are supported
# "examples/core/basic/.perseus",
Expand Down
9 changes: 8 additions & 1 deletion bonnie.toml
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,14 @@ site.cmd = "concurrently \"bonnie site export\" \"bonnie site build-tailwind\""
site.desc = "builds and serves the site for local development (requires `concurrently`)"
site.subcommands.export.cmd = [
"cd website",
"perseus export -sw --cargo-engine-path cargo-clif"
"perseus export -sw --custom-watch ../docs/ --cargo-engine-path cargo-clif"
]
site.subcommands.export.desc = "exports and serves the site, watching for changes"
site.subcommands.check.cmd = [
"cd website",
"perseus check -w --cargo-engine-path cargo-clif"
]
site.subcommands.check.desc = "checks the code of the website"
site.subcommands.tinker.cmd = [
"cd website",
"perseus tinker"
Expand Down Expand Up @@ -91,6 +96,7 @@ site.subcommands.deploy-prod.cmd.generic = [
"PERSEUS_BASE_PATH=http://localhost:8080/perseus perseus tinker",
# Point this live version of the CLI at the given example
"PERSEUS_BASE_PATH=https://framesurge.sh/perseus perseus deploy -e",
"PERSEUS_BASE_PATH=https://framesurge.sh/perseus perseus export-error-page --code 404 --output pkg/404.html",
# Build the Tribble contributing docs
"cd ..",
"tribble deploy --path https://framesurge.sh/perseus/tribble -o tribble",
Expand All @@ -102,6 +108,7 @@ site.subcommands.deploy-prod.cmd.targets.windows = [
"powershell -Command { $env:PERSEUS_BASE_PATH=\"http://localhost:8080/perseus\"; perseus tinker }",
# Point this live version of the CLI at the given example
"powershell -Command { $env:PERSEUS_BASE_PATH=\"https://framesurge.sh/perseus\"; perseus deploy -e }",
"powershell -Command { $env:PERSEUS_BASE_PATH=\"https://framesurge.sh/perseus\"; perseus export-error-page --code 404 --output pkg/404.html } ",
# Build the Tribble contributing docs
"cd ..",
"tribble deploy --path https://framesurge.sh/perseus/tribble -o tribble",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ The only particular thing to note here is that, because this is rendered to a `S
Here's an example of modifying a page's metadata (taken from [here](https://github.com/arctic-hen7/perseus/blob/main/examples/core/basic/src/templates/index.rs)):

```rust
{{#lines_include ../../../../examples/core/basic/src/templates/index.rs:28:33}}
{{#lines_include ../../../../examples/core/basic/src/templates/index.rs:24:29}}
```

## Script Loading
Expand Down
1 change: 1 addition & 0 deletions examples/website/app_in_a_file/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
dist/
18 changes: 18 additions & 0 deletions examples/website/app_in_a_file/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
[package]
name = "perseus-website-example-app-in-a-file"
version = "0.4.0-beta.8"
edition = "2021"

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

[dependencies]
perseus = { path = "../../../packages/perseus" }
sycamore = "^0.8.1"
serde = { version = "1", features = [ "derive" ] }
serde_json = "1"

[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
tokio = { version = "1", features = [ "macros", "rt", "rt-multi-thread" ] }
perseus-warp = { path = "../../../packages/perseus-warp", features = [ "dflt-server" ] }

[target.'cfg(target_arch = "wasm32")'.dependencies]
3 changes: 3 additions & 0 deletions examples/website/app_in_a_file/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Tiny Example

This example shows the smallest possible and meaningful Perseus app, a simple 'Hello World!' app. This is considered a comprehensive example because it doesn't show a particular feature of Perseus, nor does it demonstrate how to do a common task. The structure of this example isn't likely to be used anywhere in the real world (your templates and error pages would nearly always be in separate files), but it shows the absolute basics of Perseus and helps new users to hit the ground running.
58 changes: 58 additions & 0 deletions examples/website/app_in_a_file/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
use perseus::{Html, PerseusApp, RenderFnResultWithCause, Template};
use sycamore::prelude::*;

// Initialize our app with the `perseus_warp` package's default server (fully
// customizable)
#[perseus::main(perseus_warp::dflt_server)]
pub fn main<G: Html>() -> PerseusApp<G> {
PerseusApp::new()
// Create a new template at `index`, which maps to our landing page
.template(|| {
Template::new("index")
.template(index_page)
.build_state_fn(get_index_build_state)
})
.template(|| Template::new("about").template(about_page))
}

// EXCERPT_START
#[perseus::template_rx]
fn index_page<'a, G: Html>(cx: Scope<'a>, props: IndexPropsRx<'a>) -> View<G> {
view! { cx,
h1 { (format!(
"Hello, {}!",
props.name.get()
)) }
input(
placeholder = "Name",
bind:value = props.name
)
a(href = "about") { "About" }
}
}

#[perseus::make_rx(IndexPropsRx)]
struct IndexProps {
name: String,
}

// This function will be run when you build your app, to generate default state
// ahead-of-time
#[perseus::build_state]
async fn get_index_build_state(
_path: String,
_locale: String,
) -> RenderFnResultWithCause<IndexProps> {
let props = IndexProps {
name: "User".to_string(),
};
Ok(props)
}
// EXCERPT_END

#[perseus::template_rx]
fn about_page<G: Html>(cx: Scope) -> View<G> {
view! { cx,
p { "This is an example webapp created with Perseus!" }
}
}
23 changes: 23 additions & 0 deletions examples/website/cli.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# 🚩 Get ready!
> perseus init my-app

# 📦 All static?
> perseus export -sw
[1/3] 📦 Exporting your app's pages...✅
[2/3] 🏗️ Building your app to Wasm...✅
[3/3] 🛰️ Your exported app is now live at <http://127.0.0.1:8080>!

# 📡 Using some more advanced features?
> perseus serve -w
[1/4] 🔨 Generating your app...✅
[2/4] 🏗️ Building your app to Wasm...✅
[3/4] 📡 Building server...✅
[4/4] 🛰️ Your app is now live on <http://127.0.0.1:8080>! To change this, re-run this command with different settings for `--host` and `--port`.

# 🧪 Testing your app's features?
> perseus test
# 🔎 Investigating some errors?
> perseus snoop wasm-build

# 🎉 Ready to send it to the world?
> perseus deploy
7 changes: 7 additions & 0 deletions examples/website/get_started.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
> cargo install perseus-cli
> perseus new my-project
> perseus serve -w

# Ready to deploy?
> perseus deploy
# And send `pkg/` to your server! 🥳
1 change: 1 addition & 0 deletions examples/website/i18n/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
dist/
18 changes: 18 additions & 0 deletions examples/website/i18n/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
[package]
name = "perseus-website-example-i18n"
version = "0.4.0-beta.8"
edition = "2021"

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

[dependencies]
perseus = { path = "../../../packages/perseus" }
sycamore = "^0.8.1"
serde = { version = "1", features = [ "derive" ] }
serde_json = "1"

[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
tokio = { version = "1", features = [ "macros", "rt", "rt-multi-thread" ] }
perseus-warp = { path = "../../../packages/perseus-warp", features = [ "dflt-server" ] }

[target.'cfg(target_arch = "wasm32")'.dependencies]
3 changes: 3 additions & 0 deletions examples/website/i18n/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Tiny Example

This example shows the smallest possible and meaningful Perseus app, a simple 'Hello World!' app. This is considered a comprehensive example because it doesn't show a particular feature of Perseus, nor does it demonstrate how to do a common task. The structure of this example isn't likely to be used anywhere in the real world (your templates and error pages would nearly always be in separate files), but it shows the absolute basics of Perseus and helps new users to hit the ground running.
34 changes: 34 additions & 0 deletions examples/website/i18n/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
use perseus::{t, Html, PerseusApp, Template};
use sycamore::prelude::*;

#[perseus::main(perseus_warp::dflt_server)]
pub fn main<G: Html>() -> PerseusApp<G> {
PerseusApp::new()
.template(|| Template::new("index").template(index_page))
// EXCERPT_START
.locales_and_translations_manager(
"en-US", // Default locale
&["fr-FR", "es-ES"], // Other supported locales
)
// EXCERPT_END
}

// EXCERPT_START
// Our landing page. Going to `/` will cause a redirect to `/en-US`,
// `/es-ES`, or `/fr-FR` based on the user's locale settings in their browser,
// all automatically. If nothing matches, the default locale (`en-US`) will be
// used.
#[perseus::template_rx]
fn index_page<G: Html>(cx: Scope) -> View<G> {
view! { cx,
h1 { (t!("greeting", cx)) }
}
}

// `translations/en-US.ftl`:
// greeting = Hello, world!
// `translations/es-ES.ftl`:
// greeting = ¡Hola, mundo!
// `translations/fr-FR.ftl`:
// greeting = Bonjour, le monde!
// EXCERPT_END
1 change: 1 addition & 0 deletions examples/website/i18n/translations/en-US.ftl
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
greeting = Hello, world!
1 change: 1 addition & 0 deletions examples/website/i18n/translations/es-ES.ftl
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
greeting = ¡Hola, mundo!
1 change: 1 addition & 0 deletions examples/website/i18n/translations/fr-FR.ftl
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
greeting = Bonjour, le monde!
1 change: 1 addition & 0 deletions examples/website/state_generation/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
dist/
18 changes: 18 additions & 0 deletions examples/website/state_generation/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
[package]
name = "perseus-website-example-state-generation"
version = "0.4.0-beta.8"
edition = "2021"

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

[dependencies]
perseus = { path = "../../../packages/perseus" }
sycamore = "^0.8.1"
serde = { version = "1", features = [ "derive" ] }
serde_json = "1"

[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
tokio = { version = "1", features = [ "macros", "rt", "rt-multi-thread" ] }
perseus-warp = { path = "../../../packages/perseus-warp", features = [ "dflt-server" ] }

[target.'cfg(target_arch = "wasm32")'.dependencies]
3 changes: 3 additions & 0 deletions examples/website/state_generation/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Tiny Example

This example shows the smallest possible and meaningful Perseus app, a simple 'Hello World!' app. This is considered a comprehensive example because it doesn't show a particular feature of Perseus, nor does it demonstrate how to do a common task. The structure of this example isn't likely to be used anywhere in the real world (your templates and error pages would nearly always be in separate files), but it shows the absolute basics of Perseus and helps new users to hit the ground running.
75 changes: 75 additions & 0 deletions examples/website/state_generation/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
use perseus::{blame_err, Html, PerseusApp, RenderFnResult, RenderFnResultWithCause, Template};
use std::time::Duration;
use sycamore::prelude::*;

#[perseus::main(perseus_warp::dflt_server)]
pub fn main<G: Html>() -> PerseusApp<G> {
PerseusApp::new().template(|| {
Template::new("post")
.template(post_page)
.build_paths_fn(get_build_paths)
.build_state_fn(get_build_state)
// Reload every blog post every day, in case it's changed
.revalidate_after(Duration::new(60 * 60 * 24, 0))
// If the user requests a page we haven't created yet, still
// pass it to `get_build_state()` and cache the output for
// future users (lazy page building)
.incremental_generation()
})
}

// EXCERPT_START
#[perseus::template_rx]
fn post_page<'a, G: Html>(cx: Scope<'a>, props: PostRx<'a>) -> View<G> {
view! { cx,
h1 { (props.title.get()) }
p { (props.author.get()) }
div(
dangerously_set_inner_html = &props.content.get()
)
}
}
// EXCERPT_END

#[perseus::make_rx(PostRx)]
struct Post {
title: String,
author: String,
content: String,
}

// EXCERPT_START
// This function will be run for each path under `/post/` to generate its state
#[perseus::build_state]
async fn get_build_state(path: String, _locale: String) -> RenderFnResultWithCause<Post> {
let raw_post = match get_post_for_path(path) {
Ok(post) => post,
// If the user sends us some bogus path with incremental generation,
// return a 404 appropriately
Err(err) => blame_err!(client, 404, err),
};
let html_content = parse_markdown(raw_post.content);
let props = Post {
title: raw_post.title,
author: raw_post.author,
content: html_content,
};
Ok(props)
}
async fn get_build_paths() -> RenderFnResult<Vec<String>> {
// These will all become URLs at `/post/<name>`
Ok(vec![
"welcome".to_string(),
"really-popular-post".to_string(),
"foobar".to_string(),
])
}
// EXCERPT_END

// SNIP
fn get_post_for_path(_path: String) -> Result<Post, std::io::Error> {
unimplemented!()
}
fn parse_markdown(_content: String) -> String {
unimplemented!()
}
19 changes: 9 additions & 10 deletions website/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,15 @@ readme = "./README.md"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
perseus = { version = "=0.4.0-beta.5", features = [ "translator-fluent" ] }
sycamore = "=0.8.0-beta.7"
sycamore-macro = "=0.8.0-beta.7"
serde = { version = "1", features = ["derive"] }
perseus = { version = "=0.4.0-beta.9", features = [ "translator-lightweight" ] }
sycamore = "0.8"
sycamore-macro = "0.8"
serde = { version = "1", features = [ "derive" ] }
serde_json = "1"
fluent-bundle = "0.15"
lazy_static = "1"
# To avoid insane target-gating on event handlers, we put this everwhere for convenience
web-sys = { version = "0.3", features = [ "Event", "EventTarget" ] }
wasm-bindgen = "0.2"
# To avoid insane target-gating on event handlers, we put this everywhere for convenience
web-sys = { version = "0.3", features = [ "Event", "EventTarget", "Element", "Window", "Document", "DomRect", "HtmlCollection", "IntersectionObserver", "IntersectionObserverInit", "IntersectionObserverEntry", "KeyboardEvent" ] }
wasm-bindgen = "0.2.82"

[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
tokio = { version = "1", features = [ "macros", "rt", "rt-multi-thread" ] }
Expand All @@ -31,5 +30,5 @@ regex = "1"

[target.'cfg(target_arch = "wasm32")'.dependencies]
wee_alloc = "0.4"

[workspace]
js-sys = "0.3"
gloo-timers = "0.2"
5 changes: 4 additions & 1 deletion website/comparisons/eleventy.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,8 @@
"supports_exporting": "full",
"language": "JavaScript/TypeScript",
"homepage_lighthouse_desktop": 100,
"homepage_lighthouse_mobile": 97
"homepage_lighthouse_mobile": 97,
"text": {
"en-US": "Eleventy is an extremely capable static site generator that creates websites that are usually as performant as Perseus ones, though it lacks the state platform necessary for app development. With a host of integrations out of the box, Eleventy is an excellent choice for small websites, though Perseus' app shell and state platform make it outperform Eleventy at runtime, while enabling the development of more advanced apps that take advantage of features like request-time state generation, and incremental generation."
}
}
5 changes: 4 additions & 1 deletion website/comparisons/gatsby.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,8 @@
"supports_exporting": "full",
"language": "JavaScript/TypeScript",
"homepage_lighthouse_desktop": 75,
"homepage_lighthouse_mobile": 45
"homepage_lighthouse_mobile": 45,
"text": {
"en-US": "GatsbyJS is a fullstack framework that brought static site generation (build-time state generation, in Perseus) to the mainstream. However, Perseus remains faster than Gatsby at runtime, and is easier to configure for certain common use-cases, sch as internationalization. GatsbyJS has more recently embraced server-side rendering, though the integration between that and build-time state generation is present only in Perseus."
}
}
5 changes: 4 additions & 1 deletion website/comparisons/nextjs.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,8 @@
"supports_exporting": "full",
"language": "JavaScript/TypeScript",
"homepage_lighthouse_desktop": 100,
"homepage_lighthouse_mobile": 72
"homepage_lighthouse_mobile": 72,
"text": {
"en-US": "NextJS is a fullstack framework for building websites and apps in JavaScript, and is the framework closest to Perseus' capabilities. Notably however, Perseus is considerably faster than NextJS at runtime (though not in compilation time), and supports the unique feature of using both server-side and build-time state generation on the same page. NextJS is far more widely used though, and has a vibrant ecosystem of plugins and tutorials that may be difficult to find with a younger framework, like Perseus."
}
}
Loading

0 comments on commit b7ace94

Please sign in to comment.