Compare commits

..

1 Commits

Author SHA1 Message Date
Greg Johnston
2cc6ccaacb feat: custom_view macro to allow implementing view types on arbitrary data 2024-08-04 21:05:04 -04:00
320 changed files with 4840 additions and 16359 deletions

View File

@@ -1,13 +0,0 @@
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "daily"
- package-ecosystem: "cargo"
directories:
- "/"
- "/examples/*"
- "/benchmarks"
schedule:
interval: "daily"

View File

@@ -1,21 +1,23 @@
name: CI Changed Examples
on:
push:
branches:
- main
- leptos_0.6
pull_request:
branches:
- main
- leptos_0.6
jobs:
get-example-changed:
uses: ./.github/workflows/get-example-changed.yml
get-matrix:
needs: [get-example-changed]
uses: ./.github/workflows/get-changed-examples-matrix.yml
with:
example_changed: ${{ fromJSON(needs.get-example-changed.outputs.example_changed) }}
test:
name: CI
needs: [get-example-changed, get-matrix]

View File

@@ -1,13 +1,13 @@
name: CI Examples
on:
push:
branches:
- main
- leptos_0.6
pull_request:
branches:
- main
- leptos_0.6
jobs:
get-leptos-changed:
uses: ./.github/workflows/get-leptos-changed.yml

View File

@@ -1,24 +1,27 @@
name: CI semver
on:
push:
branches:
- main
- leptos_0.6
pull_request:
branches:
- main
- leptos_0.6
jobs:
get-leptos-changed:
uses: ./.github/workflows/get-leptos-changed.yml
test:
needs: [get-leptos-changed]
if: github.event.pull_request.labels[0].name == 'semver' # needs.get-leptos-changed.outputs.leptos_changed == 'true' && github.event.pull_request.labels[0].name != 'breaking'
if: needs.get-leptos-changed.outputs.leptos_changed == 'true' && github.event.pull_request.labels[0].name != 'breaking'
name: Run semver check (nightly-2024-08-01)
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Semver Checks
uses: obi1kenobi/cargo-semver-checks-action@v2
with:

View File

@@ -1,25 +1,50 @@
name: CI
on:
push:
branches:
- main
- leptos_0.6
pull_request:
branches:
- main
- leptos_0.6
jobs:
get-leptos-changed:
uses: ./.github/workflows/get-leptos-changed.yml
get-leptos-matrix:
uses: ./.github/workflows/get-leptos-matrix.yml
test:
name: CI
needs: [get-leptos-changed, get-leptos-matrix]
needs: [get-leptos-changed]
if: needs.get-leptos-changed.outputs.leptos_changed == 'true'
strategy:
matrix: ${{ fromJSON(needs.get-leptos-matrix.outputs.matrix) }}
fail-fast: false
matrix:
directory:
[
any_error,
any_spawner,
const_str_slice_concat,
either_of,
hydration_context,
integrations/actix,
integrations/axum,
integrations/utils,
leptos,
leptos_config,
leptos_dom,
leptos_hot_reload,
leptos_macro,
leptos_server,
meta,
next_tuple,
oco,
or_poisoned,
reactive_graph,
router,
router_macro,
server_fn,
server_fn/server_fn_macro_default,
server_fn_macro,
]
uses: ./.github/workflows/run-cargo-make-task.yml
with:
directory: ${{ matrix.directory }}

View File

@@ -26,7 +26,7 @@ jobs:
- name: Get example project directories that changed
id: changed-dirs
uses: tj-actions/changed-files@v45
uses: tj-actions/changed-files@v41
with:
dir_names: true
dir_names_max_depth: "2"

View File

@@ -1,10 +1,12 @@
name: Examples Changed Call
on:
workflow_call:
outputs:
example_changed:
description: "Example Changed"
value: ${{ jobs.get-example-changed.outputs.example_changed }}
jobs:
get-example-changed:
name: Get Example Changed
@@ -16,17 +18,21 @@ jobs:
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Get example files that changed
id: changed-files
uses: tj-actions/changed-files@v45
uses: tj-actions/changed-files@v43
with:
files: |
examples/**
!examples/cargo-make/**
!examples/gtk/**
!examples/Makefile.toml
!examples/*.md
- name: List example files that changed
run: echo '${{ steps.changed-files.outputs.all_changed_files }}'
- name: Set example_changed
id: set-example-changed
run: |

View File

@@ -1,34 +1,38 @@
name: Get Examples Matrix Call
on:
workflow_call:
outputs:
matrix:
description: "Matrix"
value: ${{ jobs.create.outputs.matrix }}
jobs:
create:
name: Create Examples Matrix
runs-on: ubuntu-latest
outputs:
matrix: ${{ steps.set-matrix.outputs.matrix }}
env:
# separate examples using "|" (vertical bar) char like "a|b|c".
# cargo-make should be excluded by default.
EXCLUDED_EXAMPLES: cargo-make
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install jq
run: sudo apt-get install jq
- name: Set Matrix
id: set-matrix
run: |
examples=$(ls -1d examples/*/ |
grep -vE "($EXCLUDED_EXAMPLES)" |
sed 's/\/$//' |
examples=$(ls examples |
awk '{print "examples/" $0}' |
grep -v .md |
grep -v examples/Makefile.toml |
grep -v examples/cargo-make |
grep -v examples/gtk |
jq -R -s -c 'split("\n")[:-1]')
echo "Example Directories: $examples"
echo "matrix={\"directory\":$examples}" >> "$GITHUB_OUTPUT"
- name: Print Location Info
run: |
echo "Workspace: ${{ github.workspace }}"

View File

@@ -1,10 +1,12 @@
name: Get Leptos Changed Call
on:
workflow_call:
outputs:
leptos_changed:
description: "Leptos Changed"
value: ${{ jobs.create.outputs.leptos_changed }}
jobs:
create:
name: Detect Source Change
@@ -16,19 +18,40 @@ jobs:
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Get source files that changed
id: changed-source
uses: tj-actions/changed-files@v45
uses: tj-actions/changed-files@v43
with:
files_ignore: |
.*/**/*
cargo-make/**/*
examples/**/*
projects/**/*
benchmarks/**/*
docs/**/*
files: |
any_error/**
any_spawner/**
const_str_slice_concat/**
either_of/**
hydration_context/**
integrations/actix/**
integrations/axum/**
integrations/utils/**
leptos/**
leptos_config/**
leptos_dom/**
leptos_hot_reload/**
leptos_macro/**
leptos_server/**
meta/**
next_tuple/**
oco/**
or_poisoned/**
reactive_graph/**
router/**
router_macro/**
server_fn/**
server_fn/server_fn_macro_default/**
server_fn_macro/**
- name: List source files that changed
run: echo '${{ steps.changed-source.outputs.all_changed_files }}'
- name: Set leptos_changed
id: set-source-changed
run: |

View File

@@ -1,32 +0,0 @@
name: Get Leptos Matrix Call
on:
workflow_call:
outputs:
matrix:
description: "Matrix"
value: ${{ jobs.create.outputs.matrix }}
jobs:
create:
name: Create Leptos Matrix
runs-on: ubuntu-latest
outputs:
matrix: ${{ steps.set-matrix.outputs.matrix }}
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install jq
run: sudo apt-get install jq
- name: Set Matrix
id: set-matrix
run: |
crates=$(cargo metadata --no-deps --quiet --format-version 1 |
jq -r '.packages[] | select(.name != "workspace") | .manifest_path| rtrimstr("/Cargo.toml")' |
sed "s|$(pwd)/||" |
jq -R -s -c 'split("\n")[:-1]')
echo "Leptos Directories: $crates"
echo "matrix={\"directory\":$crates}" >> "$GITHUB_OUTPUT"
- name: Print Location Info
run: |
echo "Workspace: ${{ github.workspace }}"
pwd
ls | sort -u

View File

@@ -1,4 +1,5 @@
name: Run Task
on:
workflow_call:
inputs:
@@ -11,53 +12,70 @@ on:
toolchain:
required: true
type: string
env:
CARGO_TERM_COLOR: always
CARGO_REGISTRIES_CRATES_IO_PROTOCOL: sparse
jobs:
test:
name: Run ${{ inputs.cargo_make_task }} (${{ inputs.toolchain }})
runs-on: ubuntu-latest
steps:
# Setup environment
- uses: actions/checkout@v4
- name: Setup Rust
uses: dtolnay/rust-toolchain@master
with:
toolchain: ${{ inputs.toolchain }}
- name: Add wasm32-unknown-unknown
run: rustup target add wasm32-unknown-unknown
- name: Setup cargo-make
uses: davidB/rust-cargo-make@v1
- name: Cargo generate-lockfile
run: cargo generate-lockfile
- uses: Swatinem/rust-cache@v2
- name: Install binstall
uses: cargo-bins/cargo-binstall@main
- name: Install wasm-bindgen
run: cargo binstall wasm-bindgen-cli --no-confirm
- name: Install cargo-leptos
run: cargo binstall cargo-leptos --no-confirm
- name: Install Trunk
uses: jetli/trunk-action@v0.5.0
with:
version: "latest"
- name: Print Trunk Version
run: trunk --version
- name: Install Node.js
uses: actions/setup-node@v4
with:
node-version: 20
- uses: pnpm/action-setup@v4
- uses: pnpm/action-setup@v3
name: Install pnpm
id: pnpm-install
with:
version: 8
run_install: false
- name: Get pnpm store directory
id: pnpm-cache
run: |
echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT
- uses: actions/cache@v4
name: Setup pnpm cache
with:
@@ -65,6 +83,7 @@ jobs:
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-store-
- name: Maybe install chromedriver
run: |
project_makefile=${{inputs.directory}}/Makefile.toml
@@ -80,6 +99,7 @@ jobs:
else
echo chromedriver is not required
fi
- name: Maybe install playwright browser dependencies
run: |
for pw_path in $(find ${{inputs.directory}} -name playwright.config.ts)
@@ -93,16 +113,12 @@ jobs:
echo Playwright is not required
fi
done
- name: Install Deno
uses: denoland/setup-deno@v1
with:
deno-version: v1.x
- name: Maybe install gtk-rs dependencies
run: |
if [ ! -z $(echo ${{inputs.directory}} | grep gtk) ]; then
sudo apt-get update
sudo apt-get install -y libglib2.0-dev libgio2.0-cil-dev libgraphene-1.0-dev libcairo2-dev libpango1.0-dev libgtk-4-dev
fi
# Run Cargo Make Task
- name: ${{ inputs.cargo_make_task }}
run: |

View File

@@ -37,39 +37,38 @@ members = [
"router_macro",
"any_error",
]
exclude = ["benchmarks", "examples", "projects"]
exclude = ["benchmarks", "examples"]
[workspace.package]
version = "0.7.0-beta6"
edition = "2021"
rust-version = "1.76"
version = "0.7.0-beta"
rust-version = "1.75"
[workspace.dependencies]
throw_error = { path = "./any_error/", version = "0.2.0-beta6" }
any_spawner = { path = "./any_spawner/", version = "0.1.0" }
const_str_slice_concat = { path = "./const_str_slice_concat", version = "0.1.0" }
either_of = { path = "./either_of/", version = "0.1.0" }
hydration_context = { path = "./hydration_context", version = "0.2.0-beta6" }
leptos = { path = "./leptos", version = "0.7.0-beta6" }
leptos_config = { path = "./leptos_config", version = "0.7.0-beta6" }
leptos_dom = { path = "./leptos_dom", version = "0.7.0-beta6" }
leptos_hot_reload = { path = "./leptos_hot_reload", version = "0.7.0-beta6" }
leptos_integration_utils = { path = "./integrations/utils", version = "0.7.0-beta6" }
leptos_macro = { path = "./leptos_macro", version = "0.7.0-beta6" }
leptos_router = { path = "./router", version = "0.7.0-beta6" }
leptos_router_macro = { path = "./router_macro", version = "0.7.0-beta6" }
leptos_server = { path = "./leptos_server", version = "0.7.0-beta6" }
leptos_meta = { path = "./meta", version = "0.7.0-beta6" }
next_tuple = { path = "./next_tuple", version = "0.1.0-beta6" }
oco_ref = { path = "./oco", version = "0.2.0" }
or_poisoned = { path = "./or_poisoned", version = "0.1.0" }
reactive_graph = { path = "./reactive_graph", version = "0.1.0-beta6" }
reactive_stores = { path = "./reactive_stores", version = "0.1.0-beta6" }
reactive_stores_macro = { path = "./reactive_stores_macro", version = "0.1.0-beta6" }
server_fn = { path = "./server_fn", version = "0.7.0-beta6" }
server_fn_macro = { path = "./server_fn_macro", version = "0.7.0-beta6" }
server_fn_macro_default = { path = "./server_fn/server_fn_macro_default", version = "0.7.0-beta6" }
tachys = { path = "./tachys", version = "0.1.0-beta6" }
throw_error = { path = "./any_error/", version = "0.2.0-beta" }
any_spawner = { path = "./any_spawner/", version = "0.1" }
const_str_slice_concat = { path = "./const_str_slice_concat", version = "0.1" }
either_of = { path = "./either_of/", version = "0.1" }
hydration_context = { path = "./hydration_context", version = "0.2.0-beta" }
leptos = { path = "./leptos", version = "0.7.0-beta" }
leptos_config = { path = "./leptos_config", version = "0.7.0-beta" }
leptos_dom = { path = "./leptos_dom", version = "0.7.0-beta" }
leptos_hot_reload = { path = "./leptos_hot_reload", version = "0.7.0-beta" }
leptos_integration_utils = { path = "./integrations/utils", version = "0.7.0-beta" }
leptos_macro = { path = "./leptos_macro", version = "0.7.0-beta" }
leptos_router = { path = "./router", version = "0.7.0-beta" }
leptos_router_macro = { path = "./router_macro", version = "0.7.0-beta" }
leptos_server = { path = "./leptos_server", version = "0.7.0-beta" }
leptos_meta = { path = "./meta", version = "0.7.0-beta" }
next_tuple = { path = "./next_tuple", version = "0.1.0-beta" }
oco_ref = { path = "./oco", version = "0.2" }
or_poisoned = { path = "./or_poisoned", version = "0.1" }
reactive_graph = { path = "./reactive_graph", version = "0.1.0-beta" }
reactive_stores = { path = "./reactive_stores", version = "0.1.0-beta" }
reactive_stores_macro = { path = "./reactive_stores_macro", version = "0.1.0-beta" }
server_fn = { path = "./server_fn", version = "0.7.0-beta" }
server_fn_macro = { path = "./server_fn_macro", version = "0.7.0-beta" }
server_fn_macro_default = { path = "./server_fn/server_fn_macro_default", version = "0.7.0-beta" }
tachys = { path = "./tachys", version = "0.1.0-beta" }
[profile.release]
codegen-units = 1

View File

@@ -12,8 +12,6 @@
You can find a list of useful libraries and example projects at [`awesome-leptos`](https://github.com/leptos-rs/awesome-leptos).
# The `main` branch is currently undergoing major changes in preparation for the [0.7](https://github.com/leptos-rs/leptos/milestone/4) release. For a stable version, please use the [v0.6.13 tag](https://github.com/leptos-rs/leptos/tree/v0.6.13)
# Leptos
```rust

View File

@@ -1,13 +1,13 @@
[package]
name = "throw_error"
version = "0.2.0-beta6"
edition = "2021"
version = "0.2.0-beta"
authors = ["Greg Johnston"]
license = "MIT"
readme = "../README.md"
repository = "https://github.com/leptos-rs/leptos"
description = "Utilities for wrapping, throwing, and catching errors."
rust-version.workspace = true
edition.workspace = true
[dependencies]
pin-project-lite = "0.2.14"
pin-project-lite = "0.2"

View File

@@ -1,22 +1,22 @@
[package]
name = "any_spawner"
edition = "2021"
version = "0.1.1"
authors = ["Greg Johnston"]
license = "MIT"
readme = "../README.md"
repository = "https://github.com/leptos-rs/leptos"
description = "Spawn asynchronous tasks in an executor-independent way."
edition.workspace = true
[dependencies]
futures = "0.3.30"
glib = { version = "0.20.0", optional = true }
thiserror = "1.0"
tokio = { version = "1.39", optional = true, default-features = false, features = [
"rt",
futures = "0.3"
glib = { version = "0.19", optional = true }
thiserror = "1"
tokio = { version = "1", optional = true, default-features = false, features = [
"rt",
] }
tracing = { version = "0.1.40", optional = true }
wasm-bindgen-futures = { version = "0.4.42", optional = true }
tracing = { version = "0.1", optional = true }
wasm-bindgen-futures = { version = "0.4", optional = true }
[features]
tracing = ["dep:tracing"]
@@ -28,6 +28,3 @@ futures-executor = ["futures/thread-pool", "futures/executor"]
[package.metadata.docs.rs]
all-features = true
rustdoc-args = ["--cfg", "docsrs"]
[package.metadata.cargo-all-features]
denylist = ["tracing"]

View File

@@ -2,36 +2,35 @@
name = "benchmarks"
version = "0.1.0"
edition = "2021"
# std::sync::LazyLock is stabilized in Rust version 1.80.0
rust-version = "1.80.0"
rust-version.workspace = true
[dependencies]
l0410 = { package = "leptos", version = "0.4.10", features = [
"nightly",
"ssr",
"nightly",
"ssr",
] }
leptos = { path = "../leptos", features = ["ssr", "nightly"] }
leptos_reactive = { path = "../leptos_reactive", features = ["ssr", "nightly"] }
tachydom = { git = "https://github.com/gbj/tachys", features = [
"nightly",
"leptos",
"nightly",
"leptos",
] }
tachy_maccy = { git = "https://github.com/gbj/tachys", features = ["nightly"] }
sycamore = { version = "0.8.0", features = ["ssr"] }
yew = { version = "0.20.0", features = ["ssr"] }
tokio-test = "0.4.0"
miniserde = "0.1.0"
gloo = "0.8.0"
uuid = { version = "1.0", features = ["serde", "v4", "wasm-bindgen"] }
wasm-bindgen = "0.2.0"
lazy_static = "1.0"
log = "0.4.0"
strum = "0.24.0"
strum_macros = "0.24.0"
serde = { version = "1.0", features = ["derive", "rc"] }
serde_json = "1.0"
tera = "1.0"
sycamore = { version = "0.8", features = ["ssr"] }
yew = { version = "0.20", features = ["ssr"] }
tokio-test = "0.4"
miniserde = "0.1"
gloo = "0.8"
uuid = { version = "1", features = ["serde", "v4", "wasm-bindgen"] }
wasm-bindgen = "0.2"
lazy_static = "1"
log = "0.4"
strum = "0.24"
strum_macros = "0.24"
serde = { version = "1", features = ["derive", "rc"] }
serde_json = "1"
tera = "1"
[dependencies.web-sys]
version = "0.3.0"
version = "0.3"
features = ["Window", "Document", "HtmlElement", "HtmlInputElement"]

View File

@@ -18,7 +18,7 @@ fn leptos_ssr_bench(b: &mut Bencher) {
}
}
let rendered = view! {
let rendered = view! {
<main>
<h1>"Welcome to our benchmark page."</h1>
<p>"Here's some introductory text."</p>
@@ -58,7 +58,7 @@ fn tachys_ssr_bench(b: &mut Bencher) {
}
}
let rendered = view! {
let rendered = view! {
<main>
<h1>"Welcome to our benchmark page."</h1>
<p>"Here's some introductory text."</p>
@@ -92,13 +92,13 @@ fn tera_ssr_bench(b: &mut Bencher) {
{% endfor %}
</main>"#;
static LazyCell<TERA>: Tera = LazyLock::new(|| {
let mut tera = Tera::default();
tera.add_raw_templates(vec![("template.html", TEMPLATE)]).unwrap();
tera
});
lazy_static::lazy_static! {
static ref TERA: Tera = {
let mut tera = Tera::default();
tera.add_raw_templates(vec![("template.html", TEMPLATE)]).unwrap();
tera
};
}
#[derive(Serialize, Deserialize)]
struct Counter {

View File

@@ -55,7 +55,7 @@ static TEMPLATE: &str = r#"<main>
{% else %}
<li><a href="/">All</a></li>
{% endif %}
{% if mode_active %}
<li><a href="/active" class="selected">Active</a></li>
{% else %}
@@ -91,13 +91,13 @@ fn tera_todomvc_ssr(b: &mut Bencher) {
use serde::{Deserialize, Serialize};
use tera::*;
static LazyLock<TERA>: Tera = LazyLock( || {
lazy_static::lazy_static! {
static ref TERA: Tera = {
let mut tera = Tera::default();
tera.add_raw_templates(vec![("template.html", TEMPLATE)]).unwrap();
tera
});
};
}
#[derive(Serialize, Deserialize)]
struct Todo {
@@ -131,13 +131,13 @@ fn tera_todomvc_ssr_1000(b: &mut Bencher) {
use serde::{Deserialize, Serialize};
use tera::*;
static TERA: LazyLock<Tera> = LazyLock::new(|| {
let mut tera = Tera::default();
tera.add_raw_templates(vec![("template.html", TEMPLATE)]).unwrap();
tera
});
lazy_static::lazy_static! {
static ref TERA: Tera = {
let mut tera = Tera::default();
tera.add_raw_templates(vec![("template.html", TEMPLATE)]).unwrap();
tera
};
}
#[derive(Serialize, Deserialize)]
struct Todo {

View File

@@ -1,5 +1,6 @@
[package]
name = "const_str_slice_concat"
edition = "2021"
version = "0.1.0"
authors = ["Greg Johnston"]
license = "MIT"
@@ -7,6 +8,5 @@ readme = "../README.md"
repository = "https://github.com/leptos-rs/leptos"
description = "Utilities for const concatenation of string slices."
rust-version.workspace = true
edition.workspace = true
[dependencies]

View File

@@ -1,5 +1,6 @@
[package]
name = "either_of"
edition = "2021"
version = "0.1.0"
authors = ["Greg Johnston"]
license = "MIT"
@@ -7,7 +8,6 @@ readme = "../README.md"
repository = "https://github.com/leptos-rs/leptos"
description = "Utilities for working with enumerated types that contain one of 2..n other types."
rust-version.workspace = true
edition.workspace = true
[dependencies]
pin-project-lite = "0.2.14"
pin-project-lite = "0.2"

View File

@@ -133,104 +133,3 @@ tuples!(EitherOf13 + EitherOf13Future + EitherOf13FutureProj => A, B, C, D, E, F
tuples!(EitherOf14 + EitherOf14Future + EitherOf14FutureProj => A, B, C, D, E, F, G, H, I, J, K, L, M, N);
tuples!(EitherOf15 + EitherOf15Future + EitherOf15FutureProj => A, B, C, D, E, F, G, H, I, J, K, L, M, N, O);
tuples!(EitherOf16 + EitherOf16Future + EitherOf16FutureProj => A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P);
/// Matches over the first expression and returns an either ([`Either`], [`EitherOf3`], ... [`EitherOf6`])
/// composed of the values returned by the match arms.
///
/// The pattern syntax is exactly the same as found in a match arm.
///
/// # Examples
///
/// ```
/// # use either_of::*;
/// let either2 = either!(Some("hello"),
/// Some(s) => s.len(),
/// None => 0.0,
/// );
/// assert!(matches!(either2, Either::<usize, f64>::Left(5)));
///
/// let either3 = either!(Some("admin"),
/// Some("admin") => "hello admin",
/// Some(_) => 'x',
/// _ => 0,
/// );
/// assert!(matches!(either3, EitherOf3::<&str, char, i32>::A("hello admin")));
/// ```
#[macro_export]
macro_rules! either {
($match:expr, $left_pattern:pat => $left_expression:expr, $right_pattern:pat => $right_expression:expr,) => {
match $match {
$left_pattern => $crate::Either::Left($left_expression),
$right_pattern => $crate::Either::Right($right_expression),
}
};
($match:expr, $a_pattern:pat => $a_expression:expr, $b_pattern:pat => $b_expression:expr, $c_pattern:pat => $c_expression:expr,) => {
match $match {
$a_pattern => $crate::EitherOf3::A($a_expression),
$b_pattern => $crate::EitherOf3::B($b_expression),
$c_pattern => $crate::EitherOf3::C($c_expression),
}
};
($match:expr, $a_pattern:pat => $a_expression:expr, $b_pattern:pat => $b_expression:expr, $c_pattern:pat => $c_expression:expr, $d_pattern:pat => $d_expression:expr,) => {
match $match {
$a_pattern => $crate::EitherOf4::A($a_expression),
$b_pattern => $crate::EitherOf4::B($b_expression),
$c_pattern => $crate::EitherOf4::C($c_expression),
$d_pattern => $crate::EitherOf4::D($d_expression),
}
};
($match:expr, $a_pattern:pat => $a_expression:expr, $b_pattern:pat => $b_expression:expr, $c_pattern:pat => $c_expression:expr, $d_pattern:pat => $d_expression:expr, $e_pattern:pat => $e_expression:expr,) => {
match $match {
$a_pattern => $crate::EitherOf5::A($a_expression),
$b_pattern => $crate::EitherOf5::B($b_expression),
$c_pattern => $crate::EitherOf5::C($c_expression),
$d_pattern => $crate::EitherOf5::D($d_expression),
$e_pattern => $crate::EitherOf5::E($e_expression),
}
};
($match:expr, $a_pattern:pat => $a_expression:expr, $b_pattern:pat => $b_expression:expr, $c_pattern:pat => $c_expression:expr, $d_pattern:pat => $d_expression:expr, $e_pattern:pat => $e_expression:expr, $f_pattern:pat => $f_expression:expr,) => {
match $match {
$a_pattern => $crate::EitherOf6::A($a_expression),
$b_pattern => $crate::EitherOf6::B($b_expression),
$c_pattern => $crate::EitherOf6::C($c_expression),
$d_pattern => $crate::EitherOf6::D($d_expression),
$e_pattern => $crate::EitherOf6::E($e_expression),
$f_pattern => $crate::EitherOf6::F($f_expression),
}
}; // if you need more eithers feel free to open a PR ;-)
}
// compile time test
#[test]
fn either_macro() {
let _: Either<&str, f64> = either!(12,
12 => "12",
_ => 0.0,
);
let _: EitherOf3<&str, f64, i32> = either!(12,
12 => "12",
13 => 0.0,
_ => 12,
);
let _: EitherOf4<&str, f64, char, i32> = either!(12,
12 => "12",
13 => 0.0,
14 => ' ',
_ => 12,
);
let _: EitherOf5<&str, f64, char, f32, i32> = either!(12,
12 => "12",
13 => 0.0,
14 => ' ',
15 => 0.0f32,
_ => 12,
);
let _: EitherOf6<&str, f64, char, f32, u8, i32> = either!(12,
12 => "12",
13 => 0.0,
14 => ' ',
15 => 0.0f32,
16 => 24u8,
_ => 12,
);
}

View File

@@ -7,18 +7,19 @@ edition = "2021"
crate-type = ["cdylib", "rlib"]
[dependencies]
actix-files = { version = "0.6.6", optional = true }
actix-web = { version = "4.8", optional = true, features = ["macros"] }
console_error_panic_hook = "0.1.7"
cfg-if = "1.0"
actix-files = { version = "0.6", optional = true }
actix-web = { version = "4", optional = true, features = ["macros"] }
console_error_panic_hook = "0.1"
cfg-if = "1"
leptos = { path = "../../leptos" }
leptos_meta = { path = "../../meta" }
leptos_actix = { path = "../../integrations/actix", optional = true }
leptos_router = { path = "../../router" }
wasm-bindgen = "0.2.93"
serde = { version = "1.0", features = ["derive"] }
wasm-bindgen = "0.2"
serde = { version = "1", features = ["derive"] }
[features]
csr = ["leptos/csr"]
hydrate = ["leptos/hydrate"]
ssr = [
"dep:actix-files",

View File

@@ -1,9 +1,68 @@
# Action Form Error Handling Example
<picture>
<source srcset="https://raw.githubusercontent.com/leptos-rs/leptos/main/docs/logos/Leptos_logo_Solid_White.svg" media="(prefers-color-scheme: dark)">
<img src="https://raw.githubusercontent.com/leptos-rs/leptos/main/docs/logos/Leptos_logo_RGB.svg" alt="Leptos Logo">
</picture>
## Getting Started
# Leptos Starter Template
See the [Examples README](../README.md) for setup and run instructions.
This is a template for use with the [Leptos](https://github.com/leptos-rs/leptos) web framework and the [cargo-leptos](https://github.com/akesson/cargo-leptos) tool.
## Quick Start
## Creating your template repo
Execute `cargo leptos watch` to run this example.
If you don't have `cargo-leptos` installed you can install it with
`cargo install cargo-leptos`
Then run
`cargo leptos new --git leptos-rs/start`
to generate a new project template (you will be prompted to enter a project name).
`cd {projectname}`
to go to your newly created project.
Of course, you should explore around the project structure, but the best place to start with your application code is in `src/app.rs`.
## Running your project
`cargo leptos watch`
By default, you can access your local project at `http://localhost:3000`
## Installing Additional Tools
By default, `cargo-leptos` uses `nightly` Rust, `cargo-generate`, and `sass`. If you run into any trouble, you may need to install one or more of these tools.
1. `rustup toolchain install nightly --allow-downgrade` - make sure you have Rust nightly
2. `rustup target add wasm32-unknown-unknown` - add the ability to compile Rust to WebAssembly
3. `cargo install cargo-generate` - install `cargo-generate` binary (should be installed automatically in future)
4. `npm install -g sass` - install `dart-sass` (should be optional in future)
## Executing a Server on a Remote Machine Without the Toolchain
After running a `cargo leptos build --release` the minimum files needed are:
1. The server binary located in `target/server/release`
2. The `site` directory and all files within located in `target/site`
Copy these files to your remote server. The directory structure should be:
```text
leptos_start
site/
```
Set the following environment variables (updating for your project as needed):
```sh
export LEPTOS_OUTPUT_NAME="leptos_start"
export LEPTOS_SITE_ROOT="site"
export LEPTOS_SITE_PKG_DIR="pkg"
export LEPTOS_SITE_ADDR="127.0.0.1:3000"
export LEPTOS_RELOAD_PORT="3001"
```
Finally, run the server binary.
## Notes about CSR and Trunk:
Although it is not recommended, you can also run your project without server integration using the feature `csr` and `trunk serve`:
`trunk serve --open --features csr`
This may be useful for integrating external tools which require a static site, e.g. `tauri`.

View File

@@ -52,10 +52,23 @@ async fn main() -> std::io::Result<()> {
.await
}
#[cfg(not(feature = "ssr"))]
#[cfg(not(any(feature = "ssr", feature = "csr")))]
pub fn main() {
// no client-side main function
// unless we want this to work with e.g., Trunk for pure client-side testing
// see lib.rs for hydration function instead
// see optional feature `csr` instead
}
#[cfg(all(not(feature = "ssr"), feature = "csr"))]
pub fn main() {
// a client-side main function is required for using `trunk serve`
// prefer using `cargo leptos serve` instead
// to run: `trunk serve --open --features csr`
use action_form_error_handling::app::*;
use leptos::prelude::*;
console_error_panic_hook::set_once();
mount_to_body(App);
}

View File

@@ -1,111 +0,0 @@
[package]
name = "axum_js_ssr"
version = "0.1.0"
edition = "2021"
[lib]
crate-type = ["cdylib", "rlib"]
[dependencies]
axum = { version = "0.7.5", optional = true }
console_error_panic_hook = "0.1.7"
console_log = "1.0"
gloo-utils = "0.2.0"
html-escape = "0.2.13"
http-body-util = { version = "0.1.0", optional = true }
js-sys = { version = "0.3.69", optional = true }
leptos = { path = "../../leptos", features = ["tracing"] }
leptos_meta = { path = "../../meta" }
leptos_axum = { path = "../../integrations/axum", optional = true }
leptos_router = { path = "../../router" }
serde = { version = "1.0", features = ["derive"] }
thiserror = "1.0"
tokio = { version = "1.39", features = [ "rt-multi-thread", "macros", "time" ], optional = true }
tower = { version = "0.4.13", optional = true }
tower-http = { version = "0.5.2", features = ["fs"], optional = true }
wasm-bindgen = "0.2.92"
web-sys = { version = "0.3.69", features = [ "AddEventListenerOptions", "Document", "Element", "Event", "EventListener", "EventTarget", "Performance", "Window" ], optional = true }
[features]
hydrate = [
"leptos/hydrate",
"dep:js-sys",
"dep:web-sys",
]
ssr = [
"dep:axum",
"dep:http-body-util",
"dep:tower",
"dep:tower-http",
"dep:tokio",
"leptos/ssr",
"leptos_meta/ssr",
"dep:leptos_axum",
"leptos_router/ssr",
]
[profile.release]
panic = "abort"
[profile.wasm-release]
inherits = "release"
opt-level = 'z'
lto = true
codegen-units = 1
panic = "abort"
[package.metadata.cargo-all-features]
denylist = ["axum", "tower", "tower-http", "tokio", "sqlx", "leptos_axum"]
skip_feature_sets = [["ssr", "hydrate"]]
[package.metadata.leptos]
# The name used by wasm-bindgen/cargo-leptos for the JS/WASM bundle. Defaults to the crate name
output-name = "axum_js_ssr"
# The site root folder is where cargo-leptos generate all output. WARNING: all content of this folder will be erased on a rebuild. Use it in your server setup.
site-root = "target/site"
# The site-root relative folder where all compiled output (JS, WASM and CSS) is written
# Defaults to pkg
site-pkg-dir = "pkg"
# [Optional] The source CSS file. If it ends with .sass or .scss then it will be compiled by dart-sass into CSS. The CSS is optimized by Lightning CSS before being written to <site-root>/<site-pkg>/app.css
style-file = "style/main.scss"
# Assets source dir. All files found here will be copied and synchronized to site-root.
# The assets-dir cannot have a sub directory with the same name/path as site-pkg-dir.
#
# Optional. Env: LEPTOS_ASSETS_DIR.
assets-dir = "assets"
# The IP and port (ex: 127.0.0.1:3000) where the server serves the content. Use it in your server setup.
site-addr = "127.0.0.1:3000"
# The port to use for automatic reload monitoring
reload-port = 3001
# [Optional] Command to use when running end2end tests. It will run in the end2end dir.
# [Windows] for non-WSL use "npx.cmd playwright test"
# This binary name can be checked in Powershell with Get-Command npx
end2end-cmd = "npx playwright test"
end2end-dir = "end2end"
# The browserlist query used for optimizing the CSS.
browserquery = "defaults"
# Set by cargo-leptos watch when building with that tool. Controls whether autoreload JS will be included in the head
watch = false
# The environment Leptos will run in, usually either "DEV" or "PROD"
env = "DEV"
# The features to use when compiling the bin target
#
# Optional. Can be over-ridden with the command line parameter --bin-features
bin-features = ["ssr"]
# If the --no-default-features flag should be used when compiling the bin target
#
# Optional. Defaults to false.
bin-default-features = false
# The features to use when compiling the lib target
#
# Optional. Can be over-ridden with the command line parameter --lib-features
lib-features = ["hydrate"]
# If the --no-default-features flag should be used when compiling the lib target
#
# Optional. Defaults to false.
lib-default-features = false
lib-profile-release = "wasm-release"

View File

@@ -1,21 +0,0 @@
MIT License
Copyright (c) 2024 Tommy Yu
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -1,8 +0,0 @@
extend = [
{ path = "../cargo-make/main.toml" },
{ path = "../cargo-make/cargo-leptos.toml" },
]
[env]
CLIENT_PROCESS_NAME = "axum_js_ssr"

View File

@@ -1,10 +0,0 @@
# Leptos Axum JS SSR Example
This example shows the various ways that JavaScript may be included into
a Leptos application. The intent is to demonstrate how this may be done
and how it may cause the application to fail in an unexpected manner if
done incorrectly.
## Quick Start
Run `cargo leptos watch` to run this example.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

View File

@@ -1,29 +0,0 @@
BSD 3-Clause License
Copyright (c) 2006, Ivan Sagalaev.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@@ -1,47 +0,0 @@
# Highlight.js CDN Assets
**Note: this contains only a subset of files from the full package from NPM.**
[![install size](https://packagephobia.now.sh/badge?p=highlight.js)](https://packagephobia.now.sh/result?p=highlight.js)
**This package contains only the CDN build assets of highlight.js.**
This may be what you want if you'd like to install the pre-built distributable highlight.js client-side assets via NPM. If you're wanting to use highlight.js mainly on the server-side you likely want the [highlight.js][1] package instead.
To access these files via CDN:<br>
https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@latest/build/
**If you just want a single .js file with the common languages built-in:
<https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@latest/build/highlight.min.js>**
---
## Highlight.js
Highlight.js is a syntax highlighter written in JavaScript. It works in
the browser as well as on the server. It works with pretty much any
markup, doesnt depend on any framework, and has automatic language
detection.
If you'd like to read the full README:<br>
<https://github.com/highlightjs/highlight.js/blob/main/README.md>
## License
Highlight.js is released under the BSD License. See [LICENSE][7] file
for details.
## Links
The official site for the library is at <https://highlightjs.org/>.
The Github project may be found at: <https://github.com/highlightjs/highlight.js>
Further in-depth documentation for the API and other topics is at
<http://highlightjs.readthedocs.io/>.
A list of the Core Team and contributors can be found in the [CONTRIBUTORS.md][8] file.
[1]: https://www.npmjs.com/package/highlight.js
[7]: https://github.com/highlightjs/highlight.js/blob/main/LICENSE
[8]: https://github.com/highlightjs/highlight.js/blob/main/CONTRIBUTORS.md

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,93 +0,0 @@
{
"name": "@highlightjs/cdn-assets",
"description": "Syntax highlighting with language autodetection. (pre-compiled CDN assets)",
"keywords": [
"highlight",
"syntax"
],
"homepage": "https://highlightjs.org/",
"version": "11.10.0",
"author": "Josh Goebel <hello@joshgoebel.com>",
"contributors": [
"Josh Goebel <hello@joshgoebel.com>",
"Egor Rogov <e.rogov@postgrespro.ru>",
"Vladimir Jimenez <me@allejo.io>",
"Ivan Sagalaev <maniac@softwaremaniacs.org>",
"Jeremy Hull <sourdrums@gmail.com>",
"Oleg Efimov <efimovov@gmail.com>",
"Gidi Meir Morris <gidi@gidi.io>",
"Jan T. Sott <git@idleberg.com>",
"Li Xuanji <xuanji@gmail.com>",
"Marcos Cáceres <marcos@marcosc.com>",
"Sang Dang <sang.dang@polku.io>"
],
"bugs": {
"url": "https://github.com/highlightjs/highlight.js/issues"
},
"license": "BSD-3-Clause",
"repository": {
"type": "git",
"url": "git://github.com/highlightjs/highlight.js.git"
},
"sideEffects": [
"./es/common.js",
"./lib/common.js",
"*.css",
"*.scss"
],
"scripts": {
"mocha": "mocha",
"lint": "eslint src/*.js src/lib/*.js demo/*.js tools/**/*.js --ignore-pattern vendor",
"lint-languages": "eslint --no-eslintrc -c .eslintrc.lang.js src/languages/**/*.js",
"build_and_test": "npm run build && npm run test",
"build_and_test_browser": "npm run build-browser && npm run test-browser",
"build": "node ./tools/build.js -t node",
"build-cdn": "node ./tools/build.js -t cdn",
"build-browser": "node ./tools/build.js -t browser :common",
"devtool": "npx http-server",
"test": "mocha test",
"test-markup": "mocha test/markup",
"test-detect": "mocha test/detect",
"test-browser": "mocha test/browser",
"test-parser": "mocha test/parser"
},
"engines": {
"node": ">=12.0.0"
},
"devDependencies": {
"@colors/colors": "^1.6.0",
"@rollup/plugin-commonjs": "^26.0.1",
"@rollup/plugin-json": "^6.0.1",
"@rollup/plugin-node-resolve": "^15.2.3",
"@types/mocha": "^10.0.2",
"@typescript-eslint/eslint-plugin": "^7.15.0",
"@typescript-eslint/parser": "^7.15.0",
"clean-css": "^5.3.2",
"cli-table": "^0.3.1",
"commander": "^12.1.0",
"css": "^3.0.0",
"css-color-names": "^1.0.1",
"deep-freeze-es6": "^3.0.2",
"del": "^7.1.0",
"dependency-resolver": "^2.0.1",
"eslint": "^8.57.0",
"eslint-config-standard": "^17.1.0",
"eslint-plugin-import": "^2.28.1",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-promise": "^6.1.1",
"glob": "^8.1.0",
"glob-promise": "^6.0.5",
"handlebars": "^4.7.8",
"http-server": "^14.1.1",
"jsdom": "^24.1.0",
"lodash": "^4.17.20",
"mocha": "^10.2.0",
"refa": "^0.4.1",
"rollup": "^4.0.2",
"should": "^13.2.3",
"terser": "^5.21.0",
"tiny-worker": "^2.3.0",
"typescript": "^5.2.2",
"wcag-contrast": "^3.0.0"
}
}

View File

@@ -1,10 +0,0 @@
pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}/*!
Theme: GitHub Dark
Description: Dark theme as seen on github.com
Author: github.com
Maintainer: @Hirse
Updated: 2021-05-15
Outdated base version: https://github.com/primer/github-syntax-dark
Current colors taken from GitHub's CSS
*/.hljs{color:#c9d1d9;background:#0d1117}.hljs-doctag,.hljs-keyword,.hljs-meta .hljs-keyword,.hljs-template-tag,.hljs-template-variable,.hljs-type,.hljs-variable.language_{color:#ff7b72}.hljs-title,.hljs-title.class_,.hljs-title.class_.inherited__,.hljs-title.function_{color:#d2a8ff}.hljs-attr,.hljs-attribute,.hljs-literal,.hljs-meta,.hljs-number,.hljs-operator,.hljs-selector-attr,.hljs-selector-class,.hljs-selector-id,.hljs-variable{color:#79c0ff}.hljs-meta .hljs-string,.hljs-regexp,.hljs-string{color:#a5d6ff}.hljs-built_in,.hljs-symbol{color:#ffa657}.hljs-code,.hljs-comment,.hljs-formula{color:#8b949e}.hljs-name,.hljs-quote,.hljs-selector-pseudo,.hljs-selector-tag{color:#7ee787}.hljs-subst{color:#c9d1d9}.hljs-section{color:#1f6feb;font-weight:700}.hljs-bullet{color:#f2cc60}.hljs-emphasis{color:#c9d1d9;font-style:italic}.hljs-strong{color:#c9d1d9;font-weight:700}.hljs-addition{color:#aff5b4;background-color:#033a16}.hljs-deletion{color:#ffdcd7;background-color:#67060c}

View File

@@ -1,10 +0,0 @@
pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}/*!
Theme: GitHub
Description: Light theme as seen on github.com
Author: github.com
Maintainer: @Hirse
Updated: 2021-05-15
Outdated base version: https://github.com/primer/github-syntax-light
Current colors taken from GitHub's CSS
*/.hljs{color:#24292e;background:#fff}.hljs-doctag,.hljs-keyword,.hljs-meta .hljs-keyword,.hljs-template-tag,.hljs-template-variable,.hljs-type,.hljs-variable.language_{color:#d73a49}.hljs-title,.hljs-title.class_,.hljs-title.class_.inherited__,.hljs-title.function_{color:#6f42c1}.hljs-attr,.hljs-attribute,.hljs-literal,.hljs-meta,.hljs-number,.hljs-operator,.hljs-selector-attr,.hljs-selector-class,.hljs-selector-id,.hljs-variable{color:#005cc5}.hljs-meta .hljs-string,.hljs-regexp,.hljs-string{color:#032f62}.hljs-built_in,.hljs-symbol{color:#e36209}.hljs-code,.hljs-comment,.hljs-formula{color:#6a737d}.hljs-name,.hljs-quote,.hljs-selector-pseudo,.hljs-selector-tag{color:#22863a}.hljs-subst{color:#24292e}.hljs-section{color:#005cc5;font-weight:700}.hljs-bullet{color:#735c0f}.hljs-emphasis{color:#24292e;font-style:italic}.hljs-strong{color:#24292e;font-weight:700}.hljs-addition{color:#22863a;background-color:#f0fff4}.hljs-deletion{color:#b31d28;background-color:#ffeef0}

View File

@@ -1,6 +0,0 @@
{
"name": "axum_js_ssr",
"dependencies": {
"@highlightjs/cdn-assets": "^11.10.0"
}
}

View File

@@ -1,2 +0,0 @@
[toolchain]
channel = "stable" # test change

View File

@@ -1,8 +0,0 @@
use leptos::{prelude::ServerFnError, server};
#[server]
pub async fn fetch_code() -> Result<String, ServerFnError> {
// emulate loading of code from a database/version control/etc
tokio::time::sleep(std::time::Duration::from_millis(50)).await;
Ok(crate::consts::CH05_02A.to_string())
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,39 +0,0 @@
// Example programs from the Rust Programming Language Book
pub const CH03_05A: &str = r#"fn main() {
let number = 3;
if number < 5 {
println!("condition was true");
} else {
println!("condition was false");
}
}
"#;
// For some reason, swapping the code examples "fixes" example 6. It
// might have something to do with the lower complexity of highlighting
// a shorter example. Anyway, including extra newlines for the shorter
// example to match with the longer in order to avoid reflowing the
// table during the async resource loading for CSR.
pub const CH05_02A: &str = r#"fn main() {
let width1 = 30;
let height1 = 50;
println!(
"The area of the rectangle is {} square pixels.",
area(width1, height1)
);
}
fn area(width: u32, height: u32) -> u32 {
width * height
}
"#;
pub const LEPTOS_HYDRATED: &str = "_leptos_hydrated";

View File

@@ -1,59 +0,0 @@
#[cfg(not(feature = "ssr"))]
mod csr {
use gloo_utils::format::JsValueSerdeExt;
use js_sys::{
Object,
Reflect::{get, set},
};
use wasm_bindgen::{prelude::wasm_bindgen, JsValue};
#[wasm_bindgen(
module = "/node_modules/@highlightjs/cdn-assets/es/highlight.min.js"
)]
extern "C" {
type HighlightOptions;
#[wasm_bindgen(catch, js_namespace = default, js_name = highlight)]
fn highlight_lang(
code: String,
options: Object,
) -> Result<Object, JsValue>;
#[wasm_bindgen(js_namespace = default, js_name = highlightAll)]
pub fn highlight_all();
}
// Keeping the `ignoreIllegals` argument out of the default case, and since there is no optional arguments
// in Rust, this will have to be provided in a separate function (e.g. `highlight_ignore_illegals`), much
// like how `web_sys` does it for the browser APIs. For simplicity, only the highlighted HTML code is
// returned on success, and None on error.
pub fn highlight(code: String, lang: String) -> Option<String> {
let options = js_sys::Object::new();
set(&options, &"language".into(), &lang.into())
.expect("failed to assign lang to options");
highlight_lang(code, options)
.map(|result| {
let value = get(&result, &"value".into())
.expect("HighlightResult failed to contain the value key");
value.into_serde().expect("Value should have been a string")
})
.ok()
}
}
#[cfg(feature = "ssr")]
mod ssr {
// noop under ssr
pub fn highlight_all() {}
// TODO see if there is a Rust-based solution that will enable isomorphic rendering for this feature.
// the current (disabled) implementation simply calls html_escape.
// pub fn highlight(code: String, _lang: String) -> Option<String> {
// Some(html_escape::encode_text(&code).into_owned())
// }
}
#[cfg(not(feature = "ssr"))]
pub use csr::*;
#[cfg(feature = "ssr")]
pub use ssr::*;

View File

@@ -1,51 +0,0 @@
pub mod api;
pub mod app;
pub mod consts;
pub mod hljs;
#[cfg(feature = "hydrate")]
#[wasm_bindgen::prelude::wasm_bindgen]
pub fn hydrate() {
use app::*;
use consts::LEPTOS_HYDRATED;
use std::panic;
panic::set_hook(Box::new(|info| {
// this custom hook will call out to show the usual error log at
// the console while also attempt to update the UI to indicate
// a restart of the application is required to continue.
console_error_panic_hook::hook(info);
let window = leptos::prelude::window();
if !matches!(
js_sys::Reflect::get(&window, &wasm_bindgen::JsValue::from_str(LEPTOS_HYDRATED)),
Ok(t) if t == true
) {
let document = leptos::prelude::document();
let _ = document.query_selector("#reset").map(|el| {
el.map(|el| {
el.set_class_name("panicked");
})
});
let _ = document.query_selector("#notice").map(|el| {
el.map(|el| {
el.set_class_name("panicked");
})
});
}
}));
leptos::mount::hydrate_body(App);
let window = leptos::prelude::window();
js_sys::Reflect::set(
&window,
&wasm_bindgen::JsValue::from_str(LEPTOS_HYDRATED),
&wasm_bindgen::JsValue::TRUE,
)
.expect("error setting hydrated status");
let event = web_sys::Event::new(LEPTOS_HYDRATED)
.expect("error creating hydrated event");
let document = leptos::prelude::document();
document
.dispatch_event(&event)
.expect("error dispatching hydrated event");
leptos::logging::log!("dispatched hydrated event");
}

View File

@@ -1,152 +0,0 @@
#[cfg(feature = "ssr")]
mod latency {
use std::sync::{Mutex, OnceLock};
pub static LATENCY: OnceLock<
Mutex<std::iter::Cycle<std::slice::Iter<'_, u64>>>,
> = OnceLock::new();
pub static ES_LATENCY: OnceLock<
Mutex<std::iter::Cycle<std::slice::Iter<'_, u64>>>,
> = OnceLock::new();
}
#[cfg(feature = "ssr")]
#[tokio::main]
async fn main() {
use axum::{
body::Body,
extract::Request,
http::{
header::{self, HeaderValue},
StatusCode,
},
middleware::{self, Next},
response::{IntoResponse, Response},
routing::get,
Router,
};
use axum_js_ssr::app::*;
use http_body_util::BodyExt;
use leptos::prelude::*;
use leptos_axum::{generate_route_list, LeptosRoutes};
latency::LATENCY.get_or_init(|| [0, 4, 40, 400].iter().cycle().into());
latency::ES_LATENCY.get_or_init(|| [0].iter().cycle().into());
// Having the ES_LATENCY (a cycle of latency for the loading of the es
// module) in an identical cycle as LATENCY (for the standard version)
// adversely influences the intended demo, as this ultimately delays
// hydration when set too high which can cause panic under every case.
// If you want to test the effects of the delay just modify the list of
// values for the desired cycle of delays.
let conf = get_configuration(None).unwrap();
let addr = conf.leptos_options.site_addr;
let leptos_options = conf.leptos_options;
// Generate the list of routes in your Leptos App
let routes = generate_route_list(App);
async fn highlight_js() -> impl IntoResponse {
(
[(header::CONTENT_TYPE, "text/javascript")],
include_str!(
"../node_modules/@highlightjs/cdn-assets/highlight.min.js"
),
)
}
async fn latency_for_highlight_js(
req: Request,
next: Next,
) -> Result<impl IntoResponse, (StatusCode, String)> {
let uri_parts = &mut req.uri().path().rsplit('/');
let is_highlightjs = uri_parts.next() == Some("highlight.min.js");
let es = uri_parts.next() == Some("es");
let module_type = if es { "es module " } else { "standard " };
let res = next.run(req).await;
if is_highlightjs {
// additional processing if the filename is the test subject
let (mut parts, body) = res.into_parts();
let bytes = body
.collect()
.await
.map_err(|err| {
(
StatusCode::BAD_REQUEST,
format!("error reading body: {err}"),
)
})?
.to_bytes();
let latency = if es {
&latency::ES_LATENCY
} else {
&latency::LATENCY
};
let delay = match latency
.get()
.expect("latency cycle wasn't set up")
.try_lock()
{
Ok(ref mut mutex) => {
*mutex.next().expect("cycle always has next")
}
Err(_) => 0,
};
// inject the logging of the delay used into the target script
log!(
"loading {module_type}highlight.min.js with latency of \
{delay} ms"
);
let js_log = format!(
"\nconsole.log('loaded {module_type}highlight.js with a \
minimum latency of {delay} ms');"
);
tokio::time::sleep(std::time::Duration::from_millis(delay)).await;
let bytes = [bytes, js_log.into()].concat();
let length = bytes.len();
let body = Body::from(bytes);
// Provide the bare minimum set of headers to avoid browser cache.
parts.headers = header::HeaderMap::from_iter(
[
(
header::CONTENT_TYPE,
HeaderValue::from_static("text/javascript"),
),
(header::CONTENT_LENGTH, HeaderValue::from(length)),
]
.into_iter(),
);
Ok(Response::from_parts(parts, body))
} else {
Ok(res)
}
}
let app = Router::new()
.route("/highlight.min.js", get(highlight_js))
.leptos_routes(&leptos_options, routes, {
let leptos_options = leptos_options.clone();
move || shell(leptos_options.clone())
})
.fallback(leptos_axum::file_and_error_handler(shell))
.layer(middleware::from_fn(latency_for_highlight_js))
.with_state(leptos_options);
// run our app with hyper
// `axum::Server` is a re-export of `hyper::Server`
log!("listening on http://{}", &addr);
let listener = tokio::net::TcpListener::bind(&addr).await.unwrap();
axum::serve(listener, app.into_make_service())
.await
.unwrap();
}
#[cfg(not(feature = "ssr"))]
pub fn main() {
// no client-side main function
// unless we want this to work with e.g., Trunk for pure client-side testing
// see lib.rs for hydration function instead
}

View File

@@ -1,171 +0,0 @@
html, body {
margin: 0;
padding: 0;
font-family: sans-serif;
height: 100vh;
overflow: hidden;
}
body {
display: flex;
flex-flow: row nowrap;
}
nav {
min-width: 17em;
height: 100vh;
counter-reset: example-counter 0;
list-style-type: none;
list-style-position: outside;
overflow: auto;
}
nav a {
display: block;
padding: 0.5em 2em;
text-decoration: none;
}
nav a small {
display: block;
}
nav a.example::before {
counter-reset: subexample-counter 0;
counter-increment: example-counter 1;
content: counter(example-counter) ". ";
}
nav a.subexample::before {
counter-increment: subexample-counter 1;
content: counter(example-counter) "." counter(subexample-counter) " ";
}
div#notice {
display: none;
}
main div#notice.panicked {
position: sticky;
top: 0;
padding: 0.5em 2em;
display: block;
}
main {
width: 100%;
overflow: auto;
}
main article {
max-width: 60em;
margin: 0 1em;
padding: 0 1em;
}
main p, main li {
line-height: 1.3em;
}
main li pre code, main div pre code {
display: block;
line-height: normal;
}
main ol, main ul {
padding-left: 2em;
}
h2>code, p>code, li>code {
border-radius: 3px;
padding: 2px;
}
li pre code, div pre code {
margin: 0 !important;
padding: 0 !important;
}
#code-demo {
overflow-x: auto;
}
#code-demo table {
width: 50em;
margin: auto;
}
#code-demo table td {
vertical-align: top;
}
#code-demo table code {
display: block;
padding: 1em;
}
@media (prefers-color-scheme: light) {
nav {
background: #f7f7f7;
}
nav a {
color: #000;
}
nav a[aria-current="page"] {
background-color: #e0e0e0;
}
nav a:hover, h2>code, p>code, li>code {
background-color: #e7e7e7;
}
nav a.panicked, main div#notice.panicked {
background: #fdd;
}
main div#notice.panicked a {
color: #000;
}
nav a.section {
border-bottom: 1px solid #777;
}
}
@media (prefers-color-scheme: dark) {
nav {
background: #080808;
}
nav a {
color: #fff;
}
nav a[aria-current="page"] {
background-color: #3f3f3f;
}
nav a:hover, h2>code, p>code, li>code {
background-color: #383838;
}
nav a.panicked, main div#notice.panicked {
background: #733;
}
main div#notice.panicked a {
color: #fff;
}
nav a.section {
border-bottom: 1px solid #888;
}
}
// Just include the raw style as-is because I can't find a quick and easy way to import them just for the
// appropriate media type...
pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}
@media (prefers-color-scheme: light){.hljs{color:#24292e;background:#fff}.hljs-doctag,.hljs-keyword,.hljs-meta .hljs-keyword,.hljs-template-tag,.hljs-template-variable,.hljs-type,.hljs-variable.language_{color:#d73a49}.hljs-title,.hljs-title.class_,.hljs-title.class_.inherited__,.hljs-title.function_{color:#6f42c1}.hljs-attr,.hljs-attribute,.hljs-literal,.hljs-meta,.hljs-number,.hljs-operator,.hljs-selector-attr,.hljs-selector-class,.hljs-selector-id,.hljs-variable{color:#005cc5}.hljs-meta .hljs-string,.hljs-regexp,.hljs-string{color:#032f62}.hljs-built_in,.hljs-symbol{color:#e36209}.hljs-code,.hljs-comment,.hljs-formula{color:#6a737d}.hljs-name,.hljs-quote,.hljs-selector-pseudo,.hljs-selector-tag{color:#22863a}.hljs-subst{color:#24292e}.hljs-section{color:#005cc5;font-weight:700}.hljs-bullet{color:#735c0f}.hljs-emphasis{color:#24292e;font-style:italic}.hljs-strong{color:#24292e;font-weight:700}.hljs-addition{color:#22863a;background-color:#f0fff4}.hljs-deletion{color:#b31d28;background-color:#ffeef0}}
@media (prefers-color-scheme: dark){.hljs{color:#c9d1d9;background:#0d1117}.hljs-doctag,.hljs-keyword,.hljs-meta .hljs-keyword,.hljs-template-tag,.hljs-template-variable,.hljs-type,.hljs-variable.language_{color:#ff7b72}.hljs-title,.hljs-title.class_,.hljs-title.class_.inherited__,.hljs-title.function_{color:#d2a8ff}.hljs-attr,.hljs-attribute,.hljs-literal,.hljs-meta,.hljs-number,.hljs-operator,.hljs-selector-attr,.hljs-selector-class,.hljs-selector-id,.hljs-variable{color:#79c0ff}.hljs-meta .hljs-string,.hljs-regexp,.hljs-string{color:#a5d6ff}.hljs-built_in,.hljs-symbol{color:#ffa657}.hljs-code,.hljs-comment,.hljs-formula{color:#8b949e}.hljs-name,.hljs-quote,.hljs-selector-pseudo,.hljs-selector-tag{color:#7ee787}.hljs-subst{color:#c9d1d9}.hljs-section{color:#1f6feb;font-weight:700}.hljs-bullet{color:#f2cc60}.hljs-emphasis{color:#c9d1d9;font-style:italic}.hljs-strong{color:#c9d1d9;font-weight:700}.hljs-addition{color:#aff5b4;background-color:#033a16}.hljs-deletion{color:#ffdcd7;background-color:#67060c}}

View File

@@ -10,12 +10,12 @@ lto = true
[dependencies]
leptos = { path = "../../leptos", features = ["csr"] }
console_log = "1.0"
log = "0.4.22"
console_log = "1"
log = "0.4"
console_error_panic_hook = "0.1.7"
gloo-timers = { version = "0.3.0", features = ["futures"] }
[dev-dependencies]
wasm-bindgen = "0.2.93"
wasm-bindgen-test = "0.3.42"
web-sys = "0.3.70"
wasm-bindgen = "0.2"
wasm-bindgen-test = "0.3.0"
web-sys = "0.3"

View File

@@ -2,8 +2,6 @@
name = "counter_isomorphic"
version = "0.1.0"
edition = "2021"
# std::sync::LazyLock is stabilized in Rust version 1.80.0
rust-version = "1.80.0"
[lib]
crate-type = ["cdylib", "rlib"]
@@ -13,22 +11,23 @@ codegen-units = 1
lto = true
[dependencies]
actix-files = { version = "0.6.6", optional = true }
actix-web = { version = "4.8", optional = true, features = ["macros"] }
broadcaster = "1.0"
console_log = "1.0"
console_error_panic_hook = "0.1.7"
futures = "0.3.30"
actix-files = { version = "0.6", optional = true }
actix-web = { version = "4", optional = true, features = ["macros"] }
broadcaster = "1"
console_log = "1"
console_error_panic_hook = "0.1"
futures = "0.3"
lazy_static = "1"
leptos = { path = "../../leptos" }
leptos_actix = { path = "../../integrations/actix", optional = true }
leptos_router = { path = "../../router" }
log = "0.4.22"
once_cell = "1.19"
gloo-net = { version = "0.6.0" }
wasm-bindgen = "0.2.93"
serde = { version = "1.0", features = ["derive"] }
simple_logger = "5.0"
tracing = { version = "0.1.40", optional = true }
log = "0.4"
once_cell = "1.18"
gloo-net = { version = "0.6" }
wasm-bindgen = "0.2"
serde = { version = "1", features = ["derive"] }
simple_logger = "4.3"
tracing = { version = "0.1", optional = true }
send_wrapper = "0.6.0"
[features]
@@ -47,13 +46,13 @@ denylist = ["actix-files", "actix-web", "leptos_actix"]
skip_feature_sets = [["ssr", "hydrate"]]
[package.metadata.leptos]
# The name used by wasm-bindgen/cargo-leptos for the JS/WASM bundle. Defaults to the crate name
# The name used by wasm-bindgen/cargo-leptos for the JS/WASM bundle. Defaults to the crate name
output-name = "counter_isomorphic"
# The site root folder is where cargo-leptos generate all output. WARNING: all content of this folder will be erased on a rebuild. Use it in your server setup.
# When NOT using cargo-leptos this must be updated to "." or the counters will not work. The above warning still applies if you do switch to cargo-leptos later.
site-root = "target/site"
# The site-root relative folder where all compiled output (JS, WASM and CSS) is written
# Defaults to pkg
# Defaults to pkg
site-pkg-dir = "pkg"
# [Optional] The source CSS file. If it ends with .sass or .scss then it will be compiled by dart-sass into CSS. The CSS is optimized by Lightning CSS before being written to <site-root>/<site-pkg>/app.css
# style-file = "src/styles/tailwind.css"

View File

@@ -10,12 +10,12 @@ use tracing::instrument;
pub mod ssr_imports {
pub use broadcaster::BroadcastChannel;
pub use std::sync::atomic::{AtomicI32, Ordering};
use std::sync::LazyLock;
pub static COUNT: AtomicI32 = AtomicI32::new(0);
pub static COUNT_CHANNEL: LazyLock<BroadcastChannel<i32>> =
LazyLock::new(BroadcastChannel::<i32>::new);
lazy_static::lazy_static! {
pub static ref COUNT_CHANNEL: BroadcastChannel<i32> = BroadcastChannel::new();
}
}
#[server]

View File

@@ -13,6 +13,6 @@ leptos_router = { path = "../../router", features = [] }
console_error_panic_hook = "0.1.7"
[dev-dependencies]
wasm-bindgen = "0.2.93"
wasm-bindgen-test = "0.3.42"
web-sys = "0.3.70"
wasm-bindgen = "0.2"
wasm-bindgen-test = "0.3.0"
web-sys = "0.3"

View File

@@ -14,10 +14,10 @@ console_error_panic_hook = "0.1.7"
[dev-dependencies]
wasm-bindgen = "0.2"
wasm-bindgen-test = "0.3.42"
pretty_assertions = "1.4"
rstest = "0.22.0"
wasm-bindgen-test = "0.3.34"
pretty_assertions = "1.3.0"
rstest = "0.17.0"
[dev-dependencies.web-sys]
features = ["HtmlElement", "XPathResult"]
version = "0.3.70"
version = "0.3.61"

View File

@@ -1,6 +0,0 @@
# Support playwright testing
node_modules/
test-results/
end2end/playwright-report/
playwright/.cache/
pnpm-lock.yaml

View File

@@ -4,10 +4,10 @@ version = "0.1.0"
edition = "2021"
[dependencies]
leptos = { path = "../../leptos", features = ["csr"] }
leptos = { path = "../../leptos", features = ["csr"] }
console_error_panic_hook = "0.1.7"
[dev-dependencies]
wasm-bindgen-test = "0.3.42"
wasm-bindgen = "0.2.93"
web-sys = "0.3.70"
wasm-bindgen-test = "0.3.0"
wasm-bindgen = "0.2"
web-sys = "0.3"

View File

@@ -2,5 +2,4 @@ extend = [
{ path = "../cargo-make/main.toml" },
{ path = "../cargo-make/wasm-test.toml" },
{ path = "../cargo-make/trunk_server.toml" },
{ path = "../cargo-make/playwright-trunk-test.toml" },
]

View File

@@ -1,4 +0,0 @@
node_modules/
/test-results/
/playwright-report/
/playwright/.cache/

View File

@@ -1,83 +0,0 @@
{
"name": "grip",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "grip",
"devDependencies": {
"@playwright/test": "^1.35.1"
}
},
"node_modules/.pnpm/@playwright+test@1.33.0": {
"extraneous": true
},
"node_modules/.pnpm/@types+node@20.2.1/node_modules/@types/node": {
"version": "20.2.1",
"extraneous": true,
"license": "MIT"
},
"node_modules/.pnpm/playwright-core@1.33.0/node_modules/playwright-core": {
"version": "1.33.0",
"extraneous": true,
"license": "Apache-2.0",
"bin": {
"playwright": "cli.js"
},
"engines": {
"node": ">=14"
}
},
"node_modules/@playwright/test": {
"version": "1.35.1",
"resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.35.1.tgz",
"integrity": "sha512-b5YoFe6J9exsMYg0pQAobNDR85T1nLumUYgUTtKm4d21iX2L7WqKq9dW8NGJ+2vX0etZd+Y7UeuqsxDXm9+5ZA==",
"dev": true,
"dependencies": {
"@types/node": "*",
"playwright-core": "1.35.1"
},
"bin": {
"playwright": "cli.js"
},
"engines": {
"node": ">=16"
},
"optionalDependencies": {
"fsevents": "2.3.2"
}
},
"node_modules/@types/node": {
"version": "20.3.1",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.3.1.tgz",
"integrity": "sha512-EhcH/wvidPy1WeML3TtYFGR83UzjxeWRen9V402T8aUGYsCHOmfoisV3ZSg03gAFIbLq8TnWOJ0f4cALtnSEUg==",
"dev": true
},
"node_modules/fsevents": {
"version": "2.3.2",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
"integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
"dev": true,
"hasInstallScript": true,
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
}
},
"node_modules/playwright-core": {
"version": "1.35.1",
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.35.1.tgz",
"integrity": "sha512-pNXb6CQ7OqmGDRspEjlxE49w+4YtR6a3X6mT1hZXeJHWmsEz7SunmvZeiG/+y1yyMZdHnnn73WKYdtV1er0Xyg==",
"dev": true,
"bin": {
"playwright-core": "cli.js"
},
"engines": {
"node": ">=16"
}
}
}
}

View File

@@ -1,10 +0,0 @@
{
"private": "true",
"scripts": {},
"devDependencies": {
"@playwright/test": "^1.46.1"
},
"dependencies": {
"pnpm": "^9.7.1"
}
}

View File

@@ -1,77 +0,0 @@
import { defineConfig, devices } from "@playwright/test";
/**
* Read environment variables from file.
* https://github.com/motdotla/dotenv
*/
// require('dotenv').config();
/**
* See https://playwright.dev/docs/test-configuration.
*/
export default defineConfig({
testDir: "./tests",
/* Run tests in files in parallel */
fullyParallel: true,
/* Fail the build on CI if you accidentally left test.only in the source code. */
forbidOnly: !process.env.DEV,
/* Retry on CI only */
retries: process.env.DEV ? 0 : 10,
/* Opt out of parallel tests on CI. */
workers: process.env.DEV ? 1 : 1,
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
reporter: [["html", { open: "never" }], ["list"]],
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
use: {
/* Base URL to use in actions like `await page.goto('/')`. */
baseURL: "http://127.0.0.1:8080",
/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
trace: "on-first-retry",
},
/* Configure projects for major browsers */
projects: [
{
name: "chromium",
use: { ...devices["Desktop Chrome"] },
},
// {
// name: "firefox",
// use: { ...devices["Desktop Firefox"] },
// },
// {
// name: "webkit",
// use: { ...devices["Desktop Safari"] },
// },
/* Test against mobile viewports. */
// {
// name: 'Mobile Chrome',
// use: { ...devices['Pixel 5'] },
// },
// {
// name: 'Mobile Safari',
// use: { ...devices['iPhone 12'] },
// },
/* Test against branded browsers. */
// {
// name: 'Microsoft Edge',
// use: { ...devices['Desktop Edge'], channel: 'msedge' },
// },
// {
// name: 'Google Chrome',
// use: { ..devices['Desktop Chrome'], channel: 'chrome' },
// },
],
/* Run your local dev server before starting the tests */
// webServer: {
// command: "cd ../ && trunk serve",
// url: "http://127.0.0.1:8080",
// reuseExistingServer: false, //!process.env.CI,
// },
});

View File

@@ -1,19 +0,0 @@
import { test, expect } from "@playwright/test";
import { CountersPage } from "./fixtures/counters_page";
test.describe("Add 1000 Counters", () => {
test("should increase the number of counters", async ({ page }) => {
const ui = new CountersPage(page);
await Promise.all([
await ui.goto(),
await ui.addOneThousandCountersButton.waitFor(),
]);
await ui.addOneThousandCounters();
await ui.addOneThousandCounters();
await ui.addOneThousandCounters();
await expect(ui.counters).toHaveText("3000");
});
});

View File

@@ -1,15 +0,0 @@
import { test, expect } from "@playwright/test";
import { CountersPage } from "./fixtures/counters_page";
test.describe("Add Counter", () => {
test("should increase the number of counters", async ({ page }) => {
const ui = new CountersPage(page);
await ui.goto();
await ui.addCounter();
await ui.addCounter();
await ui.addCounter();
await expect(ui.counters).toHaveText("3");
});
});

View File

@@ -1,18 +0,0 @@
import { test, expect } from "@playwright/test";
import { CountersPage } from "./fixtures/counters_page";
test.describe("Clear Counters", () => {
test("should reset the counts", async ({ page }) => {
const ui = new CountersPage(page);
await ui.goto();
await ui.addCounter();
await ui.addCounter();
await ui.addCounter();
await ui.clearCounters();
await expect(ui.total).toHaveText("0");
await expect(ui.counters).toHaveText("0");
});
});

View File

@@ -1,16 +0,0 @@
import { test, expect } from "@playwright/test";
import { CountersPage } from "./fixtures/counters_page";
test.describe("Decrement Count", () => {
test("should decrease the total count", async ({ page }) => {
const ui = new CountersPage(page);
await ui.goto();
await ui.addCounter();
await ui.decrementCount();
await ui.decrementCount();
await ui.decrementCount();
await expect(ui.total).toHaveText("-3");
});
});

View File

@@ -1,30 +0,0 @@
import { test, expect } from "@playwright/test";
import { CountersPage } from "./fixtures/counters_page";
test.describe("Enter Count", () => {
test("should increase the total count", async ({ page }) => {
const ui = new CountersPage(page);
await ui.goto();
await ui.addCounter();
await ui.enterCount("5");
await expect(ui.total).toHaveText("5");
await expect(ui.counters).toHaveText("1");
});
test("should decrease the total count", async ({ page }) => {
const ui = new CountersPage(page);
await ui.goto();
await ui.addCounter();
await ui.addCounter();
await ui.addCounter();
await ui.enterCount("100");
await ui.enterCount("100", 1);
await ui.enterCount("100", 2);
await ui.enterCount("50", 1);
await expect(ui.total).toHaveText("250");
});
});

View File

@@ -1,98 +0,0 @@
import { expect, Locator, Page } from "@playwright/test";
export class CountersPage {
readonly page: Page;
readonly addCounterButton: Locator;
readonly addOneThousandCountersButton: Locator;
readonly clearCountersButton: Locator;
readonly incrementCountButton: Locator;
readonly counterInput: Locator;
readonly decrementCountButton: Locator;
readonly removeCountButton: Locator;
readonly total: Locator;
readonly counters: Locator;
constructor(page: Page) {
this.page = page;
this.addCounterButton = page.locator("button", { hasText: "Add Counter" });
this.addOneThousandCountersButton = page.locator("button", {
hasText: "Add 1000 Counters",
});
this.clearCountersButton = page.locator("button", {
hasText: "Clear Counters",
});
this.decrementCountButton = page.locator("button", {
hasText: "-1",
});
this.incrementCountButton = page.locator("button", {
hasText: "+1",
});
this.removeCountButton = page.locator("button", {
hasText: "x",
});
this.total = page.getByTestId("total");
this.counters = page.getByTestId("counters");
this.counterInput = page.getByRole("textbox");
}
async goto() {
await this.page.goto("/");
}
async addCounter() {
await Promise.all([
this.addCounterButton.waitFor(),
this.addCounterButton.click(),
]);
}
async addOneThousandCounters() {
this.addOneThousandCountersButton.click();
}
async decrementCount(index: number = 0) {
await Promise.all([
this.decrementCountButton.nth(index).waitFor(),
this.decrementCountButton.nth(index).click(),
]);
}
async incrementCount(index: number = 0) {
await Promise.all([
this.incrementCountButton.nth(index).waitFor(),
this.incrementCountButton.nth(index).click(),
]);
}
async clearCounters() {
await Promise.all([
this.clearCountersButton.waitFor(),
this.clearCountersButton.click(),
]);
}
async enterCount(count: string, index: number = 0) {
await Promise.all([
this.counterInput.nth(index).waitFor(),
this.counterInput.nth(index).fill(count),
]);
}
async removeCounter(index: number = 0) {
await Promise.all([
this.removeCountButton.nth(index).waitFor(),
this.removeCountButton.nth(index).click(),
]);
}
}

View File

@@ -1,16 +0,0 @@
import { test, expect } from "@playwright/test";
import { CountersPage } from "./fixtures/counters_page";
test.describe("Increment Count", () => {
test("should increase the total count", async ({ page }) => {
const ui = new CountersPage(page);
await ui.goto();
await ui.addCounter();
await ui.incrementCount();
await ui.incrementCount();
await ui.incrementCount();
await expect(ui.total).toHaveText("3");
});
});

View File

@@ -1,17 +0,0 @@
import { test, expect } from "@playwright/test";
import { CountersPage } from "./fixtures/counters_page";
test.describe("Remove Counter", () => {
test("should decrement the number of counters", async ({ page }) => {
const ui = new CountersPage(page);
await ui.goto();
await ui.addCounter();
await ui.addCounter();
await ui.addCounter();
await ui.removeCounter(1);
await expect(ui.counters).toHaveText("2");
});
});

View File

@@ -1,19 +0,0 @@
import { test, expect } from "@playwright/test";
import { CountersPage } from "./fixtures/counters_page";
test.describe("View Counters", () => {
test("should see the title", async ({ page }) => {
const ui = new CountersPage(page);
await ui.goto();
await expect(page).toHaveTitle("Counters");
});
test("should see the initial counts", async ({ page }) => {
const counters = new CountersPage(page);
await counters.goto();
await expect(counters.total).toHaveText("0");
await expect(counters.counters).toHaveText("0");
});
});

View File

@@ -2,7 +2,6 @@
<html>
<head>
<link data-trunk rel="rust" data-wasm-opt="z" data-weak-refs/>
<title>Counters</title>
</head>
<body></body>
</html>
</html>

View File

@@ -1,4 +1,4 @@
use leptos::prelude::*;
use leptos::prelude::{signal::*, *};
const MANY_COUNTERS: usize = 1000;
@@ -44,13 +44,12 @@ pub fn Counters() -> impl IntoView {
<button on:click=clear_counters>"Clear Counters"</button>
<p>
"Total: "
<span data-testid="total">
<span>
{move || {
counters.get().iter().map(|(_, count)| count.get()).sum::<i32>().to_string()
}}
</span> " from "
<span data-testid="counters">{move || counters.get().len().to_string()}</span>
</span> " from " <span>{move || counters.get().len().to_string()}</span>
" counters."
</p>
<ul>

View File

@@ -23,7 +23,7 @@ async fn inc() {
div.inner_html(),
"<button>Add Counter</button><button>Add 1000 \
Counters</button><button>Clear Counters</button><p>Total: \
<span data-testid=\"total\">0</span> from <span data-testid=\"counters\">0</span> counters.</p><ul><!----></ul>"
<span>0</span> from <span>0</span> counters.</p><ul><!----></ul>"
);
// add 3 counters
@@ -38,7 +38,7 @@ async fn inc() {
div.inner_html(),
"<button>Add Counter</button><button>Add 1000 \
Counters</button><button>Clear Counters</button><p>Total: \
<span data-testid=\"total\">0</span> from <span data-testid=\"counters\">3</span> \
<span>0</span> from <span>3</span> \
counters.</p><ul><li><button>-1</button><input \
type=\"text\"><span>0</span><button>+1</button><button>x</button></\
li><li><button>-1</button><input \
@@ -80,7 +80,7 @@ async fn inc() {
div.inner_html(),
"<button>Add Counter</button><button>Add 1000 \
Counters</button><button>Clear Counters</button><p>Total: \
<span data-testid=\"total\">6</span> from <span data-testid=\"counters\">3</span> \
<span>6</span> from <span>3</span> \
counters.</p><ul><li><button>-1</button><input \
type=\"text\"><span>1</span><button>+1</button><button>x</button></\
li><li><button>-1</button><input \
@@ -105,7 +105,7 @@ async fn inc() {
div.inner_html(),
"<button>Add Counter</button><button>Add 1000 \
Counters</button><button>Clear Counters</button><p>Total: \
<span data-testid=\"total\">5</span> from <span data-testid=\"counters\">2</span> \
<span>5</span> from <span>2</span> \
counters.</p><ul><li><button>-1</button><input \
type=\"text\"><span>2</span><button>+1</button><button>x</button></\
li><li><button>-1</button><input \

View File

@@ -5,12 +5,12 @@ edition = "2021"
[dependencies]
leptos = { path = "../../leptos", features = ["csr"] }
log = "0.4.22"
console_log = "1.0"
log = "0.4"
console_log = "1"
console_error_panic_hook = "0.1.7"
web-sys = { version = "0.3.70", features = ["Clipboard", "Navigator"] }
web-sys = { version = "0.3", features = ["Clipboard", "Navigator"] }
[dev-dependencies]
wasm-bindgen-test = "0.3.42"
wasm-bindgen = "0.2.93"
web-sys = { version = "0.3.70", features = ["NodeList"] }
wasm-bindgen-test = "0.3.0"
wasm-bindgen = "0.2"
web-sys = { version = "0.3", features = ["NodeList"] }

View File

@@ -24,7 +24,11 @@ pub fn copy_to_clipboard(el: Element, content: &str) {
evt.prevent_default();
evt.stop_propagation();
let _ = window().navigator().clipboard().write_text(&content);
let _ = window()
.navigator()
.clipboard()
.expect("navigator.clipboard to be available")
.write_text(&content);
el.set_inner_html(&format!("Copied \"{}\"", &content));
});
@@ -49,6 +53,7 @@ impl From<()> for Amount {
}
}
// .into() will automatically be called on the parameter
pub fn add_dot(el: Element, amount: Amount) {
use leptos::wasm_bindgen::JsCast;
let el = el.unchecked_into::<web_sys::HtmlElement>();
@@ -77,17 +82,12 @@ pub fn App() -> impl IntoView {
let data = "Hello World!";
view! {
<a href="#" use:copy_to_clipboard=data>
"Copy \""
{data}
"\" to clipboard"
</a>
<a href="#" use:copy_to_clipboard=data>"Copy \"" {data} "\" to clipboard"</a>
// automatically applies the directive to every root element in `SomeComponent`
<SomeComponent use:highlight/>
<SomeComponent use:highlight />
// no value will default to `().into()`
<button use:add_dot>"Add a dot"</button>
// can manually call `.into()` to convert to the correct type
// (automatically calling `.into()` prevents using generics in directive functions)
<button use:add_dot=5.into()>"Add 5 dots"</button>
// `5.into()` automatically called
<button use:add_dot=5>"Add 5 dots"</button>
}
}

View File

@@ -9,6 +9,6 @@ lto = true
[dependencies]
leptos = { path = "../../leptos", features = ["csr"] }
console_log = "1.0"
log = "0.4.22"
console_log = "1"
log = "0.4"
console_error_panic_hook = "0.1.7"

View File

@@ -7,19 +7,19 @@ edition = "2021"
crate-type = ["cdylib", "rlib"]
[dependencies]
console_error_panic_hook = "0.1.7"
console_error_panic_hook = "0.1"
leptos = { path = "../../leptos" }
leptos_axum = { path = "../../integrations/axum", optional = true }
leptos_meta = { path = "../../meta" }
leptos_router = { path = "../../router" }
serde = { version = "1.0", features = ["derive"] }
axum = { version = "0.7.5", optional = true }
tower = { version = "0.4.13", optional = true }
tower-http = { version = "0.5.2", features = ["fs"], optional = true }
tokio = { version = "1.39", features = ["full"], optional = true }
http = { version = "1.1" }
serde = { version = "1", features = ["derive"] }
axum = { version = "0.7", optional = true }
tower = { version = "0.4", optional = true }
tower-http = { version = "0.5", features = ["fs"], optional = true }
tokio = { version = "1", features = ["full"], optional = true }
http = { version = "1.0" }
thiserror = "1.0"
wasm-bindgen = "0.2.93"
wasm-bindgen = "0.2"
[features]
hydrate = ["leptos/hydrate"]

View File

@@ -9,16 +9,16 @@ lto = true
[dependencies]
leptos = { path = "../../leptos", features = ["csr", "tracing"] }
reqwasm = "0.5.0"
gloo-timers = { version = "0.3.0", features = ["futures"] }
serde = { version = "1.0", features = ["derive"] }
log = "0.4.22"
console_log = "1.0"
console_error_panic_hook = "0.1.7"
thiserror = "1.0"
tracing = "0.1.40"
tracing-subscriber = "0.3.18"
tracing-subscriber-wasm = "0.1.0"
reqwasm = "0.5"
gloo-timers = { version = "0.3", features = ["futures"] }
serde = { version = "1", features = ["derive"] }
log = "0.4"
console_log = "1"
console_error_panic_hook = "0.1"
thiserror = "1"
tracing = "0.1"
tracing-subscriber = "0.3"
tracing-subscriber-wasm = "0.1"
[dev-dependencies]
wasm-bindgen-test = "0.3.42"
wasm-bindgen-test = "0.3"

View File

@@ -4,15 +4,15 @@ version = "0.1.0"
edition = "2021"
[dependencies]
leptos = { path = "../../leptos" }
leptos = { path = "../../leptos", features = ["csr"] }
throw_error = { path = "../../any_error/" }
# these are used to build the integration
gtk = { version = "0.9.0", package = "gtk4" }
any_spawner = { path = "../../any_spawner/" }
next_tuple = { path = "../../next_tuple/" }
paste = "1.0"
gtk = { version = "0.8.0", package = "gtk4", optional = true }
paste = "1.0.14"
# we want to support using glib for the reactive runtime event loop
any_spawner = { path = "../../any_spawner/", features = ["glib"] }
# yes, we want effects to run: this is a "frontend," not a backend
reactive_graph = { path = "../../reactive_graph", features = ["effects"] }
console_error_panic_hook = { version = "0.1", optional = true }
[features]
gtk = ["dep:gtk", "any_spawner/glib"]
wasm = ["any_spawner/wasm-bindgen", "dep:console_error_panic_hook"]

View File

@@ -1 +0,0 @@
extend = [{ path = "../cargo-make/main.toml" }]

View File

@@ -1,5 +1,6 @@
use self::properties::Connect;
use gtk::{
ffi::GtkWidget,
glib::{
object::{IsA, IsClass, ObjectExt},
Object, Value,
@@ -15,7 +16,7 @@ use leptos::{
},
};
use next_tuple::NextTuple;
use std::marker::PhantomData;
use std::{borrow::Cow, marker::PhantomData};
#[derive(Debug)]
pub struct LeptosGtk;
@@ -55,12 +56,11 @@ impl Mountable<LeptosGtk> for Element {
.insert_before(&parent.0, marker.as_ref().map(|m| &m.0));
}
fn insert_before_this(&self, child: &mut dyn Mountable<LeptosGtk>) -> bool {
if let Some(parent) = self.0.parent() {
child.mount(&Element(parent), Some(self));
return true;
}
false
fn insert_before_this(&self,
child: &mut dyn Mountable<LeptosGtk>,
) -> bool {
child.mount(parent, Some(self.as_ref()));
true
}
}
@@ -79,8 +79,11 @@ impl Mountable<LeptosGtk> for Text {
.insert_before(&parent.0, marker.as_ref().map(|m| &m.0));
}
fn insert_before_this(&self, child: &mut dyn Mountable<LeptosGtk>) -> bool {
self.0.insert_before_this(child)
fn insert_before_this(&self,
child: &mut dyn Mountable<LeptosGtk>,
) -> bool {
child.mount(parent, Some(self.as_ref()));
true
}
}
@@ -156,13 +159,13 @@ impl Renderer for LeptosGtk {
}
fn remove_node(
_parent: &Self::Element,
_child: &Self::Node,
parent: &Self::Element,
child: &Self::Node,
) -> Option<Self::Node> {
todo!()
}
fn remove(_node: &Self::Node) {
fn remove(node: &Self::Node) {
todo!()
}
@@ -170,19 +173,19 @@ impl Renderer for LeptosGtk {
node.0.parent().map(Element::from)
}
fn first_child(_node: &Self::Node) -> Option<Self::Node> {
fn first_child(node: &Self::Node) -> Option<Self::Node> {
todo!()
}
fn next_sibling(_node: &Self::Node) -> Option<Self::Node> {
fn next_sibling(node: &Self::Node) -> Option<Self::Node> {
todo!()
}
fn log_node(node: &Self::Node) {
println!("{node:?}");
todo!()
}
fn clear_children(_parent: &Self::Element) {
fn clear_children(parent: &Self::Element) {
todo!()
}
}
@@ -329,12 +332,16 @@ where
parent: &<LeptosGtk as Renderer>::Element,
marker: Option<&<LeptosGtk as Renderer>::Node>,
) {
println!("mounting {}", std::any::type_name::<Widg>());
self.children.mount(&self.widget, None);
LeptosGtk::insert_node(parent, &self.widget, marker);
}
fn insert_before_this(&self, child: &mut dyn Mountable<LeptosGtk>) -> bool {
self.widget.insert_before_this(child)
fn insert_before_this(&self,
child: &mut dyn Mountable<LeptosGtk>,
) -> bool {
child.mount(parent, Some(self.widget.as_ref()));
true
}
}
@@ -367,22 +374,7 @@ where
})
}
fn rebuild(self, widget: &Element, state: &mut Self::State) {
let prev_value = state.take_value();
let widget = widget.to_owned();
*state = RenderEffect::new_with_value(
move |prev| {
let value = self();
if let Some(mut state) = prev {
value.rebuild(&widget, &mut state);
state
} else {
unreachable!()
}
},
prev_value,
);
}
fn rebuild(self, widget: &Element, state: &mut Self::State) {}
}
pub fn button() -> LGtkWidget<gtk::Button, (), ()> {
@@ -414,9 +406,9 @@ mod widgets {
}
pub mod properties {
#![allow(dead_code)]
use super::{Element, LGtkWidget, LeptosGtk, Property, WidgetClass};
use super::{
Element, LGtkWidget, LGtkWidgetState, LeptosGtk, Property, WidgetClass,
};
use gtk::glib::{object::ObjectExt, Value};
use leptos::tachys::{renderer::Renderer, view::Render};
use next_tuple::NextTuple;
@@ -439,9 +431,7 @@ pub mod properties {
element.0.connect(self.signal_name, false, self.callback);
}
fn rebuild(self, _element: &Element, _state: &mut Self::State) {
// TODO we want to *remove* the previous listener, and reconnect with this new one
}
fn rebuild(self, element: &Element, state: &mut Self::State) {}
}
/* examples for macro */
@@ -544,7 +534,7 @@ pub mod properties {
}
/* end examples for properties macro */
#[derive(Debug)]
pub struct Label {
value: String,
}
@@ -570,9 +560,7 @@ pub mod properties {
}
fn rebuild(self, element: &Element, state: &mut Self::State) {
if self.value != state.value {
LeptosGtk::set_attribute(element, "label", &self.value);
}
todo!()
}
}

View File

@@ -1,8 +1,20 @@
use any_spawner::Executor;
use gtk::{prelude::*, Application, ApplicationWindow, Orientation};
use leptos::prelude::*;
use leptos_gtk::LeptosGtk;
#[cfg(feature = "gtk")]
use gtk::{
glib::Value, prelude::*, Application, ApplicationWindow, Orientation,
Widget,
};
#[cfg(feature = "wasm")]
use leptos::tachys::{dom::body, html::element, html::event as ev};
use leptos::{
logging,
prelude::*,
reactive_graph::{effect::Effect, owner::Owner, signal::RwSignal},
Executor, For, ForProps,
};
#[cfg(feature = "gtk")]
use leptos_gtk::{Element, LGtkWidget, LeptosGtk};
use std::{mem, thread, time::Duration};
#[cfg(feature = "gtk")]
mod leptos_gtk;
const APP_ID: &str = "dev.leptos.Counter";
@@ -10,39 +22,59 @@ const APP_ID: &str = "dev.leptos.Counter";
// Basic GTK app setup from https://gtk-rs.org/gtk4-rs/stable/latest/book/hello_world.html
fn main() {
// use the glib event loop to power the reactive system
_ = Executor::init_glib();
let app = Application::builder().application_id(APP_ID).build();
#[cfg(feature = "gtk")]
{
_ = Executor::init_glib();
let app = Application::builder().application_id(APP_ID).build();
app.connect_startup(|_| load_css());
app.connect_startup(|_| load_css());
app.connect_activate(|app| {
// Connect to "activate" signal of `app`
app.connect_activate(|app| {
// Connect to "activate" signal of `app`
let owner = Owner::new();
let view = owner.with(ui);
let (root, state) = leptos_gtk::root(view);
let window = ApplicationWindow::builder()
.application(app)
.title("TachyGTK")
.child(&root)
.build();
// Present window
window.present();
mem::forget((owner, state));
});
app.run();
}
#[cfg(all(feature = "wasm", not(feature = "gtk")))]
{
console_error_panic_hook::set_once();
_ = Executor::init_wasm_bindgen();
let owner = Owner::new();
let view = owner.with(ui);
let (root, state) = leptos_gtk::root(view);
let window = ApplicationWindow::builder()
.application(app)
.title("TachyGTK")
.child(&root)
.build();
// Present window
window.present();
let mut state = view.build();
state.mount(&body().into(), None);
mem::forget((owner, state));
});
app.run();
}
}
fn ui() -> impl Render<LeptosGtk> {
#[cfg(feature = "gtk")]
type Rndr = LeptosGtk;
#[cfg(all(feature = "wasm", not(feature = "gtk")))]
type Rndr = Dom;
fn ui() -> impl Render<Rndr> {
let value = RwSignal::new(0);
let rows = RwSignal::new(vec![1, 2, 3, 4, 5]);
Effect::new(move |_| {
println!("value = {}", value.get());
logging::log!("value = {}", value.get());
});
// just an example of multithreaded reactivity
#[cfg(feature = "gtk")]
thread::spawn(move || loop {
thread::sleep(Duration::from_millis(250));
value.update(|n| *n += 1);
@@ -50,10 +82,7 @@ fn ui() -> impl Render<LeptosGtk> {
vstack((
hstack((
button("-1", move || {
println!("clicked -1");
value.update(|n| *n -= 1);
}),
button("-1", move || value.update(|n| *n -= 1)),
move || value.get().to_string(),
button("+1", move || value.update(|n| *n += 1)),
)),
@@ -62,36 +91,75 @@ fn ui() -> impl Render<LeptosGtk> {
items.swap(1, 3);
})
}),
hstack(rows),
hstack(For(ForProps::builder()
.each(move || rows.get())
.key(|k| *k)
.children(|v| v)
.build())),
))
}
fn button(
label: impl Render<LeptosGtk>,
label: impl Render<Rndr>,
callback: impl Fn() + Send + Sync + 'static,
) -> impl Render<LeptosGtk> {
leptos_gtk::button()
.child(label)
.connect("clicked", move |_| {
callback();
None
})
) -> impl Render<Rndr> {
#[cfg(feature = "gtk")]
{
leptos_gtk::button()
.child(label)
.connect("clicked", move |_| {
callback();
None
})
}
#[cfg(all(feature = "wasm", not(feature = "gtk")))]
{
element::button()
.on(ev::click, move |_| callback())
.child(label)
}
}
fn vstack(children: impl Render<LeptosGtk>) -> impl Render<LeptosGtk> {
leptos_gtk::r#box()
.orientation(Orientation::Vertical)
.spacing(12)
.child(children)
fn vstack(children: impl Render<Rndr>) -> impl Render<Rndr> {
#[cfg(feature = "gtk")]
{
leptos_gtk::r#box()
.orientation(Orientation::Vertical)
.spacing(12)
.child(children)
}
#[cfg(all(feature = "wasm", not(feature = "gtk")))]
{
element::div()
.style(("display", "flex"))
.style(("flex-direction", "column"))
.style(("align-items", "center"))
.style(("justify-content", "center"))
.style(("margin", "1rem"))
.child(children)
}
}
fn hstack(children: impl Render<LeptosGtk>) -> impl Render<LeptosGtk> {
leptos_gtk::r#box()
.orientation(Orientation::Horizontal)
.spacing(12)
.child(children)
fn hstack(children: impl Render<Rndr>) -> impl Render<Rndr> {
#[cfg(feature = "gtk")]
{
leptos_gtk::r#box()
.orientation(Orientation::Horizontal)
.spacing(12)
.child(children)
}
#[cfg(all(feature = "wasm", not(feature = "gtk")))]
{
element::div()
.style(("display", "flex"))
.style(("align-items", "center"))
.style(("justify-content", "center"))
.style(("margin", "1rem"))
.child(children)
}
}
#[cfg(feature = "gtk")]
fn load_css() {
use gtk::{gdk::Display, CssProvider};

View File

@@ -13,24 +13,23 @@ panic = "abort"
lto = true
[dependencies]
actix-files = { version = "0.6.6", optional = true }
actix-web = { version = "4.8", optional = true, features = ["macros"] }
console_log = "1.0"
console_error_panic_hook = "0.1.7"
actix-files = { version = "0.6", optional = true }
actix-web = { version = "4", optional = true, features = ["macros"] }
console_log = "1"
console_error_panic_hook = "0.1"
leptos = { path = "../../leptos" }
leptos_meta = { path = "../../meta" }
leptos_actix = { path = "../../integrations/actix", optional = true }
leptos_router = { path = "../../router" }
log = "0.4.22"
serde = { version = "1.0", features = ["derive"] }
gloo-net = { version = "0.6.0", features = ["http"] }
reqwest = { version = "0.12.5", features = ["json"] }
wasm-bindgen = "0.2.93"
web-sys = { version = "0.3.70", features = ["AbortController", "AbortSignal"] }
log = "0.4"
serde = { version = "1", features = ["derive"] }
gloo-net = { version = "0.6", features = ["http"] }
reqwest = { version = "0.12", features = ["json"] }
wasm-bindgen = "0.2"
web-sys = { version = "0.3", features = ["AbortController", "AbortSignal"] }
send_wrapper = "0.6.0"
[features]
default = ["csr"]
csr = ["leptos/csr"]
hydrate = ["leptos/hydrate"]
ssr = ["dep:actix-files", "dep:actix-web", "dep:leptos_actix", "leptos/ssr"]

View File

@@ -11,22 +11,22 @@ codegen-units = 1
lto = true
[dependencies]
console_error_panic_hook = "0.1.7"
console_error_panic_hook = "0.1"
leptos = { path = "../../leptos" }
leptos_axum = { path = "../../integrations/axum", optional = true }
leptos_meta = { path = "../../meta" }
leptos_router = { path = "../../router" }
serde = { version = "1.0", features = ["derive"] }
tracing = "0.1.40"
gloo-net = { version = "0.6.0", features = ["http"] }
reqwest = { version = "0.12.5", features = ["json"] }
axum = { version = "0.7.5", optional = true }
tower = { version = "0.4.13", optional = true }
tower-http = { version = "0.5.2", features = ["fs"], optional = true }
tokio = { version = "1.39", features = ["full"], optional = true }
http = { version = "1.1", optional = true }
web-sys = { version = "0.3.70", features = ["AbortController", "AbortSignal"] }
wasm-bindgen = "0.2.93"
tracing = "0.1"
gloo-net = { version = "0.6", features = ["http"] }
reqwest = { version = "0.12", features = ["json"] }
axum = { version = "0.7", optional = true }
tower = { version = "0.4", optional = true }
tower-http = { version = "0.5", features = ["fs"], optional = true }
tokio = { version = "1", features = ["full"], optional = true }
http = { version = "1.0", optional = true }
web-sys = { version = "0.3", features = ["AbortController", "AbortSignal"] }
wasm-bindgen = "0.2"
send_wrapper = { version = "0.6.0", features = ["futures"] }
[features]

View File

@@ -11,34 +11,36 @@ codegen-units = 1
lto = true
[dependencies]
console_error_panic_hook = "0.1.7"
console_error_panic_hook = "0.1"
leptos = { path = "../../leptos", features = ["experimental-islands"] }
leptos_axum = { path = "../../integrations/axum", optional = true }
leptos_meta = { path = "../../meta" }
leptos_router = { path = "../../router" }
serde = { version = "1.0", features = ["derive"] }
tracing = "0.1.40"
gloo-net = { version = "0.6.0", features = ["http"] }
reqwest = { version = "0.12.5", features = ["json"] }
axum = { version = "0.7.5", optional = true, features = ["http2"] }
tower = { version = "0.4.13", optional = true }
tower-http = { version = "0.5.2", features = [
tracing = "0.1"
gloo-net = { version = "0.6", features = ["http"] }
reqwest = { version = "0.12", features = ["json"] }
axum = { version = "0.7", optional = true, features = ["http2"] }
tower = { version = "0.4", optional = true }
tower-http = { version = "0.5", features = [
"fs",
"compression-gzip",
"compression-br",
], optional = true }
tokio = { version = "1.39", features = ["full"], optional = true }
http = { version = "1.1", optional = true }
web-sys = { version = "0.3.70", features = ["AbortController", "AbortSignal"] }
wasm-bindgen = "0.2.93"
rust-embed = { version = "8.5", features = [
tokio = { version = "1", features = ["full"], optional = true }
http = { version = "1.0", optional = true }
web-sys = { version = "0.3", features = ["AbortController", "AbortSignal"] }
wasm-bindgen = "0.2"
lazy_static = "1.4.0"
rust-embed = { version = "8", features = [
"axum",
"mime_guess",
"tokio",
], optional = true }
mime_guess = { version = "2.0", optional = true }
mime_guess = { version = "2.0.4", optional = true }
[features]
default = []
csr = ["leptos/csr"]
hydrate = ["leptos/hydrate"]
ssr = [

View File

@@ -11,30 +11,30 @@ codegen-units = 1
lto = true
[dependencies]
console_error_panic_hook = "0.1.7"
console_error_panic_hook = "0.1"
console_log = "1.0"
log = "0.4.22"
log = "0.4"
leptos = { path = "../../leptos" }
leptos_axum = { path = "../../integrations/axum", default-features = false, optional = true }
leptos_meta = { path = "../../meta" }
leptos_router = { path = "../../router" }
leptos_server = { path = "../../leptos_server", optional = true }
serde = { version = "1.0", features = ["derive"] }
tracing = "0.1.40"
gloo-net = { version = "0.6.0", features = ["http"] }
reqwest = { version = "0.12.5", features = ["json"] }
axum = { version = "0.7.5", default-features = false, optional = true }
tower = { version = "0.4.13", optional = true }
http = { version = "1.1", optional = true }
web-sys = { version = "0.3.70", features = [
tracing = "0.1"
gloo-net = { version = "0.6", features = ["http"] }
reqwest = { version = "0.12", features = ["json"] }
axum = { version = "0.7", default-features = false, optional = true }
tower = { version = "0.4", optional = true }
http = { version = "1.0", optional = true }
web-sys = { version = "0.3", features = [
"AbortController",
"AbortSignal",
"Request",
"Response",
] }
getrandom = { version = "0.2.15", features = ["js"] }
wasm-bindgen = "0.2.93"
wasm-bindgen-futures = { version = "0.4.42", features = [
getrandom = { version = "0.2.7", features = ["js"] }
wasm-bindgen = "0.2"
wasm-bindgen-futures = { version = "0.4.37", features = [
"futures-core-03-stream",
], optional = true }
axum-js-fetch = { git = "https://github.com/seanaye/axum-js-fetch", optional = true }

View File

@@ -7,32 +7,32 @@ edition = "2021"
crate-type = ["cdylib", "rlib"]
[dependencies]
console_error_panic_hook = "0.1.7"
futures = "0.3.30"
http = "1.1"
console_error_panic_hook = "0.1"
futures = "0.3"
http = "1.0"
leptos = { path = "../../leptos", features = [
"tracing",
"experimental-islands",
"tracing",
"experimental-islands",
] }
server_fn = { path = "../../server_fn", features = ["serde-lite"] }
leptos_axum = { path = "../../integrations/axum", optional = true }
log = "0.4.22"
serde = { version = "1.0", features = ["derive"] }
axum = { version = "0.7.5", optional = true }
tower = { version = "0.4.13", optional = true }
tower-http = { version = "0.5.2", features = ["fs"], optional = true }
tokio = { version = "1.39", features = ["full"], optional = true }
wasm-bindgen = "0.2.93"
log = "0.4"
serde = { version = "1", features = ["derive"] }
axum = { version = "0.7", optional = true }
tower = { version = "0.4", optional = true }
tower-http = { version = "0.5", features = ["fs"], optional = true }
tokio = { version = "1", features = ["full"], optional = true }
wasm-bindgen = "0.2"
[features]
hydrate = ["leptos/hydrate"]
ssr = [
"dep:axum",
"dep:tower",
"dep:tower-http",
"dep:tokio",
"leptos/ssr",
"dep:leptos_axum",
"dep:axum",
"dep:tower",
"dep:tower-http",
"dep:tokio",
"leptos/ssr",
"dep:leptos_axum",
]
[profile.wasm-release]

View File

@@ -7,35 +7,33 @@ edition = "2021"
crate-type = ["cdylib", "rlib"]
[dependencies]
console_error_panic_hook = "0.1.7"
futures = "0.3.30"
http = "1.1"
console_error_panic_hook = "0.1"
futures = "0.3"
http = "1.0"
leptos = { path = "../../leptos", features = [
"tracing",
"experimental-islands",
"tracing",
"experimental-islands",
] }
leptos_router = { path = "../../router" }
server_fn = { path = "../../server_fn", features = ["serde-lite"] }
leptos_axum = { path = "../../integrations/axum", features = [
"islands-router",
], optional = true }
log = "0.4.22"
serde = { version = "1.0", features = ["derive"] }
axum = { version = "0.7.5", optional = true }
tower = { version = "0.4.13", optional = true }
tower-http = { version = "0.5.2", features = ["fs"], optional = true }
tokio = { version = "1.39", features = ["full"], optional = true }
wasm-bindgen = "0.2.93"
leptos_axum = { path = "../../integrations/axum", features = ["islands-router"], optional = true }
log = "0.4"
serde = { version = "1", features = ["derive"] }
axum = { version = "0.7", optional = true }
tower = { version = "0.4", optional = true }
tower-http = { version = "0.5", features = ["fs"], optional = true }
tokio = { version = "1", features = ["full"], optional = true }
wasm-bindgen = "0.2"
[features]
hydrate = ["leptos/hydrate"]
ssr = [
"dep:axum",
"dep:tower",
"dep:tower-http",
"dep:tokio",
"leptos/ssr",
"dep:leptos_axum",
"dep:axum",
"dep:tower",
"dep:tower-http",
"dep:tokio",
"leptos/ssr",
"dep:leptos_axum",
]
[profile.wasm-release]

View File

@@ -8,13 +8,13 @@ codegen-units = 1
lto = true
[dependencies]
leptos = { path = "../../leptos", features = ["csr"] } # for actual benchmarking, add `nightly` and `delegation` features
leptos = { path = "../../leptos", features = ["csr"] } # for actual benchmarking, add `nightly` and `event-delegation` features
# used in rand, but we need to enable js feature
getrandom = { version = "0.2.15", features = ["js"] }
getrandom = { version = "0.2.7", features = ["js"] }
rand = { version = "0.8.5", features = ["small_rng"] }
console_error_panic_hook = "0.1.7"
[dev-dependencies]
wasm-bindgen = "0.2"
wasm-bindgen-test = "0.3.42"
wasm-bindgen-test = "0.3.0"
web-sys = "0.3"

View File

@@ -162,24 +162,22 @@ pub fn App() -> impl IntoView {
<table class="table table-hover table-striped test-data">
<tbody>
<For
each=move || data.get()
key=|row| row.id
each={move || data.get()}
key={|row| row.id}
children=move |row: RowData| {
let row_id = row.id;
let label = row.label;
let is_selected = is_selected.clone();
template! {
< tr class : danger = { move || is_selected.selected(Some(row_id)) }
> < td class = "col-md-1" > { row_id.to_string() } </ td > < td
class = "col-md-4" >< a on : click = move | _ | set_selected
.set(Some(row_id)) > { move || label.get() } </ a ></ td > < td
class = "col-md-1" >< a on : click = move | _ | remove(row_id) ><
span class = "glyphicon glyphicon-remove" aria - hidden = "true" ></
span ></ a ></ td > < td class = "col-md-6" /> </ tr >
}
ViewTemplate::new(view! {
<tr class:danger={move || is_selected.selected(Some(row_id))}>
<td class="col-md-1">{row_id.to_string()}</td>
<td class="col-md-4"><a on:click=move |_| set_selected.set(Some(row_id))>{move || label.get()}</a></td>
<td class="col-md-1"><a on:click=move |_| remove(row_id)><span class="glyphicon glyphicon-remove" aria-hidden="true"></span></a></td>
<td class="col-md-6"/>
</tr>
})
}
/>
</tbody>
</table>
<span class="preloadicon glyphicon glyphicon-remove" aria-hidden="true"></span>

View File

@@ -9,7 +9,7 @@ lto = true
[dependencies]
leptos = { path = "../../leptos", features = ["csr"] }
console_log = "1.0"
log = "0.4.22"
console_log = "1"
log = "0.4"
console_error_panic_hook = "0.1.7"
web-sys = "0.3.70"
web-sys = "0.3"

View File

@@ -5,12 +5,12 @@ edition = "2021"
[dependencies]
leptos = { path = "../../leptos", features = ["csr"] }
log = "0.4.22"
console_log = "1.0"
log = "0.4"
console_log = "1"
console_error_panic_hook = "0.1.7"
wasm-bindgen = "0.2.93"
wasm-bindgen = "0.2"
[dev-dependencies]
wasm-bindgen-test = "0.3.42"
wasm-bindgen = "0.2.93"
web-sys = "0.3.70"
wasm-bindgen-test = "0.3.0"
wasm-bindgen = "0.2"
web-sys = "0.3"

View File

@@ -10,16 +10,16 @@ codegen-units = 1
panic = "abort"
[dependencies]
console_log = "1.0"
console_log = "1"
leptos = { path = "../../leptos", features = ["csr", "tracing"] }
leptos_router = { path = "../../router" } #, features = ["tracing"] }
leptos_router = { path = "../../router" } #, features = ["tracing"] }
leptos_router_macro = { path = "../../router_macro" }
serde = { version = "1.0", features = ["derive"] }
futures = "0.3.30"
serde = { version = "1", features = ["derive"] }
futures = "0.3"
console_error_panic_hook = "0.1.7"
tracing-subscriber = "0.3.18"
tracing-subscriber-wasm = "0.1.0"
tracing = "0.1.40"
[dev-dependencies]
wasm-bindgen-test = "0.3.42"
wasm-bindgen-test = "0.3.0"

View File

@@ -72,7 +72,6 @@ pub fn ContactRoutes() -> impl MatchNestedRoutes<Dom> + Clone {
<Route path=path!("/:id") view=Contact/>
</ParentRoute>
}
.into_inner()
}
#[component]

View File

@@ -7,53 +7,44 @@ edition = "2021"
crate-type = ["cdylib", "rlib"]
[dependencies]
console_error_panic_hook = "0.1.7"
futures = "0.3.30"
http = "1.1"
console_error_panic_hook = "0.1"
futures = "0.3"
http = "1.0"
leptos = { path = "../../leptos" }
leptos_axum = { path = "../../integrations/axum", optional = true }
server_fn = { path = "../../server_fn", features = [
"serde-lite",
"rkyv",
"multipart",
"postcard",
] }
log = "0.4.22"
simple_logger = "5.0"
serde = { version = "1.0", features = ["derive"] }
axum = { version = "0.7.5", optional = true }
tower = { version = "0.4.13", optional = true }
tower-http = { version = "0.5.2", features = [
"fs",
"tracing",
"trace",
], optional = true }
tokio = { version = "1.39", features = ["full"], optional = true }
server_fn = { path = "../../server_fn", features = ["serde-lite", "rkyv", "multipart"] }
log = "0.4"
simple_logger = "4.0"
serde = { version = "1", features = ["derive"] }
axum = { version = "0.7", optional = true }
tower = { version = "0.4", optional = true }
tower-http = { version = "0.5", features = ["fs", "tracing", "trace"], optional = true }
tokio = { version = "1", features = ["full"], optional = true }
thiserror = "1.0"
wasm-bindgen = "0.2.93"
wasm-bindgen = "0.2"
serde_toml = "0.0.1"
toml = "0.8.19"
web-sys = { version = "0.3.70", features = ["FileList", "File"] }
strum = { version = "0.26.3", features = ["strum_macros", "derive"] }
notify = { version = "6.1", optional = true }
pin-project-lite = "0.2.14"
dashmap = { version = "6.0", optional = true }
once_cell = { version = "1.19", optional = true }
async-broadcast = { version = "0.7.1", optional = true }
toml = "0.8.8"
web-sys = { version = "0.3.67", features = ["FileList", "File"] }
strum = { version = "0.25.0", features = ["strum_macros", "derive"] }
notify = { version = "6.1.1", optional = true }
pin-project-lite = "0.2.13"
dashmap = { version = "5.5.3", optional = true }
once_cell = { version = "1.19.0", optional = true }
async-broadcast = { version = "0.6.0", optional = true }
[features]
hydrate = ["leptos/hydrate"]
ssr = [
"dep:axum",
"dep:tower",
"dep:tower-http",
"dep:tokio",
"leptos/ssr",
"dep:leptos_axum",
"dep:notify",
"dep:dashmap",
"dep:once_cell",
"dep:async-broadcast",
"dep:axum",
"dep:tower",
"dep:tower-http",
"dep:tokio",
"leptos/ssr",
"dep:leptos_axum",
"dep:notify",
"dep:dashmap",
"dep:once_cell",
"dep:async-broadcast",
]
[package.metadata.cargo-all-features]

View File

@@ -6,8 +6,7 @@ use server_fn::{
client::{browser::BrowserClient, Client},
codec::{
Encoding, FromReq, FromRes, GetUrl, IntoReq, IntoRes, MultipartData,
MultipartFormData, Postcard, Rkyv, SerdeLite, StreamingText,
TextStream,
MultipartFormData, Rkyv, SerdeLite, StreamingText, TextStream,
},
request::{browser::BrowserRequest, ClientReq, Req},
response::{browser::BrowserResponse, ClientRes, Res},
@@ -66,7 +65,6 @@ pub fn HomePage() -> impl IntoView {
<h2>"Alternative Encodings"</h2>
<ServerFnArgumentExample/>
<RkyvExample/>
<PostcardExample/>
<FileUpload/>
<FileUploadWithProgress/>
<FileWatcher/>
@@ -882,67 +880,3 @@ pub fn CustomClientExample() -> impl IntoView {
})>Click me</button>
}
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub struct PostcardData {
name: String,
age: u32,
hobbies: Vec<String>,
}
/// This server function uses Postcard for both input and output encoding.
/// Postcard provides efficient binary serialization, almost as fast as rkyv, while also being
/// serde compatible
#[server(input = Postcard, output = Postcard)]
pub async fn postcard_example(
data: PostcardData,
) -> Result<PostcardData, ServerFnError> {
// Simulate some processing time
tokio::time::sleep(std::time::Duration::from_millis(250)).await;
// Modify the data to demonstrate server-side changes
let mut modified_data = data.clone();
modified_data.age += 1;
modified_data.hobbies.push("Rust programming".to_string());
Ok(modified_data)
}
/// This component demonstrates the usage of Postcard encoding with server functions.
/// It allows incrementing the age of a person and shows how the data is
/// serialized, sent to the server, processed, and returned.
#[component]
pub fn PostcardExample() -> impl IntoView {
// Initialize the input data
let (input, set_input) = signal(PostcardData {
name: "Alice".to_string(),
age: 30,
hobbies: vec!["reading".to_string(), "hiking".to_string()],
});
// Create a resource that will call the server function whenever the input changes
let postcard_result = Resource::new(
move || input.get(),
|data| async move { postcard_example(data).await },
);
view! {
<h3>Using <code>postcard</code> encoding</h3>
<p>"This example demonstrates using Postcard for efficient binary serialization."</p>
<button on:click=move |_| {
// Update the input data when the button is clicked
set_input.update(|data| {
data.age += 1;
});
}>
"Increment Age"
</button>
// Display the current input data
<p>"Input: " {move || format!("{:?}", input.get())}</p>
<Transition>
// Display the result from the server, which will update automatically
// when the input changes due to the resource
<p>"Result: " {move || postcard_result.get().map(|r| format!("{:?}", r))}</p>
</Transition>
}
}

View File

@@ -9,6 +9,6 @@ lto = true
[dependencies]
leptos = { path = "../../leptos", features = ["csr"] }
console_log = "1.0"
log = "0.4.22"
console_log = "1"
log = "0.4"
console_error_panic_hook = "0.1.7"

View File

@@ -2,26 +2,25 @@
name = "ssr_modes"
version = "0.1.0"
edition = "2021"
# std::sync::LazyLock is stabilized in Rust version 1.80.0
rust-version = "1.80.0"
[lib]
crate-type = ["cdylib", "rlib"]
[dependencies]
actix-files = { version = "0.6.6", optional = true }
actix-web = { version = "4.8", optional = true, features = ["macros"] }
console_error_panic_hook = "0.1.7"
console_log = "1.0"
leptos = { path = "../../leptos" }
actix-files = { version = "0.6", optional = true }
actix-web = { version = "4", optional = true, features = ["macros"] }
console_error_panic_hook = "0.1"
console_log = "1"
lazy_static = "1"
leptos = { path = "../../leptos"}
leptos_meta = { path = "../../meta" }
leptos_actix = { path = "../../integrations/actix", optional = true }
leptos_router = { path = "../../router" }
log = "0.4.22"
serde = { version = "1.0", features = ["derive"] }
thiserror = "1.0"
tokio = { version = "1.39", features = ["time"] }
wasm-bindgen = "0.2.93"
log = "0.4"
serde = { version = "1", features = ["derive"] }
thiserror = "1"
tokio = { version = "1", features = ["time"] }
wasm-bindgen = "0.2"
[features]
hydrate = ["leptos/hydrate"]
@@ -39,12 +38,12 @@ denylist = ["actix-files", "actix-web", "leptos_actix"]
skip_feature_sets = [["ssr", "hydrate"]]
[package.metadata.leptos]
# The name used by wasm-bindgen/cargo-leptos for the JS/WASM bundle. Defaults to the crate name
# The name used by wasm-bindgen/cargo-leptos for the JS/WASM bundle. Defaults to the crate name
output-name = "ssr_modes"
# The site root folder is where cargo-leptos generate all output. WARNING: all content of this folder will be erased on a rebuild. Use it in your server setup.
site-root = "target/site"
# The site-root relative folder where all compiled output (JS, WASM and CSS) is written
# Defaults to pkg
# Defaults to pkg
site-pkg-dir = "pkg"
# [Optional] The source CSS file. If it ends with .sass or .scss then it will be compiled by dart-sass into CSS. The CSS is optimized by Lightning CSS before being written to <site-root>/<site-pkg>/app.css
style-file = "style/main.scss"

View File

@@ -1,5 +1,4 @@
use std::sync::LazyLock;
use lazy_static::lazy_static;
use leptos::prelude::*;
use leptos_meta::*;
use leptos_router::{
@@ -147,9 +146,8 @@ fn Post() -> impl IntoView {
}
// Dummy API
static POSTS: LazyLock<[Post; 3]> = LazyLock::new(|| {
[
lazy_static! {
static ref POSTS: Vec<Post> = vec![
Post {
id: 0,
title: "My first post".to_string(),
@@ -165,8 +163,8 @@ static POSTS: LazyLock<[Post; 3]> = LazyLock::new(|| {
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 {

View File

@@ -2,45 +2,42 @@
name = "ssr_modes_axum"
version = "0.1.0"
edition = "2021"
# std::sync::LazyLock is stabilized in Rust version 1.80.0
rust-version = "1.80.0"
[lib]
crate-type = ["cdylib", "rlib"]
[dependencies]
console_error_panic_hook = "0.1.7"
console_log = "1.0"
leptos = { path = "../../leptos", features = [
"hydration",
] } #"nightly", "hydration"] }
console_error_panic_hook = "0.1"
console_log = "1"
lazy_static = "1"
leptos = { path = "../../leptos", features = ["hydration" ] } #"nightly", "hydration"] }
leptos_meta = { path = "../../meta" }
leptos_axum = { path = "../../integrations/axum", optional = true }
leptos_router = { path = "../../router" }
log = "0.4.22"
serde = { version = "1.0", features = ["derive"] }
thiserror = "1.0"
axum = { version = "0.7.5", optional = true }
tower = { version = "0.4.13", optional = true }
tower-http = { version = "0.5.2", features = ["fs"], optional = true }
tokio = { version = "1.39", features = [
"rt-multi-thread",
"macros",
"time",
log = "0.4"
serde = { version = "1", features = ["derive"] }
thiserror = "1"
axum = { version = "0.7", optional = true }
tower = { version = "0.4", optional = true }
tower-http = { version = "0.5", features = ["fs"], optional = true }
tokio = { version = "1", features = [
"rt-multi-thread",
"macros",
"time",
], optional = true }
wasm-bindgen = "0.2.93"
wasm-bindgen = "0.2"
[features]
hydrate = ["leptos/hydrate"]
ssr = [
"dep:axum",
"dep:tower",
"dep:tower-http",
"dep:tokio",
"leptos/ssr",
"leptos_meta/ssr",
"dep:leptos_axum",
"leptos_router/ssr",
"dep:axum",
"dep:tower",
"dep:tower-http",
"dep:tokio",
"leptos/ssr",
"leptos_meta/ssr",
"dep:leptos_axum",
"leptos_router/ssr",
]
[profile.release]

View File

@@ -1,5 +1,4 @@
use std::sync::LazyLock;
use lazy_static::lazy_static;
use leptos::prelude::*;
use leptos_meta::MetaTags;
use leptos_meta::*;
@@ -21,7 +20,7 @@ pub fn shell(options: LeptosOptions) -> impl IntoView {
<head>
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<AutoReload options=options.clone()/>
<AutoReload options=options.clone() />
<HydrationScripts options/>
<MetaTags/>
</head>
@@ -65,24 +64,15 @@ pub fn App() -> impl IntoView {
<a href="/admin">"Admin"</a>
<Transition>
<ActionForm action=toggle_admin>
<input
type="hidden"
name="is_admin"
value=move || {
(!is_admin.get().and_then(|n| n.ok()).unwrap_or_default())
.to_string()
}
<input type="hidden" name="is_admin"
value=move || (!is_admin.get().and_then(|n| n.ok()).unwrap_or_default()).to_string()
/>
<button>
{move || {
if is_admin.get().and_then(Result::ok).unwrap_or_default() {
"Log Out"
} else {
"Log In"
}
{move || if is_admin.get().and_then(Result::ok).unwrap_or_default() {
"Log Out"
} else {
"Log In"
}}
</button>
</ActionForm>
</Transition>
@@ -149,15 +139,9 @@ fn HomePage() -> impl IntoView {
<li>
<a href=format!("/post/{}", post.id)>{post.title.clone()}</a>
"|"
<a href=format!(
"/post_in_order/{}",
post.id,
)>{post.title.clone()} "(in order)"</a>
<a href=format!("/post_in_order/{}", post.id)>{post.title.clone()} "(in order)"</a>
"|"
<a href=format!(
"/post_partially_blocked/{}",
post.id,
)>{post.title} "(partially blocked)"</a>
<a href=format!("/post_partially_blocked/{}", post.id)>{post.title} "(partially blocked)"</a>
</li>
</For>
</ul>
@@ -220,11 +204,12 @@ fn Post() -> impl IntoView {
Ok(comments) => Ok(view! {
<h1>"Comments"</h1>
<ul>
{comments
.into_iter()
.map(|comment| view! { <li>{comment}</li> })
.collect_view()}
{comments.into_iter()
.map(|comment| view! {
<li>{comment}</li>
})
.collect_view()
}
</ul>
}),
_ => Err(PostError::ServerError),
@@ -252,19 +237,22 @@ fn Post() -> impl IntoView {
}
}>{post_view}</ErrorBoundary>
</Suspense>
<Suspense fallback=move || view! { <p>"Loading comments..."</p> }>{comments_view}</Suspense>
<Suspense fallback=move || view! { <p>"Loading comments..."</p> }>
{comments_view}
</Suspense>
}
}
#[component]
pub fn Admin() -> impl IntoView {
view! { <p>"You can only see this page if you're logged in."</p> }
view! {
<p>"You can only see this page if you're logged in."</p>
}
}
// Dummy API
static POSTS: LazyLock<[Post; 3]> = LazyLock::new(|| {
[
lazy_static! {
static ref POSTS: Vec<Post> = vec![
Post {
id: 0,
title: "My first post".to_string(),
@@ -280,8 +268,8 @@ static POSTS: LazyLock<[Post; 3]> = LazyLock::new(|| {
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 {

View File

@@ -1,13 +0,0 @@
# Generated by Cargo
# will have compiled files and executables
/target/
pkg
# These are backup files generated by rustfmt
**/*.rs.bk
# node e2e test tools and outputs
node_modules/
test-results/
end2end/playwright-report/
playwright/.cache/

View File

@@ -1,115 +0,0 @@
[package]
name = "static_routing"
version = "0.1.0"
edition = "2021"
[lib]
crate-type = ["cdylib", "rlib"]
[dependencies]
console_error_panic_hook = "0.1.7"
console_log = "1.0"
leptos = { path = "../../leptos", features = [
"hydration",
] } #"nightly", "hydration"] }
leptos_meta = { path = "../../meta" }
leptos_axum = { path = "../../integrations/axum", optional = true }
leptos_router = { path = "../../router" }
log = "0.4.22"
serde = { version = "1.0", features = ["derive"] }
thiserror = "1.0"
axum = { version = "0.7.5", optional = true }
tower = { version = "0.4.13", optional = true }
tower-http = { version = "0.5.2", features = ["fs"], optional = true }
tokio = { version = "1.39", features = [
"fs",
"rt-multi-thread",
"macros",
], optional = true }
tokio-stream = { version = "0.1", features = ["fs"], optional = true }
futures = "0.3"
wasm-bindgen = "0.2.93"
notify = { version = "6", optional = true }
http = { version = "1", optional = true }
[features]
hydrate = ["leptos/hydrate"]
ssr = [
"dep:axum",
"dep:tower",
"dep:tower-http",
"dep:tokio",
"dep:tokio-stream",
"leptos/ssr",
"leptos_meta/ssr",
"dep:leptos_axum",
"leptos_router/ssr",
"dep:notify",
"dep:http"
]
[profile.release]
panic = "abort"
[profile.wasm-release]
inherits = "release"
opt-level = 'z'
lto = true
codegen-units = 1
panic = "abort"
[package.metadata.cargo-all-features]
denylist = ["axum", "tower", "tower-http", "tokio", "sqlx", "leptos_axum"]
skip_feature_sets = [["ssr", "hydrate"]]
[package.metadata.leptos]
# The name used by wasm-bindgen/cargo-leptos for the JS/WASM bundle. Defaults to the crate name
output-name = "ssr_modes"
# The site root folder is where cargo-leptos generate all output. WARNING: all content of this folder will be erased on a rebuild. Use it in your server setup.
site-root = "target/site"
# The site-root relative folder where all compiled output (JS, WASM and CSS) is written
# Defaults to pkg
site-pkg-dir = "pkg"
# [Optional] The source CSS file. If it ends with .sass or .scss then it will be compiled by dart-sass into CSS. The CSS is optimized by Lightning CSS before being written to <site-root>/<site-pkg>/app.css
style-file = "style/main.scss"
# Assets source dir. All files found here will be copied and synchronized to site-root.
# The assets-dir cannot have a sub directory with the same name/path as site-pkg-dir.
#
# Optional. Env: LEPTOS_ASSETS_DIR.
assets-dir = "assets"
# The IP and port (ex: 127.0.0.1:3000) where the server serves the content. Use it in your server setup.
site-addr = "127.0.0.1:3007"
# The port to use for automatic reload monitoring
reload-port = 3001
# [Optional] Command to use when running end2end tests. It will run in the end2end dir.
# [Windows] for non-WSL use "npx.cmd playwright test"
# This binary name can be checked in Powershell with Get-Command npx
end2end-cmd = "npx playwright test"
end2end-dir = "end2end"
# The browserlist query used for optimizing the CSS.
browserquery = "defaults"
# Set by cargo-leptos watch when building with that tool. Controls whether autoreload JS will be included in the head
watch = false
# The environment Leptos will run in, usually either "DEV" or "PROD"
env = "DEV"
# The features to use when compiling the bin target
#
# Optional. Can be over-ridden with the command line parameter --bin-features
bin-features = ["ssr"]
# If the --no-default-features flag should be used when compiling the bin target
#
# Optional. Defaults to false.
bin-default-features = false
# The features to use when compiling the lib target
#
# Optional. Can be over-ridden with the command line parameter --lib-features
lib-features = ["hydrate"]
# If the --no-default-features flag should be used when compiling the lib target
#
# Optional. Defaults to false.
lib-default-features = false
lib-profile-release = "wasm-release"

View File

@@ -1,21 +0,0 @@
MIT License
Copyright (c) 2022 henrik
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

Some files were not shown because too many files have changed in this diff Show More