Compare commits
369 Commits
fix-tailwi
...
send-sync-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9f704f91fe | ||
|
|
4b0e212f1c | ||
|
|
8fa89cffef | ||
|
|
18ceb4c4f8 | ||
|
|
0d3e2baa9b | ||
|
|
1563d237d0 | ||
|
|
b861f84e40 | ||
|
|
62812af5b2 | ||
|
|
f300e7fd41 | ||
|
|
44974fcf69 | ||
|
|
815c2e6dc2 | ||
|
|
2fc20d8312 | ||
|
|
679692e202 | ||
|
|
be1343fa88 | ||
|
|
fc7199f188 | ||
|
|
154e42f3f4 | ||
|
|
4c24795ffd | ||
|
|
f2e7b00d5a | ||
|
|
0b36b68846 | ||
|
|
f24bad4bf2 | ||
|
|
a2ea1d8483 | ||
|
|
9b0fb63632 | ||
|
|
2febaf6b99 | ||
|
|
6c8e8e9ce7 | ||
|
|
7aa0181192 | ||
|
|
8496bd59ce | ||
|
|
fd6e63796e | ||
|
|
39cddfc82d | ||
|
|
d1333a3402 | ||
|
|
7f9919e2d5 | ||
|
|
fc2d6ef19d | ||
|
|
a5531b1a7c | ||
|
|
81ab77e8ea | ||
|
|
23bd399239 | ||
|
|
3e04318082 | ||
|
|
2d88524354 | ||
|
|
ecb784e422 | ||
|
|
69e02bfce2 | ||
|
|
a75abb9e04 | ||
|
|
bf1ef1b7c2 | ||
|
|
7fb7bb90f8 | ||
|
|
a22a693de7 | ||
|
|
cbb1e4c9d2 | ||
|
|
dbccf525ac | ||
|
|
ed6d6ae4b0 | ||
|
|
89ee88d75e | ||
|
|
9ea604f516 | ||
|
|
b5ab7b107a | ||
|
|
18eecd9606 | ||
|
|
a49dfd3f8e | ||
|
|
7075f58451 | ||
|
|
bcabdddce5 | ||
|
|
726393c446 | ||
|
|
c336eb8769 | ||
|
|
0f5f0de410 | ||
|
|
3d769c9f21 | ||
|
|
9ac0f0a579 | ||
|
|
a385f502b6 | ||
|
|
603eead12d | ||
|
|
8a73f3b879 | ||
|
|
5fc8907b85 | ||
|
|
678990194f | ||
|
|
a964e89d1a | ||
|
|
285092a467 | ||
|
|
c1c74ead0f | ||
|
|
e4c9109278 | ||
|
|
64add54de6 | ||
|
|
ac343427e7 | ||
|
|
452e397048 | ||
|
|
ad3ac5ad3c | ||
|
|
db63eda2f5 | ||
|
|
6cbdc57f7a | ||
|
|
3215e44c9a | ||
|
|
b54a60213b | ||
|
|
ebeb1d69d1 | ||
|
|
cadb04b076 | ||
|
|
490b7a1596 | ||
|
|
f4d781e739 | ||
|
|
ebe5bf4600 | ||
|
|
d62046dc6f | ||
|
|
c7abb57168 | ||
|
|
bc0cd5d0ba | ||
|
|
7df67444f9 | ||
|
|
40155e91ea | ||
|
|
5c062fa6f1 | ||
|
|
3517820afd | ||
|
|
300cc4f54c | ||
|
|
586e9be99a | ||
|
|
6ed86d0ee9 | ||
|
|
1fe93fd588 | ||
|
|
2723871a80 | ||
|
|
70d92c7f42 | ||
|
|
e96d4b0687 | ||
|
|
ce0910caca | ||
|
|
81a937277d | ||
|
|
355e711964 | ||
|
|
27ec506fd5 | ||
|
|
79c76ae4cb | ||
|
|
e416815591 | ||
|
|
81bdd6788f | ||
|
|
f7d5567a35 | ||
|
|
ae0a243cc0 | ||
|
|
7893ff8b55 | ||
|
|
6130e708ce | ||
|
|
d049d2f36b | ||
|
|
61ca6465df | ||
|
|
10a833d763 | ||
|
|
17982e8ac5 | ||
|
|
6cfb6227f5 | ||
|
|
159852b8d7 | ||
|
|
6f95713b59 | ||
|
|
e17afd4559 | ||
|
|
e0aa1e245b | ||
|
|
7951a6e9cf | ||
|
|
1f39299303 | ||
|
|
2be4610233 | ||
|
|
af254e9b61 | ||
|
|
4aae8a5088 | ||
|
|
7ff044cef6 | ||
|
|
11122b575e | ||
|
|
a62ee4031b | ||
|
|
19b43607a1 | ||
|
|
884297706a | ||
|
|
fb4c208609 | ||
|
|
5701e74efb | ||
|
|
2afe8e202a | ||
|
|
08ec473304 | ||
|
|
3ae0880db4 | ||
|
|
9180aaad7e | ||
|
|
89be6bc68e | ||
|
|
56426170b0 | ||
|
|
0571ea4103 | ||
|
|
cdf709fb09 | ||
|
|
7eaa36812d | ||
|
|
2ef36c65fd | ||
|
|
a16540ccc5 | ||
|
|
613c7b32a1 | ||
|
|
8f2a731c9f | ||
|
|
1621b86d8f | ||
|
|
b1ac17995d | ||
|
|
6471af8b89 | ||
|
|
abf54b832e | ||
|
|
91e839c71a | ||
|
|
b944b17e6d | ||
|
|
54c1abb4b7 | ||
|
|
c24f33aeb2 | ||
|
|
9e83acfe63 | ||
|
|
46254a18f3 | ||
|
|
7d7a96d9bc | ||
|
|
339c920b19 | ||
|
|
ecc24fa65d | ||
|
|
3f036ee321 | ||
|
|
4e00ec2348 | ||
|
|
9c59b720b7 | ||
|
|
da4340894f | ||
|
|
02f5c3891c | ||
|
|
087e67466f | ||
|
|
1925c5bbe5 | ||
|
|
1613616008 | ||
|
|
8a01880ade | ||
|
|
180ab87ff9 | ||
|
|
e324fb6e76 | ||
|
|
0547b4f846 | ||
|
|
75659ce674 | ||
|
|
190cb162ad | ||
|
|
1f556cefb0 | ||
|
|
6a68ef67f3 | ||
|
|
23bbd90c81 | ||
|
|
27b8553076 | ||
|
|
5bfeb93e3d | ||
|
|
dd9ae1b7b1 | ||
|
|
ad34a5d9c6 | ||
|
|
ace5e7cbba | ||
|
|
c8f0988e53 | ||
|
|
64f0f8879b | ||
|
|
b8cafeb650 | ||
|
|
992b218ffe | ||
|
|
5df89b0d25 | ||
|
|
c050456a47 | ||
|
|
8a8d7cbe1b | ||
|
|
f5f345e623 | ||
|
|
4df3687463 | ||
|
|
f6622448e9 | ||
|
|
78825401c5 | ||
|
|
f2b7ad6244 | ||
|
|
43f107d9bd | ||
|
|
a2612ca1fc | ||
|
|
a000c84e1a | ||
|
|
ee647cba1c | ||
|
|
1377b823e2 | ||
|
|
4d21f5ac63 | ||
|
|
1ec603ee58 | ||
|
|
c56806713e | ||
|
|
2f6aa6753d | ||
|
|
2544687acd | ||
|
|
3d25e86c23 | ||
|
|
28ec3a6cda | ||
|
|
8b92a561a3 | ||
|
|
e490c0423f | ||
|
|
b6579a040a | ||
|
|
01e024b726 | ||
|
|
6603c44ce2 | ||
|
|
977f11b180 | ||
|
|
fb34b29ccf | ||
|
|
6576d8eda1 | ||
|
|
6b729f9131 | ||
|
|
dc60c35b58 | ||
|
|
32ec9cc57e | ||
|
|
35601d8284 | ||
|
|
49bc7d2a27 | ||
|
|
aa7c7367dc | ||
|
|
70808c5262 | ||
|
|
67503a108d | ||
|
|
ef52a01838 | ||
|
|
4cacfe98d8 | ||
|
|
52e653316e | ||
|
|
bf5b6ca9c2 | ||
|
|
8875939a27 | ||
|
|
b9a83277d9 | ||
|
|
dad84b5867 | ||
|
|
1f29d29947 | ||
|
|
1b8175e2fa | ||
|
|
dbe3ec015c | ||
|
|
492fa6c6d3 | ||
|
|
343e8c8abe | ||
|
|
656d20cb65 | ||
|
|
a0a66b75dd | ||
|
|
085ba3506c | ||
|
|
63f3780eda | ||
|
|
c41cf879d1 | ||
|
|
b34f2070d3 | ||
|
|
7fa21defa6 | ||
|
|
bdd9abc04d | ||
|
|
1d25134213 | ||
|
|
de73622949 | ||
|
|
5d3cfc6483 | ||
|
|
6fbbd09000 | ||
|
|
f2842cf14e | ||
|
|
a6b6864bc5 | ||
|
|
063b946cd4 | ||
|
|
5a2c9ea345 | ||
|
|
808d87598b | ||
|
|
0956c48b1e | ||
|
|
8915e2615b | ||
|
|
7f47134058 | ||
|
|
af7b93fa1e | ||
|
|
ed940f577a | ||
|
|
916f30a07b | ||
|
|
e01c565de1 | ||
|
|
dffe195cdc | ||
|
|
a5e2587555 | ||
|
|
af8889fab2 | ||
|
|
267c1cfc34 | ||
|
|
3498378e60 | ||
|
|
f8c680d14d | ||
|
|
b852e459a9 | ||
|
|
681f10ec8d | ||
|
|
1d480791a1 | ||
|
|
7acc309f66 | ||
|
|
9527de15ed | ||
|
|
aeb25a715a | ||
|
|
46e91a538c | ||
|
|
1fe526c99c | ||
|
|
6b05918807 | ||
|
|
05d2eb8ce0 | ||
|
|
e12c2d9769 | ||
|
|
825245b65f | ||
|
|
ef067f18e1 | ||
|
|
844dc21efd | ||
|
|
1a00e99a24 | ||
|
|
6c5bcf30ba | ||
|
|
be8ffe935d | ||
|
|
0b80bba4ec | ||
|
|
9cc38988d8 | ||
|
|
0d92a5dec8 | ||
|
|
677e4f2540 | ||
|
|
0029e1d8f7 | ||
|
|
635aa5c681 | ||
|
|
f5c4c9448c | ||
|
|
63b1837315 | ||
|
|
bc43a9d329 | ||
|
|
1850c28d3a | ||
|
|
319a058e63 | ||
|
|
678e49268f | ||
|
|
6df4a6f120 | ||
|
|
73c6bbb225 | ||
|
|
fa57085946 | ||
|
|
aef589cd24 | ||
|
|
05ffd8c989 | ||
|
|
1125a5f7cb | ||
|
|
dfba1d9656 | ||
|
|
96418ed684 | ||
|
|
b010233bb4 | ||
|
|
7e28f56f01 | ||
|
|
dd35c31db1 | ||
|
|
c9ac4ed2b5 | ||
|
|
7631ce3b09 | ||
|
|
a5988c59ee | ||
|
|
9ba807f79b | ||
|
|
9d8627b337 | ||
|
|
64bf01c59e | ||
|
|
ed023c8970 | ||
|
|
13bdef22bd | ||
|
|
6f49a6c12a | ||
|
|
7db292779b | ||
|
|
e2496e01d0 | ||
|
|
d5bda04306 | ||
|
|
9165242744 | ||
|
|
927fe0949f | ||
|
|
459216a30e | ||
|
|
c7fa041469 | ||
|
|
cab7360bef | ||
|
|
159ec4a7bd | ||
|
|
ae40f3134a | ||
|
|
3c080e0564 | ||
|
|
e8c1bf5055 | ||
|
|
2a4a5f75c9 | ||
|
|
91b65654d6 | ||
|
|
dcca6e4e17 | ||
|
|
4550545e4f | ||
|
|
af1a4492e8 | ||
|
|
6b1b4463a0 | ||
|
|
632267c13a | ||
|
|
a349707e1f | ||
|
|
84fa6cd3a8 | ||
|
|
05468d3307 | ||
|
|
0da88f39cd | ||
|
|
5dffb0a803 | ||
|
|
e2a5c2d78f | ||
|
|
ca679ec496 | ||
|
|
10282857fe | ||
|
|
263d5b1d89 | ||
|
|
6a4cbbf266 | ||
|
|
8d14972808 | ||
|
|
441eb1697e | ||
|
|
64e6eedb4d | ||
|
|
78d965cc91 | ||
|
|
28dce925b0 | ||
|
|
a2943c4649 | ||
|
|
d4b5b958f3 | ||
|
|
9537cafe25 | ||
|
|
95dd252c14 | ||
|
|
755ceb7d75 | ||
|
|
d5b74dacc8 | ||
|
|
411fc51ea2 | ||
|
|
e714cac0ec | ||
|
|
ab0b687943 | ||
|
|
7f21ee97a8 | ||
|
|
0ed56d382d | ||
|
|
a47cac6e3c | ||
|
|
edbd3612b3 | ||
|
|
e2517c99b8 | ||
|
|
2b01bf99b4 | ||
|
|
bd5bd71a21 | ||
|
|
60187961a0 | ||
|
|
1344f113c5 | ||
|
|
96bbb86346 | ||
|
|
7478315970 | ||
|
|
b894444b8d | ||
|
|
9f8bcd6fb1 | ||
|
|
d82781abbd | ||
|
|
f8c4cac6d3 | ||
|
|
4264b15aab | ||
|
|
168f9d3a45 | ||
|
|
9663555195 | ||
|
|
e92176029c | ||
|
|
fe820c48c8 | ||
|
|
87cd4b8f00 | ||
|
|
9ba06cd604 |
3
.github/FUNDING.yml
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
# These are supported funding model platforms
|
||||
|
||||
github: gbj
|
||||
17
.github/workflows/test.yml
vendored
@@ -21,13 +21,14 @@ jobs:
|
||||
- ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Setup Rust
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: ${{ matrix.rust }}
|
||||
override: true
|
||||
components: rustfmt
|
||||
|
||||
- name: Setup cargo-make
|
||||
uses: davidB/rust-cargo-make@v1
|
||||
@@ -35,16 +36,10 @@ jobs:
|
||||
- name: Cargo generate-lockfile
|
||||
run: cargo generate-lockfile
|
||||
|
||||
- name: Cargo cache
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
~/.cargo/bin/
|
||||
~/.cargo/registry/index/
|
||||
~/.cargo/registry/cache/
|
||||
~/.cargo/git/db/
|
||||
target/
|
||||
key: ${{ runner.os }}-cargo-${{ matrix.rust }}-${{ hashFiles('**/Cargo.lock') }}
|
||||
- name: Run Rustfmt
|
||||
run: cargo fmt -- --check
|
||||
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
|
||||
- name: Run tests with all features
|
||||
run: cargo make ci
|
||||
|
||||
1
.gitignore
vendored
@@ -6,3 +6,4 @@ blob.rs
|
||||
Cargo.lock
|
||||
**/*.rs.bk
|
||||
.DS_Store
|
||||
.idea
|
||||
|
||||
51
CODE_OF_CONDUCT.md
Normal file
@@ -0,0 +1,51 @@
|
||||
# Contributor Covenant Code of Conduct
|
||||
|
||||
_This Code of Conduct is based on the [Rust Code of Conduct](https://www.rust-lang.org/policies/code-of-conduct)
|
||||
and the [Bevy Code of Conduct](https://raw.githubusercontent.com/bevyengine/bevy/main/CODE_OF_CONDUCT.md),
|
||||
which are adapted from the [Node.js Policy on Trolling](http://blog.izs.me/post/30036893703/policy-on-trolling)
|
||||
and the [Contributor Covenant](https://www.contributor-covenant.org)._
|
||||
|
||||
## Our Pledge
|
||||
|
||||
We as members, contributors, and leaders pledge to make participation in our
|
||||
community a harassment-free experience for everyone, regardless of age, body
|
||||
size, visible or invisible disability, ethnicity, sex characteristics, gender
|
||||
identity and expression, level of experience, education, socio-economic status,
|
||||
nationality, personal appearance, race, religion, or sexual identity
|
||||
and orientation.
|
||||
|
||||
We pledge to act and interact in ways that contribute to an open, welcoming,
|
||||
diverse, inclusive, and healthy community.
|
||||
|
||||
## Our Standards
|
||||
|
||||
We are a community of people learning and exploring how to build better web applications
|
||||
with Rust. When interacting with one another, please remember that there are no experts and there are
|
||||
no stupid questions. Assume the best in other people's communication, and take a step back if
|
||||
you find yourself getting defensive.
|
||||
|
||||
Please note the following guidelines as well:
|
||||
|
||||
* Please avoid using overtly sexual aliases or other nicknames that might detract from a friendly, safe and welcoming environment for all.
|
||||
* Please be kind and courteous. There’s no need to be mean or rude.
|
||||
* Respect that people have differences of opinion and that every design or implementation choice carries a trade-off and numerous costs. There is seldom a right answer.
|
||||
* Please keep unstructured critique to a minimum. If you have solid ideas you want to experiment with, make a fork and see how it works.
|
||||
* We will exclude you from interaction if you insult, demean or harass anyone. That is not welcome behavior. We interpret the term “harassment” as including the definition in the [Citizen Code of Conduct](https://github.com/stumpsyn/policies/blob/master/citizen_code_of_conduct.md); if you have any lack of clarity about what might be included in that concept, please read their definition. In particular, we don’t tolerate behavior that excludes people in socially marginalized groups.
|
||||
* Private harassment is also unacceptable. No matter who you are, if you feel you have been or are being harassed or made uncomfortable by a community member, please contact the maintainers immediately. Whether you’re a regular contributor or a newcomer, we care about making this community a safe place for you and we’ve got your back.
|
||||
* Do not make casual mention of slavery or indentured servitude and/or false comparisons of one's occupation or situation to slavery. Please consider using or asking about alternate terminology when referring to such metaphors in technology.
|
||||
* Likewise any spamming, trolling, flaming, baiting or other attention-stealing behavior is not welcome.
|
||||
|
||||
## Moderation
|
||||
|
||||
These are the policies for upholding [our community’s standards of conduct](#our-standards). If you feel that a thread needs moderation, please contact the maintainers.
|
||||
|
||||
1. Remarks that violate the community standards of conduct, including hateful, hurtful, oppressive, or exclusionary remarks, are not allowed. (Cursing is allowed, but never targeting another user, and never in a hateful manner).
|
||||
2. Remarks that maintainers find inappropriate, whether listed in the code of conduct or not, are also not allowed.
|
||||
3. Maintainers will first respond to such remarks with a warning.
|
||||
4. If the warning is unheeded, the user will be “kicked,” i.e., kicked out of the communication channel to cool off.
|
||||
5. If the user comes back and continues to make trouble, they will be banned, i.e., indefinitely excluded.
|
||||
6. Maintainers may choose at their discretion to un-ban the user if it was a first offense and they offer the offended party a genuine apology.
|
||||
7. If a maintainer bans someone and you think it was unjustified, please take it up with that maintainer, or with a different maintainer, in private. Complaints about bans in-channel are not allowed.
|
||||
8. Maintainers are held to a higher standard than other community members. If a maintainer creates an inappropriate situation, they should expect less leeway than others.
|
||||
|
||||
The enforcement policies in the code of conduct apply to all official venues, including Discord channels, GitHub repositories, and all other forums.
|
||||
15
Cargo.toml
@@ -23,10 +23,23 @@ members = [
|
||||
]
|
||||
exclude = ["benchmarks", "examples"]
|
||||
|
||||
[workspace.package]
|
||||
version = "0.1.1"
|
||||
|
||||
[workspace.dependencies]
|
||||
leptos = { path = "./leptos", default-features = false, version = "0.1.1" }
|
||||
leptos_dom = { path = "./leptos_dom", default-features = false, version = "0.1.1" }
|
||||
leptos_macro = { path = "./leptos_macro", default-features = false, version = "0.1.1" }
|
||||
leptos_reactive = { path = "./leptos_reactive", default-features = false, version = "0.1.1" }
|
||||
leptos_server = { path = "./leptos_server", default-features = false, version = "0.1.1" }
|
||||
leptos_config = { path = "./leptos_config", default-features = false, version = "0.1.1" }
|
||||
leptos_router = { path = "./router", version = "0.1.1" }
|
||||
leptos_meta = { path = "./meta", default-feature = false, version = "0.1.1" }
|
||||
|
||||
[profile.release]
|
||||
codegen-units = 1
|
||||
lto = true
|
||||
opt-level = 'z'
|
||||
|
||||
[workspace.metadata.cargo-all-features]
|
||||
skip_feature_sets = [["csr", "ssr"], ["csr", "hydrate"], ["ssr", "hydrate"]]
|
||||
skip_feature_sets = [["csr", "ssr"], ["csr", "hydrate"], ["ssr", "hydrate"]]
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
default_to_workspace = false
|
||||
|
||||
[tasks.ci]
|
||||
dependencies = ["build", "test"]
|
||||
dependencies = ["build", "build-examples", "test"]
|
||||
|
||||
[tasks.build]
|
||||
clear = true
|
||||
@@ -19,6 +19,24 @@ command = "cargo"
|
||||
args = ["+nightly", "build-all-features"]
|
||||
install_crate = "cargo-all-features"
|
||||
|
||||
[tasks.build-examples]
|
||||
clear = true
|
||||
dependencies = [
|
||||
{ name = "build", path = "examples/counter" },
|
||||
{ name = "build", path = "examples/counter_isomorphic" },
|
||||
{ name = "build", path = "examples/counters" },
|
||||
{ name = "build", path = "examples/counters_stable" },
|
||||
{ name = "build", path = "examples/fetch" },
|
||||
{ name = "build", path = "examples/hackernews" },
|
||||
{ name = "build", path = "examples/hackernews_axum" },
|
||||
{ name = "build", path = "examples/parent_child" },
|
||||
{ name = "build", path = "examples/router" },
|
||||
{ name = "build", path = "examples/tailwind" },
|
||||
{ name = "build", path = "examples/todo_app_sqlite" },
|
||||
{ name = "build", path = "examples/todo_app_sqlite_axum" },
|
||||
{ name = "build", path = "examples/todomvc" },
|
||||
]
|
||||
|
||||
[tasks.test]
|
||||
clear = true
|
||||
dependencies = ["test-all"]
|
||||
|
||||
41
README.md
@@ -1,6 +1,7 @@
|
||||
**NOTE: We're in the middle of merging changes and making fixes to support our upcoming `0.1.0` release. Some of the examples may be in a broken state. You can continue using the `0.0` releases with no issues.**
|
||||
|
||||
<img src="https://raw.githubusercontent.com/gbj/leptos/main/docs/logos/logo.svg" alt="Leptos Logo" style="width: 100%; height: auto; display: block; margin: auto;">
|
||||
<picture>
|
||||
<source srcset="https://raw.githubusercontent.com/leptos-rs/leptos/main/docs/logos/Leptos_logo_pref_dark_RGB.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>
|
||||
|
||||
[](https://crates.io/crates/leptos)
|
||||
[](https://docs.rs/leptos)
|
||||
@@ -28,7 +29,7 @@ pub fn SimpleCounter(cx: Scope, initial_value: i32) -> impl IntoView {
|
||||
<div>
|
||||
<button on:click=clear>"Clear"</button>
|
||||
<button on:click=decrement>"-1"</button>
|
||||
<span>"Value: " {move || value().to_string()} "!"</span>
|
||||
<span>"Value: " {value} "!"</span>
|
||||
<button on:click=increment>"+1"</button>
|
||||
</div>
|
||||
}
|
||||
@@ -58,12 +59,11 @@ Leptos is a full-stack, isomorphic Rust web framework leveraging fine-grained re
|
||||
|
||||
Here are some resources for learning more about Leptos:
|
||||
|
||||
- [Examples](https://github.com/gbj/leptos/tree/main/examples)
|
||||
- [Examples](https://github.com/leptos-rs/leptos/tree/main/examples)
|
||||
- [API Documentation](https://docs.rs/leptos/latest/leptos/)
|
||||
- [Common Bugs](https://github.com/gbj/leptos/tree/main/docs/COMMON_BUGS.md) (and how to fix them!)
|
||||
- [Common Bugs](https://github.com/leptos-rs/leptos/tree/main/docs/COMMON_BUGS.md) (and how to fix them!)
|
||||
- Leptos Guide (in progress)
|
||||
|
||||
|
||||
## `nightly` Note
|
||||
|
||||
Most of the examples assume you’re using `nightly` Rust.
|
||||
@@ -81,12 +81,12 @@ If you’re on `stable`, note the following:
|
||||
1. You need to enable the `"stable"` flag in `Cargo.toml`: `leptos = { version = "0.1.0-alpha", features = ["stable"] }`
|
||||
2. `nightly` enables the function call syntax for accessing and setting signals. If you’re using `stable`,
|
||||
you’ll just call `.get()`, `.set()`, or `.update()` manually. Check out the
|
||||
[`counters-stable` example](https://github.com/gbj/leptos/blob/main/examples/counters-stable/src/main.rs)
|
||||
[`counters_stable` example](https://github.com/leptos-rs/leptos/blob/main/examples/counters_stable/src/main.rs)
|
||||
for examples of the correct API.
|
||||
|
||||
## `cargo-leptos`
|
||||
|
||||
[`cargo-leptos`](https://github.com/akesson/cargo-leptos) is a build tool that's designed to make it easy to build apps that run on both the client and the server, with seamless integration. The best way to get started with a real Leptos project right now is to use `cargo-leptos` and our [starter template](https://github.com/leptos-rs/start).
|
||||
[`cargo-leptos`](https://github.com/leptos-rs/cargo-leptos) is a build tool that's designed to make it easy to build apps that run on both the client and the server, with seamless integration. The best way to get started with a real Leptos project right now is to use `cargo-leptos` and our [starter template](https://github.com/leptos-rs/start).
|
||||
|
||||
```bash
|
||||
cargo install cargo-leptos
|
||||
@@ -95,8 +95,28 @@ cd [your project name]
|
||||
cargo leptos watch
|
||||
```
|
||||
|
||||
Open browser on [http://localhost:3000/](http://localhost:3000/)
|
||||
|
||||
## FAQs
|
||||
|
||||
### Is it production ready?
|
||||
|
||||
People usually mean one of three things by this question.
|
||||
|
||||
1. **Are the APIs stable?** i.e., will I have to rewrite my whole app from Leptos 0.1 to 0.2 to 0.3 to 0.4, or can I write it now and benefit from new features and updates as new versions come?
|
||||
|
||||
With 0.1 the APIs are basically settled. We’re adding new features, but we’re very happy with where the type system and patterns have landed. I would not expect major breaking changes to your code to adapt to, for example, a 0.2.0 release.
|
||||
|
||||
2. **Are there bugs?**
|
||||
|
||||
Yes, I’m sure there are. You can see from the state of our issue tracker over time that there aren’t that _many_ bugs and they’re usually resolved pretty quickly. But for sure, there may be moments where you encounter something that requires a fix at the framework level, which may not be immediately resolved.
|
||||
|
||||
3. **Am I a consumer or a contributor?**
|
||||
|
||||
This may be the big one: “production ready” implies a certain orientation to a library: that you can basically use it, without any special knowledge of its internals or ability to contribute. Everyone has this at some level in their stack: for example I (@gbj) don’t have the capacity or knowledge to contribute to something like `wasm-bindgen` at this point: I simply rely on it to work.
|
||||
|
||||
There are several people in this community using Leptos right now for internal apps at work, who have also become significant contributors. I think this is the right level of production use for now. There may be missing features that you need, and you may end up building them! But for internal apps, if you’re willing to build and contribute missing pieces along the way, the framework is definitely usable right now.
|
||||
|
||||
### Can I use this for native GUI?
|
||||
|
||||
Sure! Obviously the `view` macro is for generating DOM nodes but you can use the reactive system to drive native any GUI toolkit that uses the same kind of object-oriented, event-callback-based framework as the DOM pretty easily. The principles are the same:
|
||||
@@ -106,7 +126,7 @@ Sure! Obviously the `view` macro is for generating DOM nodes but you can use the
|
||||
- Use event listeners to update signals
|
||||
- Create effects to update the UI
|
||||
|
||||
I've put together a [very simple GTK example](https://github.com/gbj/leptos/blob/main/examples/gtk/src/main.rs) so you can see what I mean.
|
||||
I've put together a [very simple GTK example](https://github.com/leptos-rs/leptos/blob/main/examples/gtk/src/main.rs) so you can see what I mean.
|
||||
|
||||
### How is this different from Yew/Dioxus?
|
||||
|
||||
@@ -124,7 +144,6 @@ There are some practical differences that make a significant difference:
|
||||
|
||||
- **Maturity:** Sycamore is obviously a much more mature and stable library with a larger ecosystem.
|
||||
- **Templating:** Leptos uses a JSX-like template format (built on [syn-rsx](https://github.com/stoically/syn-rsx)) for its `view` macro. Sycamore offers the choice of its own templating DSL or a builder syntax.
|
||||
- **Template node cloning:** Leptos's `view` macro compiles to a static HTML string and a set of instructions of how to assign its reactive values. This means that at runtime, Leptos can clone a `<template>` node rather than calling `document.createElement()` to create DOM nodes. This is a _significantly_ faster way of rendering components.
|
||||
- **Read-write segregation:** Leptos, like Solid, encourages read-write segregation between signal getters and setters, so you end up accessing signals with tuples like `let (count, set_count) = create_signal(cx, 0);` _(If you prefer or if it's more convenient for your API, you can use `create_rw_signal` to give a unified read/write signal.)_
|
||||
- **Signals are functions:** In Leptos, you can call a signal to access it rather than calling a specific method (so, `count()` instead of `count.get()`) This creates a more consistent mental model: accessing a reactive value is always a matter of calling a function. For example:
|
||||
|
||||
|
||||
@@ -2,9 +2,9 @@ use test::Bencher;
|
||||
|
||||
#[bench]
|
||||
fn leptos_ssr_bench(b: &mut Bencher) {
|
||||
b.iter(|| {
|
||||
b.iter(|| {
|
||||
use leptos::*;
|
||||
|
||||
HydrationCtx::reset_id();
|
||||
_ = create_scope(create_runtime(), |cx| {
|
||||
#[component]
|
||||
fn Counter(cx: Scope, initial: i32) -> impl IntoView {
|
||||
@@ -32,18 +32,17 @@ fn leptos_ssr_bench(b: &mut Bencher) {
|
||||
|
||||
assert_eq!(
|
||||
rendered,
|
||||
"<main><h1>Welcome to our benchmark page.</h1><p>Here's some introductory text.</p><div><button>-1</button><span>Value: <!>1<template id=\"_3\"></template>!</span><button>+1</button></div><template id=\"_1\"></template><div><button>-1</button><span>Value: <!>2<template id=\"_2\"></template>!</span><button>+1</button></div><template id=\"_0\"></template><div><button>-1</button><span>Value: <!>3<template id=\"_2\"></template>!</span><button>+1</button></div><template id=\"_0\"></template></main>"
|
||||
);
|
||||
"<main id=\"_0-1\"><h1 id=\"_0-2\">Welcome to our benchmark page.</h1><p id=\"_0-3\">Here's some introductory text.</p><div id=\"_0-3-1\"><button id=\"_0-3-2\">-1</button><span id=\"_0-3-3\">Value: <!>1<!--hk=_0-3-4-->!</span><button id=\"_0-3-5\">+1</button></div><!--hk=_0-3-0--><div id=\"_0-3-5-1\"><button id=\"_0-3-5-2\">-1</button><span id=\"_0-3-5-3\">Value: <!>2<!--hk=_0-3-5-4-->!</span><button id=\"_0-3-5-5\">+1</button></div><!--hk=_0-3-5-0--><div id=\"_0-3-5-5-1\"><button id=\"_0-3-5-5-2\">-1</button><span id=\"_0-3-5-5-3\">Value: <!>3<!--hk=_0-3-5-5-4-->!</span><button id=\"_0-3-5-5-5\">+1</button></div><!--hk=_0-3-5-5-0--></main>" );
|
||||
});
|
||||
});
|
||||
}
|
||||
/*
|
||||
|
||||
#[bench]
|
||||
fn tera_ssr_bench(b: &mut Bencher) {
|
||||
use tera::*;
|
||||
use serde::{Serialize, Deserialize};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tera::*;
|
||||
|
||||
static TEMPLATE: &str = r#"<main>
|
||||
static TEMPLATE: &str = r#"<main>
|
||||
<h1>Welcome to our benchmark page.</h1>
|
||||
<p>Here's some introductory text.</p>
|
||||
{% for counter in counters %}
|
||||
@@ -55,37 +54,40 @@ fn tera_ssr_bench(b: &mut Bencher) {
|
||||
{% endfor %}
|
||||
</main>"#;
|
||||
|
||||
lazy_static::lazy_static! {
|
||||
static ref TERA: Tera = {
|
||||
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 {
|
||||
value: i32
|
||||
}
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct Counter {
|
||||
value: i32,
|
||||
}
|
||||
|
||||
b.iter(|| {
|
||||
let mut ctx = Context::new();
|
||||
ctx.insert("counters", &vec![
|
||||
Counter { value: 0 },
|
||||
Counter { value: 1},
|
||||
Counter { value: 2 }
|
||||
]);
|
||||
b.iter(|| {
|
||||
let mut ctx = Context::new();
|
||||
ctx.insert(
|
||||
"counters",
|
||||
&vec![
|
||||
Counter { value: 0 },
|
||||
Counter { value: 1 },
|
||||
Counter { value: 2 },
|
||||
],
|
||||
);
|
||||
|
||||
let _ = TERA.render("template.html", &ctx).unwrap();
|
||||
});
|
||||
let _ = TERA.render("template.html", &ctx).unwrap();
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn sycamore_ssr_bench(b: &mut Bencher) {
|
||||
use sycamore::*;
|
||||
use sycamore::prelude::*;
|
||||
use sycamore::prelude::*;
|
||||
use sycamore::*;
|
||||
|
||||
b.iter(|| {
|
||||
b.iter(|| {
|
||||
_ = create_scope(|cx| {
|
||||
#[derive(Prop)]
|
||||
struct CounterProps {
|
||||
@@ -139,10 +141,10 @@ fn sycamore_ssr_bench(b: &mut Bencher) {
|
||||
|
||||
#[bench]
|
||||
fn yew_ssr_bench(b: &mut Bencher) {
|
||||
use yew::prelude::*;
|
||||
use yew::ServerRenderer;
|
||||
use yew::prelude::*;
|
||||
use yew::ServerRenderer;
|
||||
|
||||
b.iter(|| {
|
||||
b.iter(|| {
|
||||
#[derive(Properties, PartialEq, Eq, Debug)]
|
||||
struct CounterProps {
|
||||
initial: i32
|
||||
@@ -194,4 +196,3 @@ fn yew_ssr_bench(b: &mut Bencher) {
|
||||
});
|
||||
});
|
||||
}
|
||||
*/
|
||||
@@ -8,171 +8,165 @@ pub struct Todos(pub Vec<Todo>);
|
||||
const STORAGE_KEY: &str = "todos-leptos";
|
||||
|
||||
impl Todos {
|
||||
pub fn new(cx: Scope) -> Self {
|
||||
Self(vec![])
|
||||
}
|
||||
pub fn new(cx: Scope) -> Self {
|
||||
Self(vec![])
|
||||
}
|
||||
|
||||
pub fn new_with_1000(cx: Scope) -> Self {
|
||||
let todos = (0..1000)
|
||||
.map(|id| Todo::new(cx, id, format!("Todo #{id}")))
|
||||
.collect();
|
||||
Self(todos)
|
||||
}
|
||||
pub fn new_with_1000(cx: Scope) -> Self {
|
||||
let todos = (0..1000)
|
||||
.map(|id| Todo::new(cx, id, format!("Todo #{id}")))
|
||||
.collect();
|
||||
Self(todos)
|
||||
}
|
||||
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.0.is_empty()
|
||||
}
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.0.is_empty()
|
||||
}
|
||||
|
||||
pub fn add(&mut self, todo: Todo) {
|
||||
self.0.push(todo);
|
||||
}
|
||||
pub fn add(&mut self, todo: Todo) {
|
||||
self.0.push(todo);
|
||||
}
|
||||
|
||||
pub fn remove(&mut self, id: usize) {
|
||||
self.0.retain(|todo| todo.id != id);
|
||||
}
|
||||
pub fn remove(&mut self, id: usize) {
|
||||
self.0.retain(|todo| todo.id != id);
|
||||
}
|
||||
|
||||
pub fn remaining(&self) -> usize {
|
||||
self.0.iter().filter(|todo| !(todo.completed)()).count()
|
||||
}
|
||||
pub fn remaining(&self) -> usize {
|
||||
self.0.iter().filter(|todo| !(todo.completed)()).count()
|
||||
}
|
||||
|
||||
pub fn completed(&self) -> usize {
|
||||
self.0.iter().filter(|todo| (todo.completed)()).count()
|
||||
}
|
||||
pub fn completed(&self) -> usize {
|
||||
self.0.iter().filter(|todo| (todo.completed)()).count()
|
||||
}
|
||||
|
||||
pub fn toggle_all(&self) {
|
||||
// if all are complete, mark them all active instead
|
||||
if self.remaining() == 0 {
|
||||
for todo in &self.0 {
|
||||
if todo.completed.get() {
|
||||
(todo.set_completed)(false);
|
||||
pub fn toggle_all(&self) {
|
||||
// if all are complete, mark them all active instead
|
||||
if self.remaining() == 0 {
|
||||
for todo in &self.0 {
|
||||
if todo.completed.get() {
|
||||
(todo.set_completed)(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
// otherwise, mark them all complete
|
||||
else {
|
||||
for todo in &self.0 {
|
||||
(todo.set_completed)(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// otherwise, mark them all complete
|
||||
else {
|
||||
for todo in &self.0 {
|
||||
(todo.set_completed)(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn clear_completed(&mut self) {
|
||||
self.0.retain(|todo| !todo.completed.get());
|
||||
}
|
||||
fn clear_completed(&mut self) {
|
||||
self.0.retain(|todo| !todo.completed.get());
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||
pub struct Todo {
|
||||
pub id: usize,
|
||||
pub title: ReadSignal<String>,
|
||||
pub set_title: WriteSignal<String>,
|
||||
pub completed: ReadSignal<bool>,
|
||||
pub set_completed: WriteSignal<bool>,
|
||||
pub id: usize,
|
||||
pub title: ReadSignal<String>,
|
||||
pub set_title: WriteSignal<String>,
|
||||
pub completed: ReadSignal<bool>,
|
||||
pub set_completed: WriteSignal<bool>,
|
||||
}
|
||||
|
||||
impl Todo {
|
||||
pub fn new(cx: Scope, id: usize, title: String) -> Self {
|
||||
Self::new_with_completed(cx, id, title, false)
|
||||
}
|
||||
|
||||
pub fn new_with_completed(
|
||||
cx: Scope,
|
||||
id: usize,
|
||||
title: String,
|
||||
completed: bool,
|
||||
) -> Self {
|
||||
let (title, set_title) = create_signal(cx, title);
|
||||
let (completed, set_completed) = create_signal(cx, completed);
|
||||
Self {
|
||||
id,
|
||||
title,
|
||||
set_title,
|
||||
completed,
|
||||
set_completed,
|
||||
pub fn new(cx: Scope, id: usize, title: String) -> Self {
|
||||
Self::new_with_completed(cx, id, title, false)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn toggle(&self) {
|
||||
self
|
||||
.set_completed
|
||||
.update(|completed| *completed = !*completed);
|
||||
}
|
||||
pub fn new_with_completed(cx: Scope, id: usize, title: String, completed: bool) -> Self {
|
||||
let (title, set_title) = create_signal(cx, title);
|
||||
let (completed, set_completed) = create_signal(cx, completed);
|
||||
Self {
|
||||
id,
|
||||
title,
|
||||
set_title,
|
||||
completed,
|
||||
set_completed,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn toggle(&self) {
|
||||
self.set_completed
|
||||
.update(|completed| *completed = !*completed);
|
||||
}
|
||||
}
|
||||
|
||||
const ESCAPE_KEY: u32 = 27;
|
||||
const ENTER_KEY: u32 = 13;
|
||||
|
||||
#[component]
|
||||
pub fn TodoMVC(cx: Scope,todos: Todos) -> impl IntoView {
|
||||
let mut next_id = todos
|
||||
.0
|
||||
.iter()
|
||||
.map(|todo| todo.id)
|
||||
.max()
|
||||
.map(|last| last + 1)
|
||||
.unwrap_or(0);
|
||||
|
||||
let (todos, set_todos) = create_signal(cx, todos);
|
||||
provide_context(cx, set_todos);
|
||||
|
||||
let (mode, set_mode) = create_signal(cx, Mode::All);
|
||||
window_event_listener("hashchange", move |_| {
|
||||
let new_mode = location_hash().map(|hash| route(&hash)).unwrap_or_default();
|
||||
set_mode(new_mode);
|
||||
});
|
||||
|
||||
let add_todo = move |ev: web_sys::KeyboardEvent| {
|
||||
let target = event_target::<HtmlInputElement>(&ev);
|
||||
ev.stop_propagation();
|
||||
let key_code = ev.unchecked_ref::<web_sys::KeyboardEvent>().key_code();
|
||||
if key_code == ENTER_KEY {
|
||||
let title = event_target_value(&ev);
|
||||
let title = title.trim();
|
||||
if !title.is_empty() {
|
||||
let new = Todo::new(cx, next_id, title.to_string());
|
||||
set_todos.update(|t| t.add(new));
|
||||
next_id += 1;
|
||||
target.set_value("");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let filtered_todos = create_memo::<Vec<Todo>>(cx, move |_| {
|
||||
todos.with(|todos| match mode.get() {
|
||||
Mode::All => todos.0.to_vec(),
|
||||
Mode::Active => todos
|
||||
pub fn TodoMVC(cx: Scope, todos: Todos) -> impl IntoView {
|
||||
let mut next_id = todos
|
||||
.0
|
||||
.iter()
|
||||
.filter(|todo| !todo.completed.get())
|
||||
.cloned()
|
||||
.collect(),
|
||||
Mode::Completed => todos
|
||||
.0
|
||||
.iter()
|
||||
.filter(|todo| todo.completed.get())
|
||||
.cloned()
|
||||
.collect(),
|
||||
})
|
||||
});
|
||||
.map(|todo| todo.id)
|
||||
.max()
|
||||
.map(|last| last + 1)
|
||||
.unwrap_or(0);
|
||||
|
||||
// effect to serialize to JSON
|
||||
// this does reactive reads, so it will automatically serialize on any relevant change
|
||||
create_effect(cx, move |_| {
|
||||
if let Ok(Some(storage)) = window().local_storage() {
|
||||
let objs = todos
|
||||
.get()
|
||||
.0
|
||||
.iter()
|
||||
.map(TodoSerialized::from)
|
||||
.collect::<Vec<_>>();
|
||||
let json = json::to_string(&objs);
|
||||
if storage.set_item(STORAGE_KEY, &json).is_err() {
|
||||
log::error!("error while trying to set item in localStorage");
|
||||
}
|
||||
}
|
||||
});
|
||||
let (todos, set_todos) = create_signal(cx, todos);
|
||||
provide_context(cx, set_todos);
|
||||
|
||||
view! { cx,
|
||||
let (mode, set_mode) = create_signal(cx, Mode::All);
|
||||
window_event_listener("hashchange", move |_| {
|
||||
let new_mode = location_hash().map(|hash| route(&hash)).unwrap_or_default();
|
||||
set_mode(new_mode);
|
||||
});
|
||||
|
||||
let add_todo = move |ev: web_sys::KeyboardEvent| {
|
||||
let target = event_target::<HtmlInputElement>(&ev);
|
||||
ev.stop_propagation();
|
||||
let key_code = ev.unchecked_ref::<web_sys::KeyboardEvent>().key_code();
|
||||
if key_code == ENTER_KEY {
|
||||
let title = event_target_value(&ev);
|
||||
let title = title.trim();
|
||||
if !title.is_empty() {
|
||||
let new = Todo::new(cx, next_id, title.to_string());
|
||||
set_todos.update(|t| t.add(new));
|
||||
next_id += 1;
|
||||
target.set_value("");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let filtered_todos = create_memo::<Vec<Todo>>(cx, move |_| {
|
||||
todos.with(|todos| match mode.get() {
|
||||
Mode::All => todos.0.to_vec(),
|
||||
Mode::Active => todos
|
||||
.0
|
||||
.iter()
|
||||
.filter(|todo| !todo.completed.get())
|
||||
.cloned()
|
||||
.collect(),
|
||||
Mode::Completed => todos
|
||||
.0
|
||||
.iter()
|
||||
.filter(|todo| todo.completed.get())
|
||||
.cloned()
|
||||
.collect(),
|
||||
})
|
||||
});
|
||||
|
||||
// effect to serialize to JSON
|
||||
// this does reactive reads, so it will automatically serialize on any relevant change
|
||||
create_effect(cx, move |_| {
|
||||
if let Ok(Some(storage)) = window().local_storage() {
|
||||
let objs = todos
|
||||
.get()
|
||||
.0
|
||||
.iter()
|
||||
.map(TodoSerialized::from)
|
||||
.collect::<Vec<_>>();
|
||||
let json = json::to_string(&objs);
|
||||
if storage.set_item(STORAGE_KEY, &json).is_err() {
|
||||
log::error!("error while trying to set item in localStorage");
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
view! { cx,
|
||||
<main>
|
||||
<section class="todoapp">
|
||||
<header class="header">
|
||||
@@ -228,100 +222,100 @@ pub fn TodoMVC(cx: Scope,todos: Todos) -> impl IntoView {
|
||||
|
||||
#[component]
|
||||
pub fn Todo(cx: Scope, todo: Todo) -> impl IntoView {
|
||||
let (editing, set_editing) = create_signal(cx, false);
|
||||
let set_todos = use_context::<WriteSignal<Todos>>(cx).unwrap();
|
||||
//let input = NodeRef::new(cx);
|
||||
let (editing, set_editing) = create_signal(cx, false);
|
||||
let set_todos = use_context::<WriteSignal<Todos>>(cx).unwrap();
|
||||
//let input = NodeRef::new(cx);
|
||||
|
||||
let save = move |value: &str| {
|
||||
let value = value.trim();
|
||||
if value.is_empty() {
|
||||
set_todos.update(|t| t.remove(todo.id));
|
||||
} else {
|
||||
(todo.set_title)(value.to_string());
|
||||
let save = move |value: &str| {
|
||||
let value = value.trim();
|
||||
if value.is_empty() {
|
||||
set_todos.update(|t| t.remove(todo.id));
|
||||
} else {
|
||||
(todo.set_title)(value.to_string());
|
||||
}
|
||||
set_editing(false);
|
||||
};
|
||||
|
||||
view! { cx,
|
||||
<li
|
||||
class="todo"
|
||||
class:editing={editing}
|
||||
class:completed={move || (todo.completed)()}
|
||||
//_ref=input
|
||||
>
|
||||
<div class="view">
|
||||
<input
|
||||
class="toggle"
|
||||
type="checkbox"
|
||||
prop:checked={move || (todo.completed)()}
|
||||
|
||||
/>
|
||||
<label on:dblclick=move |_| set_editing(true)>
|
||||
{move || todo.title.get()}
|
||||
</label>
|
||||
<button class="destroy" on:click=move |_| set_todos.update(|t| t.remove(todo.id))/>
|
||||
</div>
|
||||
{move || editing().then(|| view! { cx,
|
||||
<input
|
||||
class="edit"
|
||||
class:hidden={move || !(editing)()}
|
||||
prop:value={move || todo.title.get()}
|
||||
on:focusout=move |ev| save(&event_target_value(&ev))
|
||||
on:keyup={move |ev| {
|
||||
let key_code = ev.unchecked_ref::<web_sys::KeyboardEvent>().key_code();
|
||||
if key_code == ENTER_KEY {
|
||||
save(&event_target_value(&ev));
|
||||
} else if key_code == ESCAPE_KEY {
|
||||
set_editing(false);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
})
|
||||
}
|
||||
</li>
|
||||
}
|
||||
set_editing(false);
|
||||
};
|
||||
|
||||
view! { cx,
|
||||
<li
|
||||
class="todo"
|
||||
class:editing={editing}
|
||||
class:completed={move || (todo.completed)()}
|
||||
//_ref=input
|
||||
>
|
||||
<div class="view">
|
||||
<input
|
||||
class="toggle"
|
||||
type="checkbox"
|
||||
prop:checked={move || (todo.completed)()}
|
||||
|
||||
/>
|
||||
<label on:dblclick=move |_| set_editing(true)>
|
||||
{move || todo.title.get()}
|
||||
</label>
|
||||
<button class="destroy" on:click=move |_| set_todos.update(|t| t.remove(todo.id))/>
|
||||
</div>
|
||||
{move || editing().then(|| view! { cx,
|
||||
<input
|
||||
class="edit"
|
||||
class:hidden={move || !(editing)()}
|
||||
prop:value={move || todo.title.get()}
|
||||
on:focusout=move |ev| save(&event_target_value(&ev))
|
||||
on:keyup={move |ev| {
|
||||
let key_code = ev.unchecked_ref::<web_sys::KeyboardEvent>().key_code();
|
||||
if key_code == ENTER_KEY {
|
||||
save(&event_target_value(&ev));
|
||||
} else if key_code == ESCAPE_KEY {
|
||||
set_editing(false);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
})
|
||||
}
|
||||
</li>
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum Mode {
|
||||
Active,
|
||||
Completed,
|
||||
All,
|
||||
Active,
|
||||
Completed,
|
||||
All,
|
||||
}
|
||||
|
||||
impl Default for Mode {
|
||||
fn default() -> Self {
|
||||
Mode::All
|
||||
}
|
||||
fn default() -> Self {
|
||||
Mode::All
|
||||
}
|
||||
}
|
||||
|
||||
pub fn route(hash: &str) -> Mode {
|
||||
match hash {
|
||||
"/active" => Mode::Active,
|
||||
"/completed" => Mode::Completed,
|
||||
_ => Mode::All,
|
||||
}
|
||||
match hash {
|
||||
"/active" => Mode::Active,
|
||||
"/completed" => Mode::Completed,
|
||||
_ => Mode::All,
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct TodoSerialized {
|
||||
pub id: usize,
|
||||
pub title: String,
|
||||
pub completed: bool,
|
||||
pub id: usize,
|
||||
pub title: String,
|
||||
pub completed: bool,
|
||||
}
|
||||
|
||||
impl TodoSerialized {
|
||||
pub fn into_todo(self, cx: Scope) -> Todo {
|
||||
Todo::new_with_completed(cx, self.id, self.title, self.completed)
|
||||
}
|
||||
pub fn into_todo(self, cx: Scope) -> Todo {
|
||||
Todo::new_with_completed(cx, self.id, self.title, self.completed)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&Todo> for TodoSerialized {
|
||||
fn from(todo: &Todo) -> Self {
|
||||
Self {
|
||||
id: todo.id,
|
||||
title: todo.title.get(),
|
||||
completed: (todo.completed)(),
|
||||
fn from(todo: &Todo) -> Self {
|
||||
Self {
|
||||
id: todo.id,
|
||||
title: todo.title.get(),
|
||||
completed: (todo.completed)(),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,9 @@ fn leptos_todomvc_ssr(b: &mut Bencher) {
|
||||
let rendered = view! {
|
||||
cx,
|
||||
<TodoMVC todos=Todos::new(cx)/>
|
||||
}.into_view(cx).render_to_string(cx);
|
||||
}
|
||||
.into_view(cx)
|
||||
.render_to_string(cx);
|
||||
|
||||
assert!(rendered.len() > 1);
|
||||
});
|
||||
@@ -55,7 +57,7 @@ fn yew_todomvc_ssr(b: &mut Bencher) {
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
#[bench]
|
||||
fn leptos_todomvc_ssr_with_1000(b: &mut Bencher) {
|
||||
b.iter(|| {
|
||||
@@ -107,3 +109,4 @@ fn yew_todomvc_ssr_with_1000(b: &mut Bencher) {
|
||||
});
|
||||
});
|
||||
}
|
||||
*/
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Introduction
|
||||
|
||||
This book is intended as an introduction to the [Leptos](https://github.com/gbj/leptos) Web framework. Together, we’ll build a simple todo app—first as a client-side app, then as a full-stack app.
|
||||
This book is intended as an introduction to the [Leptos](https://github.com/leptos-rs/leptos) Web framework. Together, we’ll build a simple todo app—first as a client-side app, then as a full-stack app.
|
||||
|
||||
The guide doesn’t assume you know anything about fine-grained reactivity or the details of modern Web frameworks. It does assume you are familiar with the Rust programming language, HTML, CSS, and the DOM and other Web APIs.
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
# Getting Started
|
||||
|
||||
> The code for this chapter can be found [here](https://github.com/gbj/leptos/tree/main/docs/book/project/ch02_getting_started).
|
||||
> The code for this chapter can be found [here](https://github.com/leptos-rs/leptos/tree/main/docs/book/project/ch02_getting_started).
|
||||
|
||||
The easiest way to get started using Leptos is to use [Trunk](https://trunkrs.dev/), as many of our [examples](https://github.com/gbj/leptos/tree/main/examples) do. (Trunk is a simple build tool that includes a dev server.)
|
||||
The easiest way to get started using Leptos is to use [Trunk](https://trunkrs.dev/), as many of our [examples](https://github.com/leptos-rs/leptos/tree/main/examples) do. (Trunk is a simple build tool that includes a dev server.)
|
||||
|
||||
If you don’t already have it installed, you can install Trunk by running
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Templating: Building User Interfaces
|
||||
|
||||
> The code for this chapter can be found [here](https://github.com/gbj/leptos/tree/main/docs/book/project/ch03_building_ui).
|
||||
> The code for this chapter can be found [here](https://github.com/leptos-rs/leptos/tree/main/docs/book/project/ch03_building_ui).
|
||||
|
||||
## RSX and the `view!` macro
|
||||
|
||||
|
||||
BIN
docs/logos/Leptos_logo_RGB.png
Executable file
|
After Width: | Height: | Size: 72 KiB |
64
docs/logos/Leptos_logo_RGB.svg
Executable file
@@ -0,0 +1,64 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 27.1.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 437.4294 209.6185" style="enable-background:new 0 0 437.4294 209.6185;" xml:space="preserve">
|
||||
<path style="fill:none;" d="M130.0327,79.3931c-11.4854-0.23-22.52,9.3486-24.5034,21.0117l49.1157,0.0293
|
||||
c-2.1729-10.418-11.1821-21.0449-24.1987-21.0449C130.3081,79.3892,130.1714,79.3907,130.0327,79.3931z"/>
|
||||
<path style="fill:#181139;" d="M95.1109,128.1089H58.6797V65.6861c0-1.5234-0.8169-2.4331-2.1855-2.4331h-3.1187
|
||||
c-1.3159,0-2.2349,1.0005-2.2349,2.4331v67.4297c0,1.4521,0.8145,2.2852,2.2349,2.2852h41.7353c1.4844,0,2.4819-0.9375,2.4819-2.333
|
||||
v-2.7744C97.5928,128.9253,96.6651,128.1089,95.1109,128.1089z"/>
|
||||
<path style="fill:#181139;" d="M146.4561,77.1739c-4.8252-3.001-10.3037-4.5249-16.2837-4.5288c-0.0068,0-0.0137,0-0.0205,0
|
||||
c-5.7349,0-11.1377,1.4639-16.0566,4.3511c-4.916,2.8853-8.8721,6.8364-11.7593,11.7456
|
||||
c-2.8975,4.9248-4.3687,10.332-4.3721,16.0713c-0.0034,5.7188,1.4966,11.0654,4.4565,15.8887
|
||||
c2.9893,4.9209,6.8789,8.7334,11.8887,11.6514c4.8657,2.8633,10.2397,4.3174,15.9717,4.3203c0.0073,0,0.0146,0,0.022,0
|
||||
c8.123,0,14.7441-2.5869,21.4683-8.3906c0.5493-0.4805,0.8516-1.1201,0.8516-1.8008c0.001-0.6074-0.1743-1.1035-0.5205-1.4756
|
||||
l-1.3569-1.8428l-0.0732-0.0859c-0.2637-0.2637-0.6929-0.6152-1.3716-0.6152c-0.6421,0-1.2549,0.2217-1.7124,0.6143
|
||||
c-1.9346,1.585-3.5459,2.8008-4.7969,3.6182c-1.7979,1.208-5.8218,3.2314-12.5986,3.2314c-0.0073,0-0.0142,0-0.021,0
|
||||
c-0.1357,0.0029-0.269,0.0039-0.4043,0.0039c-12.2642,0-23.4736-10.3262-24.5088-22.4814l53.0127,0.0322c0.0015,0,0.0024,0,0.0034,0
|
||||
c2.2373,0,3.4697-1.1621,3.4712-3.2715c0.0034-5.2588-1.3574-10.3945-4.0464-15.2705
|
||||
C155.0015,84.0953,151.2188,80.1363,146.4561,77.1739z M154.6451,100.4341l-49.1157-0.0293
|
||||
c1.9834-11.6631,13.0181-21.2417,24.5034-21.0117c0.1387-0.0024,0.2754-0.0039,0.4136-0.0039
|
||||
C143.4629,79.3892,152.4722,90.0162,154.6451,100.4341z"/>
|
||||
<path style="fill:#181139;" d="M204.0386,136.6382c5.7319,0,11.1069-1.4502,15.9746-4.3115
|
||||
c4.938-2.9014,8.75-6.7129,11.6533-11.6533c2.8608-4.8672,4.311-10.2578,4.311-16.0244c0-5.7324-1.4502-11.1064-4.311-15.9746
|
||||
c-2.9019-4.9385-6.7134-8.75-11.6533-11.6533c-4.8687-2.8618-10.2437-4.3125-15.9746-4.3125
|
||||
c-9.938,0-19.2021,4.7583-24.3516,12.3174v-9.438c0-0.5946-0.1465-1.0788-0.411-1.4511c-0.3815-0.5369-1.0157-0.834-1.8727-0.834
|
||||
h-2.6738c-1.4521,0-2.2852,0.833-2.2852,2.2852v5.6964v46.4791v23.9676c0,1.2568,0.7808,2.0371,2.0371,2.0371h3.3667
|
||||
c0.9209,0,1.6421-0.6992,1.6421-1.5908v-17.098v-10.984C185.0884,131.8892,194.2749,136.6382,204.0386,136.6382z M186.6358,122.5591
|
||||
c-4.9346-4.9346-7.6831-11.4932-7.542-18.0254c-0.1367-6.3506,2.5439-12.751,7.3545-17.5605
|
||||
c4.8521-4.8521,11.3037-7.5547,17.7383-7.417c4.3691,0,8.4863,1.1465,12.2314,3.4043c3.7344,2.2979,6.7456,5.4053,8.9492,9.2354
|
||||
c2.1699,3.9072,3.2695,8.0967,3.2695,12.4697c0.1396,6.4619-2.5967,12.9844-7.5083,17.8955
|
||||
c-4.7617,4.7617-11.0469,7.3857-17.2544,7.2803C197.6856,129.9712,191.396,127.3208,186.6358,122.5591z"/>
|
||||
<path style="fill:#181139;" d="M241.8955,80.3975h7.5669v42.0259c0,6.8174,4.5674,12.1309,11.0825,12.9189
|
||||
c0.6836,0.1055,1.8379,0.1572,3.5303,0.1572c2.0078,0,3.0273-0.3535,3.0273-2.2842v-2.377c0-1.7891-1.334-2.0371-2.7568-2.0371
|
||||
c0,0-0.001,0-0.002,0l-1.7871-0.0488c-2.0117-0.0439-3.4883-0.7627-4.3896-2.1367c-0.9697-1.4805-1.4619-3.1738-1.4619-5.0352
|
||||
V80.3975h10.0928c1.3076,0,2.2852-1.3628,2.2852-2.5815v-1.9312c0-1.3999-0.8359-2.2354-2.2354-2.2354h-10.1426V60.6861
|
||||
c0-1.4619-0.7969-2.4829-1.9375-2.4829c-0.1865,0-0.4121,0-0.6392,0.0884l-2.6489,0.6865
|
||||
c-1.2109,0.3682-2.0171,0.9263-2.0171,2.4507v12.2207h-7.5669c-1.4185,0-2.335,0.897-2.335,2.2852v1.8813
|
||||
C239.5606,79.2393,240.6079,80.3975,241.8955,80.3975z"/>
|
||||
<path style="fill:#181139;" d="M379.1182,106.2691c-4.0488-2.9219-8.8545-5.0293-14.291-6.2646
|
||||
c-6.5049-1.3975-13.4473-5.2129-13.3203-10.3066c0-7.5225,6.6367-10.1914,12.3203-10.1914c5.3574,0,10.2207,3.002,13.001,8.0146
|
||||
c0.6729,1.2861,1.4785,1.9375,2.3955,1.9375c0.3311,0,0.7061-0.1113,0.9922-0.2832l2.2021-1.1523
|
||||
c0.5947-0.3408,0.9229-0.9414,0.9229-1.6924c0-0.5205-0.0908-0.9541-0.2617-1.292c-3.6367-8.2466-10.0967-12.4282-19.2021-12.4282
|
||||
c-11.7305,0-19.6123,6.9263-19.6123,17.2349c0,4.3125,1.8438,7.9746,5.4756,10.8809c3.4482,2.7979,7.9121,4.8623,13.2705,6.1377
|
||||
c4.5859,1.085,8.3193,2.5654,11.0977,4.4023c1.4159,0.9354,2.4412,2.0535,3.106,3.3672c0.6053,1.1962,0.9135,2.5535,0.9135,4.1005
|
||||
c0.0742,2.3857-0.79,4.5176-2.5684,6.3389c-3.1445,3.2178-8.4053,4.6689-12.0205,4.6689c-0.0361,0-0.0723,0-0.1074,0
|
||||
c-3.4268,0-6.4893-0.8438-9.1035-2.5068c-2.5918-1.6484-4.2363-3.8076-5.0293-6.6064c-0.3203-1.0996-0.751-2.1738-2.1553-2.1738
|
||||
c-0.0742,0-0.2109,0.0146-0.4062,0.0449c-0.1133,0.0166-0.2559,0.0381-0.5088,0.0742l-1.8818,0.4463l-0.1045,0.0332
|
||||
c-1.0244,0.4082-1.6113,1.1846-1.6113,2.1309c0,0.2285,0.0625,0.6592,0.2178,1.1094c1.9707,8.5801,10.2432,14.3447,20.5732,14.3447
|
||||
c0.125,0.002,0.249,0.002,0.374,0.002c6.5947,0,12.6748-2.3193,16.7275-6.3945c3.1895-3.208,4.8311-7.2363,4.748-11.6357
|
||||
c0-2.8187-0.6185-5.3109-1.8062-7.481C382.4437,109.2624,381.0062,107.631,379.1182,106.2691z"/>
|
||||
<path style="fill:#EF3939;" d="M348.9043,45.7325c0-6.3157-3.2826-11.8699-8.2238-15.0756
|
||||
c-2.811-1.8237-6.1537-2.8947-9.7469-2.8947c-9.9092,0-17.9707,8.0615-17.9707,17.9702c0,4.7659,1.8775,9.0925,4.9157,12.3123
|
||||
c-3.6619,4.3709-6.6334,9.3336-8.7663,14.7186c-1.5873-0.2422-3.2123-0.3683-4.8662-0.3683
|
||||
c-17.7158,0-32.1289,14.4131-32.1289,32.1289c0,14.6854,9.9077,27.0922,23.3869,30.9101
|
||||
c-6.7762,17.3461-23.6572,29.6719-43.3742,29.6719c-16.8195,0-31.583-8.9662-39.7656-22.369
|
||||
c-2.4778,0.5446-5.0429,0.8519-7.6721,0.9023c9.0226,16.99,26.8969,28.5917,47.4377,28.5917
|
||||
c23.2646,0,43.1121-14.8788,50.5461-35.6179c0.5204,0.0251,1.0435,0.0398,1.5701,0.0398c17.7158,0,32.1289-14.4131,32.1289-32.1289
|
||||
c0-13.557-8.4446-25.1712-20.3465-29.8811c1.9001-4.5678,4.5115-8.7646,7.6888-12.4641c0.9996,0.4404,2.0479,0.785,3.1324,1.0384
|
||||
c1.3144,0.3071,2.6773,0.486,4.0839,0.486C340.8428,63.7032,348.9043,55.6416,348.9043,45.7325z M304.2461,129.5279
|
||||
c-13.7871,0-25.0039-11.2168-25.0039-25.0039s11.2168-25.0039,25.0039-25.0039S329.25,90.7369,329.25,104.524
|
||||
S318.0332,129.5279,304.2461,129.5279z M330.9336,34.8872c0.645,0,1.2737,0.0671,1.8881,0.1755
|
||||
c5.0818,0.8974,8.9576,5.3347,8.9576,10.6697c0,5.9805-4.8652,10.8457-10.8457,10.8457s-10.8457-4.8652-10.8457-10.8457
|
||||
c0-1.3967,0.2746-2.7282,0.7576-3.9555C322.4306,37.7496,326.35,34.8872,330.9336,34.8872z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 6.5 KiB |
61
docs/logos/Leptos_logo_Solid_Black.svg
Executable file
@@ -0,0 +1,61 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 27.1.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 437.4294 209.6185" style="enable-background:new 0 0 437.4294 209.6185;" xml:space="preserve">
|
||||
<path d="M95.1109,128.1089H58.6797V65.6861c0-1.5234-0.8169-2.4331-2.1855-2.4331h-3.1187c-1.3159,0-2.2349,1.0005-2.2349,2.4331
|
||||
v67.4297c0,1.4521,0.8145,2.2852,2.2349,2.2852h41.7353c1.4844,0,2.4819-0.9375,2.4819-2.333v-2.7744
|
||||
C97.5928,128.9253,96.6651,128.1089,95.1109,128.1089z"/>
|
||||
<path d="M146.4561,77.1739c-4.8252-3.001-10.3037-4.5249-16.2837-4.5288c-0.0068,0-0.0137,0-0.0205,0
|
||||
c-5.7349,0-11.1377,1.4639-16.0566,4.3511c-4.916,2.8853-8.8721,6.8364-11.7593,11.7456
|
||||
c-2.8975,4.9248-4.3687,10.332-4.3721,16.0713c-0.0034,5.7188,1.4966,11.0654,4.4565,15.8887
|
||||
c2.9893,4.9209,6.8789,8.7334,11.8887,11.6514c4.8657,2.8633,10.2397,4.3174,15.9717,4.3203c0.0073,0,0.0146,0,0.022,0
|
||||
c8.123,0,14.7441-2.5869,21.4683-8.3906c0.5493-0.4805,0.8516-1.1201,0.8516-1.8008c0.001-0.6074-0.1743-1.1035-0.5205-1.4756
|
||||
l-1.3569-1.8428l-0.0732-0.0859c-0.2637-0.2637-0.6929-0.6152-1.3716-0.6152c-0.6421,0-1.2549,0.2217-1.7124,0.6143
|
||||
c-1.9346,1.585-3.5459,2.8008-4.7969,3.6182c-1.7979,1.208-5.8218,3.2314-12.5986,3.2314c-0.0073,0-0.0142,0-0.021,0
|
||||
c-0.1357,0.0029-0.269,0.0039-0.4043,0.0039c-12.2642,0-23.4736-10.3262-24.5088-22.4814l53.0127,0.0322c0.0015,0,0.0024,0,0.0034,0
|
||||
c2.2373,0,3.4697-1.1621,3.4712-3.2715c0.0034-5.2588-1.3574-10.3945-4.0464-15.2705
|
||||
C155.0015,84.0953,151.2188,80.1363,146.4561,77.1739z M154.6451,100.4341l-49.1157-0.0293
|
||||
c1.9834-11.6631,13.0181-21.2417,24.5034-21.0117c0.1387-0.0024,0.2754-0.0039,0.4136-0.0039
|
||||
C143.4629,79.3892,152.4722,90.0162,154.6451,100.4341z"/>
|
||||
<path d="M204.0386,136.6382c5.7319,0,11.1069-1.4502,15.9746-4.3115c4.938-2.9014,8.75-6.7129,11.6533-11.6533
|
||||
c2.8608-4.8672,4.311-10.2578,4.311-16.0244c0-5.7324-1.4502-11.1064-4.311-15.9746c-2.9019-4.9385-6.7134-8.75-11.6533-11.6533
|
||||
c-4.8687-2.8618-10.2437-4.3125-15.9746-4.3125c-9.938,0-19.2021,4.7583-24.3516,12.3174v-9.438
|
||||
c0-0.5946-0.1465-1.0788-0.411-1.4511c-0.3815-0.5369-1.0157-0.834-1.8727-0.834h-2.6738c-1.4521,0-2.2852,0.833-2.2852,2.2852
|
||||
v5.6964v46.4791v23.9676c0,1.2568,0.7808,2.0371,2.0371,2.0371h3.3667c0.9209,0,1.6421-0.6992,1.6421-1.5908v-17.098v-10.984
|
||||
C185.0884,131.8892,194.2749,136.6382,204.0386,136.6382z M186.6358,122.5591c-4.9346-4.9346-7.6831-11.4932-7.542-18.0254
|
||||
c-0.1367-6.3506,2.5439-12.751,7.3545-17.5605c4.8521-4.8521,11.3037-7.5547,17.7383-7.417c4.3691,0,8.4863,1.1465,12.2314,3.4043
|
||||
c3.7344,2.2979,6.7456,5.4053,8.9492,9.2354c2.1699,3.9072,3.2695,8.0967,3.2695,12.4697
|
||||
c0.1396,6.4619-2.5967,12.9844-7.5083,17.8955c-4.7617,4.7617-11.0469,7.3857-17.2544,7.2803
|
||||
C197.6856,129.9712,191.396,127.3208,186.6358,122.5591z"/>
|
||||
<path d="M241.8955,80.3975h7.5669v42.0259c0,6.8174,4.5674,12.1309,11.0825,12.9189c0.6836,0.1055,1.8379,0.1572,3.5303,0.1572
|
||||
c2.0078,0,3.0273-0.3535,3.0273-2.2842v-2.377c0-1.7891-1.334-2.0371-2.7568-2.0371c0,0-0.001,0-0.002,0l-1.7871-0.0488
|
||||
c-2.0117-0.0439-3.4883-0.7627-4.3896-2.1367c-0.9697-1.4805-1.4619-3.1738-1.4619-5.0352V80.3975h10.0928
|
||||
c1.3076,0,2.2852-1.3628,2.2852-2.5815v-1.9312c0-1.3999-0.8359-2.2354-2.2354-2.2354h-10.1426V60.6861
|
||||
c0-1.4619-0.7969-2.4829-1.9375-2.4829c-0.1865,0-0.4121,0-0.6392,0.0884l-2.6489,0.6865
|
||||
c-1.2109,0.3682-2.0171,0.9263-2.0171,2.4507v12.2207h-7.5669c-1.4185,0-2.335,0.897-2.335,2.2852v1.8813
|
||||
C239.5606,79.2393,240.6079,80.3975,241.8955,80.3975z"/>
|
||||
<path d="M379.1182,106.2691c-4.0488-2.9219-8.8545-5.0293-14.291-6.2646c-6.5049-1.3975-13.4473-5.2129-13.3203-10.3066
|
||||
c0-7.5225,6.6367-10.1914,12.3203-10.1914c5.3574,0,10.2207,3.002,13.001,8.0146c0.6729,1.2861,1.4785,1.9375,2.3955,1.9375
|
||||
c0.3311,0,0.7061-0.1113,0.9922-0.2832l2.2021-1.1523c0.5947-0.3408,0.9229-0.9414,0.9229-1.6924
|
||||
c0-0.5205-0.0908-0.9541-0.2617-1.292c-3.6367-8.2466-10.0967-12.4282-19.2021-12.4282c-11.7305,0-19.6123,6.9263-19.6123,17.2349
|
||||
c0,4.3125,1.8438,7.9746,5.4756,10.8809c3.4482,2.7979,7.9121,4.8623,13.2705,6.1377c4.5859,1.085,8.3193,2.5654,11.0977,4.4023
|
||||
c1.4159,0.9354,2.4412,2.0535,3.106,3.3672c0.6053,1.1962,0.9135,2.5535,0.9135,4.1005c0.0742,2.3857-0.79,4.5176-2.5684,6.3389
|
||||
c-3.1445,3.2178-8.4053,4.6689-12.0205,4.6689c-0.0361,0-0.0723,0-0.1074,0c-3.4268,0-6.4893-0.8438-9.1035-2.5068
|
||||
c-2.5918-1.6484-4.2363-3.8076-5.0293-6.6064c-0.3203-1.0996-0.751-2.1738-2.1553-2.1738c-0.0742,0-0.2109,0.0146-0.4062,0.0449
|
||||
c-0.1133,0.0166-0.2559,0.0381-0.5088,0.0742l-1.8818,0.4463l-0.1045,0.0332c-1.0244,0.4082-1.6113,1.1846-1.6113,2.1309
|
||||
c0,0.2285,0.0625,0.6592,0.2178,1.1094c1.9707,8.5801,10.2432,14.3447,20.5732,14.3447c0.125,0.002,0.249,0.002,0.374,0.002
|
||||
c6.5947,0,12.6748-2.3193,16.7275-6.3945c3.1895-3.208,4.8311-7.2363,4.748-11.6357c0-2.8187-0.6185-5.3109-1.8062-7.481
|
||||
C382.4437,109.2624,381.0062,107.631,379.1182,106.2691z"/>
|
||||
<path d="M348.9043,45.7325c0-6.3157-3.2826-11.8699-8.2238-15.0756c-2.811-1.8237-6.1537-2.8947-9.7469-2.8947
|
||||
c-9.9092,0-17.9707,8.0615-17.9707,17.9702c0,4.7659,1.8775,9.0925,4.9157,12.3123c-3.6619,4.3709-6.6334,9.3336-8.7663,14.7186
|
||||
c-1.5873-0.2422-3.2123-0.3683-4.8662-0.3683c-17.7158,0-32.1289,14.4131-32.1289,32.1289c0,14.6854,9.9077,27.0922,23.3869,30.9101
|
||||
c-6.7762,17.3461-23.6572,29.6719-43.3742,29.6719c-16.8195,0-31.583-8.9662-39.7656-22.369
|
||||
c-2.4778,0.5446-5.0429,0.8519-7.6721,0.9023c9.0226,16.99,26.8969,28.5917,47.4377,28.5917
|
||||
c23.2646,0,43.1121-14.8788,50.5461-35.6179c0.5204,0.0251,1.0435,0.0398,1.5701,0.0398c17.7158,0,32.1289-14.4131,32.1289-32.1289
|
||||
c0-13.557-8.4446-25.1712-20.3465-29.8811c1.9001-4.5678,4.5115-8.7646,7.6888-12.4641c0.9996,0.4404,2.0479,0.785,3.1324,1.0384
|
||||
c1.3144,0.3071,2.6773,0.486,4.0839,0.486C340.8428,63.7032,348.9043,55.6416,348.9043,45.7325z M304.2461,129.5279
|
||||
c-13.7871,0-25.0039-11.2168-25.0039-25.0039s11.2168-25.0039,25.0039-25.0039S329.25,90.7369,329.25,104.524
|
||||
S318.0332,129.5279,304.2461,129.5279z M330.9336,34.8872c0.645,0,1.2737,0.0671,1.8881,0.1755
|
||||
c5.0818,0.8974,8.9576,5.3347,8.9576,10.6697c0,5.9805-4.8652,10.8457-10.8457,10.8457s-10.8457-4.8652-10.8457-10.8457
|
||||
c0-1.3967,0.2746-2.7282,0.7576-3.9555C322.4306,37.7496,326.35,34.8872,330.9336,34.8872z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 6.1 KiB |
62
docs/logos/Leptos_logo_Solid_White.svg
Executable file
@@ -0,0 +1,62 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 27.1.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 437.4294 209.6185" style="enable-background:new 0 0 437.4294 209.6185;" xml:space="preserve">
|
||||
<path style="fill:#FFFFFF;" d="M95.1109,128.1089H58.6797V65.6861c0-1.5234-0.8169-2.4331-2.1855-2.4331h-3.1187
|
||||
c-1.3159,0-2.2349,1.0005-2.2349,2.4331v67.4297c0,1.4521,0.8145,2.2852,2.2349,2.2852h41.7353c1.4844,0,2.4819-0.9375,2.4819-2.333
|
||||
v-2.7744C97.5928,128.9253,96.6651,128.1089,95.1109,128.1089z"/>
|
||||
<path style="fill:#FFFFFF;" d="M146.4561,77.1739c-4.8252-3.001-10.3037-4.5249-16.2837-4.5288c-0.0068,0-0.0137,0-0.0205,0
|
||||
c-5.7349,0-11.1377,1.4639-16.0566,4.3511c-4.916,2.8853-8.8721,6.8364-11.7593,11.7456
|
||||
c-2.8975,4.9248-4.3687,10.332-4.3721,16.0713c-0.0034,5.7188,1.4966,11.0654,4.4565,15.8887
|
||||
c2.9893,4.9209,6.8789,8.7334,11.8887,11.6514c4.8657,2.8633,10.2397,4.3174,15.9717,4.3203c0.0073,0,0.0146,0,0.022,0
|
||||
c8.123,0,14.7441-2.5869,21.4683-8.3906c0.5493-0.4805,0.8516-1.1201,0.8516-1.8008c0.001-0.6074-0.1743-1.1035-0.5205-1.4756
|
||||
l-1.3569-1.8428l-0.0732-0.0859c-0.2637-0.2637-0.6929-0.6152-1.3716-0.6152c-0.6421,0-1.2549,0.2217-1.7124,0.6143
|
||||
c-1.9346,1.585-3.5459,2.8008-4.7969,3.6182c-1.7979,1.208-5.8218,3.2314-12.5986,3.2314c-0.0073,0-0.0142,0-0.021,0
|
||||
c-0.1357,0.0029-0.269,0.0039-0.4043,0.0039c-12.2642,0-23.4736-10.3262-24.5088-22.4814l53.0127,0.0322c0.0015,0,0.0024,0,0.0034,0
|
||||
c2.2373,0,3.4697-1.1621,3.4712-3.2715c0.0034-5.2588-1.3574-10.3945-4.0464-15.2705
|
||||
C155.0015,84.0953,151.2188,80.1363,146.4561,77.1739z M154.6451,100.4341l-49.1157-0.0293
|
||||
c1.9834-11.6631,13.0181-21.2417,24.5034-21.0117c0.1387-0.0024,0.2754-0.0039,0.4136-0.0039
|
||||
C143.4629,79.3892,152.4722,90.0162,154.6451,100.4341z"/>
|
||||
<path style="fill:#FFFFFF;" d="M204.0386,136.6382c5.7319,0,11.1069-1.4502,15.9746-4.3115
|
||||
c4.938-2.9014,8.75-6.7129,11.6533-11.6533c2.8608-4.8672,4.311-10.2578,4.311-16.0244c0-5.7324-1.4502-11.1064-4.311-15.9746
|
||||
c-2.9019-4.9385-6.7134-8.75-11.6533-11.6533c-4.8687-2.8618-10.2437-4.3125-15.9746-4.3125
|
||||
c-9.938,0-19.2021,4.7583-24.3516,12.3174v-9.438c0-0.5946-0.1465-1.0788-0.411-1.4511c-0.3815-0.5369-1.0157-0.834-1.8727-0.834
|
||||
h-2.6738c-1.4521,0-2.2852,0.833-2.2852,2.2852v5.6964v46.4791v23.9676c0,1.2568,0.7808,2.0371,2.0371,2.0371h3.3667
|
||||
c0.9209,0,1.6421-0.6992,1.6421-1.5908v-17.098v-10.984C185.0884,131.8892,194.2749,136.6382,204.0386,136.6382z M186.6358,122.5591
|
||||
c-4.9346-4.9346-7.6831-11.4932-7.542-18.0254c-0.1367-6.3506,2.5439-12.751,7.3545-17.5605
|
||||
c4.8521-4.8521,11.3037-7.5547,17.7383-7.417c4.3691,0,8.4863,1.1465,12.2314,3.4043c3.7344,2.2979,6.7456,5.4053,8.9492,9.2354
|
||||
c2.1699,3.9072,3.2695,8.0967,3.2695,12.4697c0.1396,6.4619-2.5967,12.9844-7.5083,17.8955
|
||||
c-4.7617,4.7617-11.0469,7.3857-17.2544,7.2803C197.6856,129.9712,191.396,127.3208,186.6358,122.5591z"/>
|
||||
<path style="fill:#FFFFFF;" d="M241.8955,80.3975h7.5669v42.0259c0,6.8174,4.5674,12.1309,11.0825,12.9189
|
||||
c0.6836,0.1055,1.8379,0.1572,3.5303,0.1572c2.0078,0,3.0273-0.3535,3.0273-2.2842v-2.377c0-1.7891-1.334-2.0371-2.7568-2.0371
|
||||
c0,0-0.001,0-0.002,0l-1.7871-0.0488c-2.0117-0.0439-3.4883-0.7627-4.3896-2.1367c-0.9697-1.4805-1.4619-3.1738-1.4619-5.0352
|
||||
V80.3975h10.0928c1.3076,0,2.2852-1.3628,2.2852-2.5815v-1.9312c0-1.3999-0.8359-2.2354-2.2354-2.2354h-10.1426V60.6861
|
||||
c0-1.4619-0.7969-2.4829-1.9375-2.4829c-0.1865,0-0.4121,0-0.6392,0.0884l-2.6489,0.6865
|
||||
c-1.2109,0.3682-2.0171,0.9263-2.0171,2.4507v12.2207h-7.5669c-1.4185,0-2.335,0.897-2.335,2.2852v1.8813
|
||||
C239.5606,79.2393,240.6079,80.3975,241.8955,80.3975z"/>
|
||||
<path style="fill:#FFFFFF;" d="M379.1182,106.2691c-4.0488-2.9219-8.8545-5.0293-14.291-6.2646
|
||||
c-6.5049-1.3975-13.4473-5.2129-13.3203-10.3066c0-7.5225,6.6367-10.1914,12.3203-10.1914c5.3574,0,10.2207,3.002,13.001,8.0146
|
||||
c0.6729,1.2861,1.4785,1.9375,2.3955,1.9375c0.3311,0,0.7061-0.1113,0.9922-0.2832l2.2021-1.1523
|
||||
c0.5947-0.3408,0.9229-0.9414,0.9229-1.6924c0-0.5205-0.0908-0.9541-0.2617-1.292c-3.6367-8.2466-10.0967-12.4282-19.2021-12.4282
|
||||
c-11.7305,0-19.6123,6.9263-19.6123,17.2349c0,4.3125,1.8438,7.9746,5.4756,10.8809c3.4482,2.7979,7.9121,4.8623,13.2705,6.1377
|
||||
c4.5859,1.085,8.3193,2.5654,11.0977,4.4023c1.4159,0.9354,2.4412,2.0535,3.106,3.3672c0.6053,1.1962,0.9135,2.5535,0.9135,4.1005
|
||||
c0.0742,2.3857-0.79,4.5176-2.5684,6.3389c-3.1445,3.2178-8.4053,4.6689-12.0205,4.6689c-0.0361,0-0.0723,0-0.1074,0
|
||||
c-3.4268,0-6.4893-0.8438-9.1035-2.5068c-2.5918-1.6484-4.2363-3.8076-5.0293-6.6064c-0.3203-1.0996-0.751-2.1738-2.1553-2.1738
|
||||
c-0.0742,0-0.2109,0.0146-0.4062,0.0449c-0.1133,0.0166-0.2559,0.0381-0.5088,0.0742l-1.8818,0.4463l-0.1045,0.0332
|
||||
c-1.0244,0.4082-1.6113,1.1846-1.6113,2.1309c0,0.2285,0.0625,0.6592,0.2178,1.1094c1.9707,8.5801,10.2432,14.3447,20.5732,14.3447
|
||||
c0.125,0.002,0.249,0.002,0.374,0.002c6.5947,0,12.6748-2.3193,16.7275-6.3945c3.1895-3.208,4.8311-7.2363,4.748-11.6357
|
||||
c0-2.8187-0.6185-5.3109-1.8062-7.481C382.4437,109.2624,381.0062,107.631,379.1182,106.2691z"/>
|
||||
<path style="fill:#FFFFFF;" d="M348.9043,45.7325c0-6.3157-3.2826-11.8699-8.2238-15.0756
|
||||
c-2.811-1.8237-6.1537-2.8947-9.7469-2.8947c-9.9092,0-17.9707,8.0615-17.9707,17.9702c0,4.7659,1.8775,9.0925,4.9157,12.3123
|
||||
c-3.6619,4.3709-6.6334,9.3336-8.7663,14.7186c-1.5873-0.2422-3.2123-0.3683-4.8662-0.3683
|
||||
c-17.7158,0-32.1289,14.4131-32.1289,32.1289c0,14.6854,9.9077,27.0922,23.3869,30.9101
|
||||
c-6.7762,17.3461-23.6572,29.6719-43.3742,29.6719c-16.8195,0-31.583-8.9662-39.7656-22.369
|
||||
c-2.4778,0.5446-5.0429,0.8519-7.6721,0.9023c9.0226,16.99,26.8969,28.5917,47.4377,28.5917
|
||||
c23.2646,0,43.1121-14.8788,50.5461-35.6179c0.5204,0.0251,1.0435,0.0398,1.5701,0.0398c17.7158,0,32.1289-14.4131,32.1289-32.1289
|
||||
c0-13.557-8.4446-25.1712-20.3465-29.8811c1.9001-4.5678,4.5115-8.7646,7.6888-12.4641c0.9996,0.4404,2.0479,0.785,3.1324,1.0384
|
||||
c1.3144,0.3071,2.6773,0.486,4.0839,0.486C340.8428,63.7032,348.9043,55.6416,348.9043,45.7325z M304.2461,129.5279
|
||||
c-13.7871,0-25.0039-11.2168-25.0039-25.0039s11.2168-25.0039,25.0039-25.0039S329.25,90.7369,329.25,104.524
|
||||
S318.0332,129.5279,304.2461,129.5279z M330.9336,34.8872c0.645,0,1.2737,0.0671,1.8881,0.1755
|
||||
c5.0818,0.8974,8.9576,5.3347,8.9576,10.6697c0,5.9805-4.8652,10.8457-10.8457,10.8457s-10.8457-4.8652-10.8457-10.8457
|
||||
c0-1.3967,0.2746-2.7282,0.7576-3.9555C322.4306,37.7496,326.35,34.8872,330.9336,34.8872z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 6.3 KiB |
BIN
docs/logos/Leptos_logo_abbreviation__circle_RGB.png
Executable file
|
After Width: | Height: | Size: 38 KiB |
37
docs/logos/Leptos_logo_abbreviation__circle_RGB.svg
Executable file
@@ -0,0 +1,37 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 27.1.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 115.9988 115.9988" style="enable-background:new 0 0 115.9988 115.9988;" xml:space="preserve">
|
||||
<g>
|
||||
<g>
|
||||
<g>
|
||||
<path style="fill:#180D38;" d="M29.1281,108.2941c9.5736-4.5548,17.1531-12.6456,21.0335-22.5787
|
||||
c-12.0865-3.4232-20.9707-14.548-20.9707-27.7159c0-15.8849,12.9236-28.8085,28.8085-28.8085
|
||||
c1.4832,0,2.9404,0.113,4.3639,0.3303c1.9125-4.8287,4.5771-9.2786,7.8607-13.1979c-2.7243-2.8871-4.4077-6.7665-4.4077-11.0399
|
||||
c0-1.6191,0.2457-3.1808,0.6921-4.6562C63.7305,0.2186,60.8908,0,57.9995,0C25.9672,0,0,25.9672,0,57.9994
|
||||
C0,79.5165,11.7263,98.2828,29.1281,108.2941z"/>
|
||||
<path style="fill:#EF3939;" d="M81.9297,15.0082c3.6788,0,6.886-2.0536,8.5379-5.0742
|
||||
c-5.3185-3.5997-11.2684-6.3339-17.646-8.0151c-0.3903,1.0504-0.6168,2.1798-0.6168,3.3644
|
||||
C72.2049,10.6458,76.5673,15.0082,81.9297,15.0082z"/>
|
||||
<path style="fill:#180D38;" d="M95.5663,13.828c-2.8537,4.5375-7.8918,7.5688-13.6366,7.5688
|
||||
c-1.2614,0-2.4835-0.1604-3.6622-0.4359c-0.9722-0.2272-1.9121-0.5362-2.8083-0.931c-2.8492,3.3173-5.1907,7.0806-6.8945,11.1766
|
||||
c10.6715,4.2233,18.2432,14.6371,18.2432,26.7928c0,15.8849-12.9235,28.8085-28.8085,28.8085
|
||||
c-0.4718,0-0.9406-0.0131-1.4069-0.0357c-3.7532,10.4704-11.0354,19.2744-20.406,24.9696
|
||||
c6.7355,2.7367,14.0948,4.257,21.8129,4.257c32.0322,0,57.9994-25.9672,57.9994-57.9995
|
||||
C115.9988,40.3018,108.0628,24.4664,95.5663,13.828z"/>
|
||||
<circle style="fill:#EF3939;" cx="57.9994" cy="57.9994" r="22.4198"/>
|
||||
</g>
|
||||
<path style="fill:#FFFFFF;" d="M78.2676,20.961c1.1786,0.2755,2.4008,0.4359,3.6622,0.4359
|
||||
c5.7448,0,10.7829-3.0313,13.6366-7.5688c-1.6275-1.3855-3.3236-2.6925-5.0987-3.894c-1.6519,3.0206-4.8591,5.0742-8.5379,5.0742
|
||||
c-5.3624,0-9.7249-4.3624-9.7249-9.7249c0-1.1846,0.2264-2.3141,0.6168-3.3644c-2.062-0.5436-4.1682-0.9763-6.3133-1.2917
|
||||
c-0.4464,1.4753-0.6921,3.0371-0.6921,4.6562c0,4.2734,1.6834,8.1528,4.4077,11.0399c-3.2836,3.9193-5.9482,8.3692-7.8607,13.1979
|
||||
c-1.4235-0.2172-2.8807-0.3303-4.3639-0.3303c-15.8849,0-28.8085,12.9235-28.8085,28.8085
|
||||
c0,13.168,8.8842,24.2928,20.9707,27.7159c-3.8804,9.9332-11.4599,18.0239-21.0335,22.5787
|
||||
c2.2621,1.3013,4.6175,2.456,7.0584,3.4478c9.3706-5.6952,16.6528-14.4992,20.406-24.9696
|
||||
c0.4663,0.0226,0.9351,0.0357,1.4069,0.0357c15.8849,0,28.8085-12.9236,28.8085-28.8085c0-12.1557-7.5717-22.5695-18.2432-26.7928
|
||||
c1.7038-4.0959,4.0453-7.8593,6.8945-11.1766C76.3555,20.4248,77.2953,20.7338,78.2676,20.961z M80.4193,57.9994
|
||||
c0,12.3623-10.0576,22.4199-22.4198,22.4199c-12.3623,0-22.4199-10.0576-22.4199-22.4199
|
||||
c0-12.3622,10.0576-22.4199,22.4199-22.4199C70.3617,35.5795,80.4193,45.6371,80.4193,57.9994z"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.9 KiB |
BIN
docs/logos/Leptos_logo_abbreviation__square_RGB.png
Executable file
|
After Width: | Height: | Size: 27 KiB |
27
docs/logos/Leptos_logo_abbreviation__square_RGB.svg
Executable file
@@ -0,0 +1,27 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 27.1.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 115.5026 115.5026" style="enable-background:new 0 0 115.5026 115.5026;" xml:space="preserve">
|
||||
<path style="fill:#181139;" d="M115.5026,0h-13.957c0.0002,0.0315,0.0031,0.0623,0.0031,0.0938
|
||||
c0,9.718-7.9059,17.6239-17.6239,17.6239c-1.3796,0-2.7163-0.1754-4.0055-0.4767c-1.0634-0.2485-2.0913-0.5864-3.0715-1.0182
|
||||
c-3.1162,3.6283-5.6772,7.7443-7.5408,12.2242c11.6719,4.6192,19.9532,16.0091,19.9532,29.3043
|
||||
c0,17.374-14.1349,31.5089-31.5089,31.5089c-0.5161,0-1.0288-0.0143-1.5388-0.039c-3.8856,10.8397-11.2302,20.0454-20.6959,26.2814
|
||||
h79.986V0z"/>
|
||||
<circle style="fill:#EF3939;" cx="57.7513" cy="57.7513" r="24.5214"/>
|
||||
<path style="fill:#181139;" d="M49.1788,88.0652c-13.2195-3.744-22.9364-15.9116-22.9364-30.3139
|
||||
c0-17.374,14.1349-31.5089,31.5089-31.5089c1.6223,0,3.2161,0.1237,4.7729,0.3612c2.0918-5.2813,5.0061-10.1484,8.5975-14.4351
|
||||
c-2.9796-3.1577-4.8209-7.4008-4.8209-12.0747c0-0.0317,0.0046-0.0622,0.0048-0.0938H0v115.5026h18.8623
|
||||
C32.7495,111.6378,43.9877,101.3537,49.1788,88.0652z"/>
|
||||
<path style="fill:#EF3939;" d="M83.9248,10.7302c5.8651,0,10.6364-4.7714,10.6364-10.6364c0-0.0316-0.004-0.0623-0.0043-0.0938
|
||||
H73.293c-0.0003,0.0316-0.0046,0.0621-0.0046,0.0938C73.2884,5.9589,78.0598,10.7302,83.9248,10.7302z"/>
|
||||
<path style="fill:#FFFFFF;" d="M56.2125,89.2212c0.51,0.0247,1.0228,0.039,1.5388,0.039c17.374,0,31.5089-14.1349,31.5089-31.5089
|
||||
c0-13.2952-8.2814-24.6851-19.9532-29.3043c1.8635-4.4799,4.4246-8.5959,7.5408-12.2242c0.9802,0.4318,2.0082,0.7698,3.0715,1.0182
|
||||
c1.2892,0.3013,2.6259,0.4767,4.0055,0.4767c9.718,0,17.6239-7.9059,17.6239-17.6239c0-0.0315-0.0029-0.0623-0.0031-0.0938h-6.9887
|
||||
c0.0003,0.0316,0.0043,0.0622,0.0043,0.0938c0,5.8651-4.7714,10.6364-10.6364,10.6364S73.2884,5.9589,73.2884,0.0938
|
||||
c0-0.0317,0.0043-0.0622,0.0046-0.0938h-6.9874c-0.0002,0.0316-0.0048,0.0621-0.0048,0.0938c0,4.674,1.8413,8.9171,4.8209,12.0747
|
||||
c-3.5914,4.2867-6.5057,9.1537-8.5975,14.4351c-1.5569-0.2375-3.1507-0.3612-4.7729-0.3612
|
||||
c-17.374,0-31.5089,14.1349-31.5089,31.5089c0,14.4023,9.7169,26.5699,22.9364,30.3139
|
||||
c-5.1912,13.2885-16.4293,23.5726-30.3165,27.4374h16.6543C44.9824,109.2666,52.327,100.0609,56.2125,89.2212z M33.2299,57.7513
|
||||
c0-13.5211,11.0004-24.5214,24.5214-24.5214s24.5214,11.0004,24.5214,24.5214S71.2724,82.2727,57.7513,82.2727
|
||||
S33.2299,71.2723,33.2299,57.7513z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.5 KiB |
13
docs/logos/Leptos_logo_pref_dark_RGB.svg
Normal file
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<svg version="1.1" id="Layer_1" x="0px" y="0px" viewBox="0 0 437.4 209.6" style="enable-background:new 0 0 437.4 209.6;" xmlns="http://www.w3.org/2000/svg">
|
||||
<style type="text/css">
|
||||
.st0{fill:#FFFFFF;}
|
||||
.st1{fill:#EF3939;}
|
||||
</style>
|
||||
<path class="st0" d="M95.1,128.1H58.7V65.7c0-1.5-0.8-2.4-2.2-2.4h-3.1c-1.3,0-2.2,1-2.2,2.4v67.4c0,1.5,0.8,2.3,2.2,2.3h41.7 c1.5,0,2.5-0.9,2.5-2.3v-2.8C97.6,128.9,96.7,128.1,95.1,128.1z"/>
|
||||
<path class="st0" d="M146.5,77.2c-4.8-3-10.3-4.5-16.3-4.5c0,0,0,0,0,0c-5.7,0-11.1,1.5-16.1,4.4c-4.9,2.9-8.9,6.8-11.8,11.7 c-2.9,4.9-4.4,10.3-4.4,16.1c0,5.7,1.5,11.1,4.5,15.9c3,4.9,6.9,8.7,11.9,11.7c4.9,2.9,10.2,4.3,16,4.3c0,0,0,0,0,0 c8.1,0,14.7-2.6,21.5-8.4c0.5-0.5,0.9-1.1,0.9-1.8c0-0.6-0.2-1.1-0.5-1.5l-1.4-1.8l-0.1-0.1c-0.3-0.3-0.7-0.6-1.4-0.6 c-0.6,0-1.3,0.2-1.7,0.6c-1.9,1.6-3.5,2.8-4.8,3.6c-1.8,1.2-5.8,3.2-12.6,3.2c0,0,0,0,0,0c-0.1,0-0.3,0-0.4,0 c-12.3,0-23.5-10.3-24.5-22.5l53,0c0,0,0,0,0,0c2.2,0,3.5-1.2,3.5-3.3c0-5.3-1.4-10.4-4-15.3C155,84.1,151.2,80.1,146.5,77.2z M154.6,100.4l-49.1,0c2-11.7,13-21.2,24.5-21c0.1,0,0.3,0,0.4,0C143.5,79.4,152.5,90,154.6,100.4z"/>
|
||||
<path class="st0" d="M204,136.6c5.7,0,11.1-1.5,16-4.3c4.9-2.9,8.8-6.7,11.7-11.7c2.9-4.9,4.3-10.3,4.3-16c0-5.7-1.5-11.1-4.3-16 c-2.9-4.9-6.7-8.8-11.7-11.7c-4.9-2.9-10.2-4.3-16-4.3c-9.9,0-19.2,4.8-24.4,12.3v-9.4c0-0.6-0.1-1.1-0.4-1.5 c-0.4-0.5-1-0.8-1.9-0.8h-2.7c-1.5,0-2.3,0.8-2.3,2.3v5.7v46.5v24c0,1.3,0.8,2,2,2h3.4c0.9,0,1.6-0.7,1.6-1.6v-17.1v-11 C185.1,131.9,194.3,136.6,204,136.6z M186.6,122.6c-4.9-4.9-7.7-11.5-7.5-18c-0.1-6.4,2.5-12.8,7.4-17.6c4.9-4.9,11.3-7.6,17.7-7.4 c4.4,0,8.5,1.1,12.2,3.4c3.7,2.3,6.7,5.4,8.9,9.2c2.2,3.9,3.3,8.1,3.3,12.5c0.1,6.5-2.6,13-7.5,17.9c-4.8,4.8-11,7.4-17.3,7.3 C197.7,130,191.4,127.3,186.6,122.6z"/>
|
||||
<path class="st0" d="M241.9,80.4h7.6v42c0,6.8,4.6,12.1,11.1,12.9c0.7,0.1,1.8,0.2,3.5,0.2c2,0,3-0.4,3-2.3v-2.4c0-1.8-1.3-2-2.8-2 c0,0,0,0,0,0l-1.8,0c-2,0-3.5-0.8-4.4-2.1c-1-1.5-1.5-3.2-1.5-5V80.4h10.1c1.3,0,2.3-1.4,2.3-2.6v-1.9c0-1.4-0.8-2.2-2.2-2.2h-10.1 v-13c0-1.5-0.8-2.5-1.9-2.5c-0.2,0-0.4,0-0.6,0.1l-2.6,0.7c-1.2,0.4-2,0.9-2,2.5v12.2h-7.6c-1.4,0-2.3,0.9-2.3,2.3v1.9 C239.6,79.2,240.6,80.4,241.9,80.4z"/>
|
||||
<path class="st0" d="M379.1,106.3c-4-2.9-8.9-5-14.3-6.3c-6.5-1.4-13.4-5.2-13.3-10.3c0-7.5,6.6-10.2,12.3-10.2c5.4,0,10.2,3,13,8 c0.7,1.3,1.5,1.9,2.4,1.9c0.3,0,0.7-0.1,1-0.3l2.2-1.2c0.6-0.3,0.9-0.9,0.9-1.7c0-0.5-0.1-1-0.3-1.3c-3.6-8.2-10.1-12.4-19.2-12.4 c-11.7,0-19.6,6.9-19.6,17.2c0,4.3,1.8,8,5.5,10.9c3.4,2.8,7.9,4.9,13.3,6.1c4.6,1.1,8.3,2.6,11.1,4.4c1.4,0.9,2.4,2.1,3.1,3.4 c0.6,1.2,0.9,2.6,0.9,4.1c0.1,2.4-0.8,4.5-2.6,6.3c-3.1,3.2-8.4,4.7-12,4.7c0,0-0.1,0-0.1,0c-3.4,0-6.5-0.8-9.1-2.5 c-2.6-1.6-4.2-3.8-5-6.6c-0.3-1.1-0.8-2.2-2.2-2.2c-0.1,0-0.2,0-0.4,0c-0.1,0-0.3,0-0.5,0.1l-1.9,0.4l-0.1,0c-1,0.4-1.6,1.2-1.6,2.1 c0,0.2,0.1,0.7,0.2,1.1c2,8.6,10.2,14.3,20.6,14.3c0.1,0,0.2,0,0.4,0c6.6,0,12.7-2.3,16.7-6.4c3.2-3.2,4.8-7.2,4.7-11.6 c0-2.8-0.6-5.3-1.8-7.5C382.4,109.3,381,107.6,379.1,106.3z"/>
|
||||
<path class="st1" d="M348.9,45.7c0-6.3-3.3-11.9-8.2-15.1c-2.8-1.8-6.2-2.9-9.7-2.9c-9.9,0-18,8.1-18,18c0,4.8,1.9,9.1,4.9,12.3 c-3.7,4.4-6.6,9.3-8.8,14.7c-1.6-0.2-3.2-0.4-4.9-0.4c-17.7,0-32.1,14.4-32.1,32.1c0,14.7,9.9,27.1,23.4,30.9 c-6.8,17.3-23.7,29.7-43.4,29.7c-16.8,0-31.6-9-39.8-22.4c-2.5,0.5-5,0.9-7.7,0.9c9,17,26.9,28.6,47.4,28.6 c23.3,0,43.1-14.9,50.5-35.6c0.5,0,1,0,1.6,0c17.7,0,32.1-14.4,32.1-32.1c0-13.6-8.4-25.2-20.3-29.9c1.9-4.6,4.5-8.8,7.7-12.5 c1,0.4,2,0.8,3.1,1c1.3,0.3,2.7,0.5,4.1,0.5C340.8,63.7,348.9,55.6,348.9,45.7z M304.2,129.5c-13.8,0-25-11.2-25-25s11.2-25,25-25 s25,11.2,25,25S318,129.5,304.2,129.5z M330.9,34.9c0.6,0,1.3,0.1,1.9,0.2c5.1,0.9,9,5.3,9,10.7c0,6-4.9,10.8-10.8,10.8 s-10.8-4.9-10.8-10.8c0-1.4,0.3-2.7,0.8-4C322.4,37.7,326.4,34.9,330.9,34.9z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.7 KiB |
|
Before Width: | Height: | Size: 7.3 KiB |
4
examples/counter/Makefile.toml
Normal file
@@ -0,0 +1,4 @@
|
||||
[tasks.build]
|
||||
command = "cargo"
|
||||
args = ["+nightly", "build-all-features"]
|
||||
install_crate = "cargo-all-features"
|
||||
@@ -3,3 +3,5 @@
|
||||
This example creates a simple counter in a client side rendered app with Rust and WASM!
|
||||
|
||||
To run it, just issue the `trunk serve --open` command in the example root. This will build the app, run it, and open a new browser to serve it.
|
||||
|
||||
> If you don't have `trunk` installed, [click here for install instructions.](https://trunkrs.dev/)
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
<html>
|
||||
<head>
|
||||
<link data-trunk rel="rust" data-wasm-opt="z"/>
|
||||
<link data-trunk rel="icon" type="image/ico" href="/public/favicon.ico"/>
|
||||
</head>
|
||||
<body></body>
|
||||
</html>
|
||||
BIN
examples/counter/public/favicon.ico
Normal file
|
After Width: | Height: | Size: 15 KiB |
@@ -17,7 +17,7 @@ pub fn SimpleCounter(
|
||||
<div>
|
||||
<button on:click=move |_| set_value(0)>"Clear"</button>
|
||||
<button on:click=move |_| set_value.update(|value| *value -= step)>"-1"</button>
|
||||
<span>"Value: " {move || value().to_string()} "!"</span>
|
||||
<span>"Value: " {value} "!"</span>
|
||||
<button on:click=move |_| set_value.update(|value| *value += step)>"+1"</button>
|
||||
</div>
|
||||
}
|
||||
|
||||
@@ -23,12 +23,11 @@ leptos_actix = { path = "../../integrations/actix", optional = true }
|
||||
leptos_meta = { path = "../../meta", default-features = false }
|
||||
leptos_router = { path = "../../router", default-features = false }
|
||||
log = "0.4"
|
||||
simple_logger = "2"
|
||||
simple_logger = "4.0.0"
|
||||
gloo-net = { git = "https://github.com/rustwasm/gloo" }
|
||||
|
||||
[features]
|
||||
default = []
|
||||
csr = ["leptos/csr", "leptos_meta/csr", "leptos_router/csr"]
|
||||
hydrate = ["leptos/hydrate", "leptos_meta/hydrate", "leptos_router/hydrate"]
|
||||
ssr = [
|
||||
"dep:actix-files",
|
||||
@@ -41,31 +40,32 @@ ssr = [
|
||||
stable = ["leptos/stable", "leptos_router/stable"]
|
||||
|
||||
[package.metadata.cargo-all-features]
|
||||
denylist = ["actix-files", "actix-web", "leptos_actix"]
|
||||
skip_feature_sets = [["csr", "ssr"], ["csr", "hydrate"], ["ssr", "hydrate"]]
|
||||
denylist = ["actix-files", "actix-web", "leptos_actix", "stable"]
|
||||
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 = "counter_isomorphic"
|
||||
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
|
||||
site-pkg-dir = "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"
|
||||
# [Optional] Files in the asset-dir will be copied to the site-root directory
|
||||
# assets-dir = "static/assets"
|
||||
assets-dir = "public"
|
||||
# The IP and port (ex: 127.0.0.1:3000) where the server serves the content. Use it in your server setup.
|
||||
site-address = "127.0.0.1:3000"
|
||||
site-addr = "127.0.0.1:3000"
|
||||
# The port to use for automatic reload monitoring
|
||||
reload-port = 3001
|
||||
reload-port = 3001
|
||||
# [Optional] Command to use when running end2end tests. It will run in the end2end dir.
|
||||
end2end-cmd = "npx playwright test"
|
||||
# The browserlist query used for optimizing the CSS.
|
||||
browserquery = "defaults"
|
||||
browserquery = "defaults"
|
||||
# Set by cargo-leptos watch when building with tha tool. Controls whether autoreload JS will be included in the head
|
||||
watch = false
|
||||
watch = false
|
||||
# The environment Leptos will run in, usually either "DEV" or "PROD"
|
||||
env = "DEV"
|
||||
# The features to use when compiling the bin target
|
||||
@@ -86,4 +86,4 @@ 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-default-features = false
|
||||
|
||||
4
examples/counter_isomorphic/Makefile.toml
Normal file
@@ -0,0 +1,4 @@
|
||||
[tasks.build]
|
||||
command = "cargo"
|
||||
args = ["+nightly", "build-all-features"]
|
||||
install_crate = "cargo-all-features"
|
||||
@@ -3,8 +3,8 @@
|
||||
This example demonstrates how to use a function isomorphically, to run a server side function from the browser and receive a result.
|
||||
|
||||
## Client Side Rendering
|
||||
To run it as a Client Side App, you can issue `trunk serve --open` in the root. This will build the entire
|
||||
app into one CSR bundle. Make sure you have trunk installed with `cargo install trunk`.
|
||||
For this example the server must store the counter state since it can be modified by many users.
|
||||
This means it is not possible to produce a working CSR-only version as a non-static server is required.
|
||||
|
||||
## Server Side Rendering with cargo-leptos
|
||||
cargo-leptos is now the easiest and most featureful way to build server side rendered apps with hydration. It provides automatic recompilation of client and server code, wasm optimisation, CSS minification, and more! Check out more about it [here](https://github.com/akesson/cargo-leptos)
|
||||
@@ -17,6 +17,9 @@ cargo install --locked cargo-leptos
|
||||
```bash
|
||||
cargo leptos watch
|
||||
```
|
||||
|
||||
Open browser on [http://localhost:3000/](http://localhost:3000/)
|
||||
|
||||
3. When ready to deploy, run
|
||||
```bash
|
||||
cargo leptos build --release
|
||||
@@ -25,7 +28,7 @@ cargo leptos build --release
|
||||
## Server Side Rendering without cargo-leptos
|
||||
To run it as a server side app with hydration, you'll need to have wasm-pack installed.
|
||||
|
||||
0. Edit the `[package.metadata.leptos]` section and set `site-root` to `"pkg"`. You'll also want to change the path of the `<StyleSheet / >` component in the root component to point towards the CSS file in the root. This tells leptos that the WASM/JS files generated by wasm-pack are available at `./pkg` and that the CSS files are no longer processed by cargo-leptos. Building to alternative folders is not supported at this time.
|
||||
0. Edit the `[package.metadata.leptos]` section and set `site-root` to `"."`. For examples with CSS you also want to change the path of the `<StyleSheet / >` component in the root component to point towards the CSS file in the root. This tells leptos that the WASM/JS files generated by wasm-pack are available at `./pkg` and that the CSS files are no longer processed by cargo-leptos. Building to alternative folders is not supported at this time. You'll also want to edit the call to `get_configuration()` to pass in `Some(Cargo.toml)`, so that Leptos will read the settings instead of cargo-leptos. If you do so, your file/folder names cannot include dashes.
|
||||
1. Install wasm-pack
|
||||
```bash
|
||||
cargo install wasm-pack
|
||||
|
||||
BIN
examples/counter_isomorphic/public/favicon.ico
Normal file
|
After Width: | Height: | Size: 15 KiB |
@@ -1,5 +1,6 @@
|
||||
use leptos::*;
|
||||
use leptos_router::*;
|
||||
use leptos_meta::*;
|
||||
|
||||
#[cfg(feature = "ssr")]
|
||||
use std::sync::atomic::{AtomicI32, Ordering};
|
||||
@@ -44,6 +45,7 @@ pub async fn clear_server_count() -> Result<i32, ServerFnError> {
|
||||
}
|
||||
#[component]
|
||||
pub fn Counters(cx: Scope) -> impl IntoView {
|
||||
provide_meta_context(cx);
|
||||
view! {
|
||||
cx,
|
||||
<Router>
|
||||
@@ -59,6 +61,7 @@ pub fn Counters(cx: Scope) -> impl IntoView {
|
||||
<li><A href="multi">"Multi-User"</A></li>
|
||||
</ul>
|
||||
</nav>
|
||||
<Link rel="shortcut icon" type_="image/ico" href="/favicon.ico"/>
|
||||
<main>
|
||||
<Routes>
|
||||
<Route path="" view=|cx| view! {
|
||||
@@ -113,9 +116,10 @@ pub fn Counter(cx: Scope) -> impl IntoView {
|
||||
<div>
|
||||
<button on:click=move |_| clear.dispatch(())>"Clear"</button>
|
||||
<button on:click=move |_| dec.dispatch(())>"-1"</button>
|
||||
<span>"Value: " {move || value().to_string()} "!"</span>
|
||||
<span>"Value: " {value} "!"</span>
|
||||
<button on:click=move |_| inc.dispatch(())>"+1"</button>
|
||||
</div>
|
||||
{move || error_msg().map(|msg| view! { cx, <p>"Error: " {msg.to_string()}</p>})}
|
||||
</div>
|
||||
}
|
||||
}
|
||||
@@ -208,8 +212,8 @@ pub fn MultiuserCounter(cx: Scope) -> impl IntoView {
|
||||
};
|
||||
|
||||
#[cfg(feature = "ssr")]
|
||||
let multiplayer_value =
|
||||
create_signal_from_stream(cx, futures::stream::once(Box::pin(async { 0.to_string() })));
|
||||
let (multiplayer_value, _) =
|
||||
create_signal(cx, None::<i32>);
|
||||
|
||||
view! {
|
||||
cx,
|
||||
|
||||
@@ -9,6 +9,7 @@ cfg_if! {
|
||||
use actix_files::{Files};
|
||||
use actix_web::*;
|
||||
use crate::counters::*;
|
||||
use leptos_actix::{generate_route_list, LeptosRoutes};
|
||||
|
||||
#[get("/api/events")]
|
||||
async fn counter_events() -> impl Responder {
|
||||
@@ -29,23 +30,26 @@ cfg_if! {
|
||||
|
||||
#[actix_web::main]
|
||||
async fn main() -> std::io::Result<()> {
|
||||
|
||||
crate::counters::register_server_functions();
|
||||
let conf = get_configuration(Some("Cargo.toml")).await.unwrap();
|
||||
let leptos_options = &conf.leptos_options;
|
||||
let site_root = &leptos_options.site_root;
|
||||
let pkg_dir = &leptos_options.site_pkg_dir;
|
||||
let bundle_path = format!("/{site_root}/{pkg_dir}");
|
||||
|
||||
// Setting this to None means we'll be using cargo-leptos and its env vars.
|
||||
// when not using cargo-leptos None must be replaced with Some("Cargo.toml")
|
||||
let conf = get_configuration(None).await.unwrap();
|
||||
|
||||
let addr = conf.leptos_options.site_address.clone();
|
||||
let routes = generate_route_list(|cx| view! { cx, <Counters/> });
|
||||
|
||||
HttpServer::new(move || {
|
||||
let leptos_options = &conf.leptos_options;
|
||||
let site_root = &leptos_options.site_root;
|
||||
|
||||
App::new()
|
||||
.service(Files::new("/pkg", "./pkg")) // used by wasm-pack and cargo run. Can be removed if using cargo-leptos
|
||||
.service(Files::new(&bundle_path, format!("./{bundle_path}"))) // used by cargo-leptos. Can be removed if using wasm-pack and cargo run.
|
||||
.service(counter_events)
|
||||
.route("/api/{tail:.*}", leptos_actix::handle_server_fns())
|
||||
.route("/{tail:.*}", leptos_actix::render_app_to_stream(leptos_options.to_owned(), |cx| view! { cx, <Counters/> }))
|
||||
//.wrap(middleware::Compress::default())
|
||||
.leptos_routes(leptos_options.to_owned(), routes.to_owned(), |cx| view! { cx, <Counters/> })
|
||||
.service(Files::new("/", &site_root))
|
||||
//.wrap(middleware::Compress::default())
|
||||
})
|
||||
.bind(&addr)?
|
||||
.run()
|
||||
@@ -53,14 +57,11 @@ cfg_if! {
|
||||
}
|
||||
}
|
||||
|
||||
// client-only stuff for Trunk
|
||||
// client-only main for Trunk
|
||||
else {
|
||||
use leptos_counter_isomorphic::counters::*;
|
||||
|
||||
pub fn main() {
|
||||
_ = console_log::init_with_level(log::Level::Debug);
|
||||
console_error_panic_hook::set_once();
|
||||
mount_to_body(|cx| view! { cx, <Counter/> });
|
||||
// isomorphic counters cannot work in a Client-Side-Rendered only
|
||||
// app as a server is required to maintain state
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
13
examples/counter_without_macros/Cargo.toml
Normal file
@@ -0,0 +1,13 @@
|
||||
[package]
|
||||
name = "counter_without_macros"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
leptos = { path = "../../leptos", features = ["stable"] }
|
||||
console_log = "0.2"
|
||||
log = "0.4"
|
||||
console_error_panic_hook = "0.1.7"
|
||||
|
||||
[dev-dependencies]
|
||||
wasm-bindgen-test = "0.3.0"
|
||||
5
examples/counter_without_macros/README.md
Normal file
@@ -0,0 +1,5 @@
|
||||
# Leptos Counter Example
|
||||
|
||||
This example is the same like the `counter` but it's written without using macros and can be build with stable Rust.
|
||||
|
||||
To run it, just issue the `trunk serve --open` command in the example root. This will build the app, run it, and open a new browser to serve it.
|
||||
@@ -2,6 +2,7 @@
|
||||
<html>
|
||||
<head>
|
||||
<link data-trunk rel="rust" data-wasm-opt="z"/>
|
||||
<link data-trunk rel="icon" type="image/ico" href="/public/favicon.ico"/>
|
||||
</head>
|
||||
<body></body>
|
||||
</html>
|
||||
BIN
examples/counter_without_macros/public/favicon.ico
Normal file
|
After Width: | Height: | Size: 15 KiB |
44
examples/counter_without_macros/src/lib.rs
Normal file
@@ -0,0 +1,44 @@
|
||||
use leptos::{ev, *};
|
||||
|
||||
pub struct Props {
|
||||
/// The starting value for the counter
|
||||
pub initial_value: i32,
|
||||
/// The change that should be applied each time the button is clicked.
|
||||
pub step: i32,
|
||||
}
|
||||
|
||||
/// A simple counter view.
|
||||
pub fn view(cx: Scope, props: Props) -> impl IntoView {
|
||||
let Props {
|
||||
initial_value,
|
||||
step,
|
||||
} = props;
|
||||
let (value, set_value) = create_signal(cx, initial_value);
|
||||
|
||||
div(cx)
|
||||
.child((
|
||||
cx,
|
||||
button(cx)
|
||||
.on(ev::click, move |_| set_value.update(|value| *value = 0))
|
||||
.child((cx, "Clear")),
|
||||
))
|
||||
.child((
|
||||
cx,
|
||||
button(cx)
|
||||
.on(ev::click, move |_| set_value.update(|value| *value -= step))
|
||||
.child((cx, "-1")),
|
||||
))
|
||||
.child((
|
||||
cx,
|
||||
span(cx)
|
||||
.child((cx, "Value: "))
|
||||
.child((cx, move || value.get()))
|
||||
.child((cx, "!")),
|
||||
))
|
||||
.child((
|
||||
cx,
|
||||
button(cx)
|
||||
.on(ev::click, move |_| set_value.update(|value| *value += step))
|
||||
.child((cx, "+1")),
|
||||
))
|
||||
}
|
||||
16
examples/counter_without_macros/src/main.rs
Normal file
@@ -0,0 +1,16 @@
|
||||
use counter_without_macros as counter;
|
||||
use leptos::*;
|
||||
|
||||
pub fn main() {
|
||||
_ = console_log::init_with_level(log::Level::Debug);
|
||||
console_error_panic_hook::set_once();
|
||||
mount_to_body(|cx| {
|
||||
counter::view(
|
||||
cx,
|
||||
counter::Props {
|
||||
initial_value: 0,
|
||||
step: 1,
|
||||
},
|
||||
)
|
||||
})
|
||||
}
|
||||
58
examples/counter_without_macros/tests/mod.rs
Normal file
@@ -0,0 +1,58 @@
|
||||
use wasm_bindgen_test::*;
|
||||
|
||||
wasm_bindgen_test_configure!(run_in_browser);
|
||||
use counter_without_macros as counter;
|
||||
use leptos::*;
|
||||
use web_sys::HtmlElement;
|
||||
|
||||
#[wasm_bindgen_test]
|
||||
fn inc() {
|
||||
mount_to_body(|cx| {
|
||||
counter::view(
|
||||
cx,
|
||||
counter::Props {
|
||||
initial_value: 0,
|
||||
step: 1,
|
||||
},
|
||||
)
|
||||
});
|
||||
|
||||
let document = leptos::document();
|
||||
let div = document.query_selector("div").unwrap().unwrap();
|
||||
let clear = div
|
||||
.first_child()
|
||||
.unwrap()
|
||||
.dyn_into::<HtmlElement>()
|
||||
.unwrap();
|
||||
let dec = clear
|
||||
.next_sibling()
|
||||
.unwrap()
|
||||
.dyn_into::<HtmlElement>()
|
||||
.unwrap();
|
||||
let text = dec
|
||||
.next_sibling()
|
||||
.unwrap()
|
||||
.dyn_into::<HtmlElement>()
|
||||
.unwrap();
|
||||
let inc = text
|
||||
.next_sibling()
|
||||
.unwrap()
|
||||
.dyn_into::<HtmlElement>()
|
||||
.unwrap();
|
||||
|
||||
inc.click();
|
||||
inc.click();
|
||||
|
||||
assert_eq!(text.text_content(), Some("Value: 2!".to_string()));
|
||||
|
||||
dec.click();
|
||||
dec.click();
|
||||
dec.click();
|
||||
dec.click();
|
||||
|
||||
assert_eq!(text.text_content(), Some("Value: -2!".to_string()));
|
||||
|
||||
clear.click();
|
||||
|
||||
assert_eq!(text.text_content(), Some("Value: 0!".to_string()));
|
||||
}
|
||||
4
examples/counters/Makefile.toml
Normal file
@@ -0,0 +1,4 @@
|
||||
[tasks.build]
|
||||
command = "cargo"
|
||||
args = ["+nightly", "build-all-features"]
|
||||
install_crate = "cargo-all-features"
|
||||
9
examples/counters/README.md
Normal file
@@ -0,0 +1,9 @@
|
||||
# Leptos Counters Example
|
||||
|
||||
This example showcases a basic leptos app with many counters. It is a good example of how to setup a basic reactive app with signals and effects, and how to interact with browser events.
|
||||
|
||||
## Client Side Rendering
|
||||
|
||||
To run it as a client-side app, you can issue `trunk serve --open` in the root. This will build the entire app into one CSR bundle.
|
||||
|
||||
> If you don't have `trunk` installed, [click here for install instructions.](https://trunkrs.dev/)
|
||||
@@ -97,10 +97,10 @@ fn Counter(
|
||||
<li>
|
||||
<button on:click=move |_| set_value.update(move |value| *value -= 1)>"-1"</button>
|
||||
<input type="text"
|
||||
prop:value={move || value().to_string()}
|
||||
prop:value={value}
|
||||
on:input=input
|
||||
/>
|
||||
<span>{move || value().to_string()}</span>
|
||||
<span>{value}</span>
|
||||
<button on:click=move |_| set_value.update(move |value| *value += 1)>"+1"</button>
|
||||
<button on:click=move |_| set_counters.update(move |counters| counters.retain(|(counter_id, _)| counter_id != &id))>"x"</button>
|
||||
</li>
|
||||
|
||||
4
examples/counters_stable/Makefile.toml
Normal file
@@ -0,0 +1,4 @@
|
||||
[tasks.build]
|
||||
command = "cargo"
|
||||
args = ["+stable", "build-all-features"]
|
||||
install_crate = "cargo-all-features"
|
||||
9
examples/counters_stable/README.md
Normal file
@@ -0,0 +1,9 @@
|
||||
# Leptos Counters Example on Rust Stable
|
||||
|
||||
This example showcases a basic Leptos app with many counters. It is a good example of how to setup a basic reactive app with signals and effects, and how to interact with browser events. Unlike the other counters example, it will compile on Rust stable, because it has the `stable` feature enabled.
|
||||
|
||||
## Client Side Rendering
|
||||
|
||||
To run it as a client-side app, you can issue `trunk serve --open` in the root. This will build the entire app into one CSR bundle.
|
||||
|
||||
> If you don't have `trunk` installed, [click here for install instructions.](https://trunkrs.dev/)
|
||||
4
examples/fetch/Makefile.toml
Normal file
@@ -0,0 +1,4 @@
|
||||
[tasks.build]
|
||||
command = "cargo"
|
||||
args = ["+nightly", "build-all-features"]
|
||||
install_crate = "cargo-all-features"
|
||||
9
examples/fetch/README.md
Normal file
@@ -0,0 +1,9 @@
|
||||
# Client Side Fetch
|
||||
|
||||
This example shows how to fetch data from the client in WebAssembly.
|
||||
|
||||
## Client Side Rendering
|
||||
|
||||
To run it as a client-side app, you can issue `trunk serve --open` in the root. This will build the entire app into one CSR bundle.
|
||||
|
||||
> If you don't have `trunk` installed, [click here for install instructions.](https://trunkrs.dev/)
|
||||
@@ -2,6 +2,7 @@
|
||||
<html>
|
||||
<head>
|
||||
<link data-trunk rel="rust" data-wasm-opt="z"/>
|
||||
<link data-trunk rel="icon" type="image/ico" href="/public/favicon.ico"/>
|
||||
</head>
|
||||
<style>
|
||||
img {
|
||||
|
||||
BIN
examples/fetch/public/favicon.ico
Normal file
|
After Width: | Height: | Size: 15 KiB |
@@ -19,7 +19,7 @@ leptos_meta = { path = "../../meta", default-features = false }
|
||||
leptos_actix = { path = "../../integrations/actix", default-features = false, optional = true }
|
||||
leptos_router = { path = "../../router", default-features = false }
|
||||
log = "0.4"
|
||||
simple_logger = "2"
|
||||
simple_logger = "4.0.0"
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
serde_json = "1"
|
||||
gloo-net = { version = "0.2", features = ["http"] }
|
||||
@@ -56,9 +56,9 @@ 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.css"
|
||||
# [Optional] Files in the asset-dir will be copied to the site-root directory
|
||||
# assets-dir = "static/assets"
|
||||
assets-dir = "public"
|
||||
# The IP and port (ex: 127.0.0.1:3000) where the server serves the content. Use it in your server setup.
|
||||
site-address = "127.0.0.1:3000"
|
||||
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.
|
||||
|
||||
4
examples/hackernews/Makefile.toml
Normal file
@@ -0,0 +1,4 @@
|
||||
[tasks.build]
|
||||
command = "cargo"
|
||||
args = ["+nightly", "build-all-features"]
|
||||
install_crate = "cargo-all-features"
|
||||
@@ -17,6 +17,9 @@ cargo install --locked cargo-leptos
|
||||
```bash
|
||||
cargo leptos watch
|
||||
```
|
||||
|
||||
Open browser on [http://localhost:3000/](http://localhost:3000/)
|
||||
|
||||
3. When ready to deploy, run
|
||||
```bash
|
||||
cargo leptos build --release
|
||||
@@ -25,7 +28,7 @@ cargo leptos build --release
|
||||
## Server Side Rendering without cargo-leptos
|
||||
To run it as a server side app with hydration, you'll need to have wasm-pack installed.
|
||||
|
||||
0. Edit the `[package.metadata.leptos]` section and set `site-root` to `"pkg"`. You'll also want to change the path of the `<StyleSheet / >` component in the root component to point towards the CSS file in the root. This tells leptos that the WASM/JS files generated by wasm-pack are available at `./pkg` and that the CSS files are no longer processed by cargo-leptos. Building to alternative folders is not supported at this time.
|
||||
0. Edit the `[package.metadata.leptos]` section and set `site-root` to `"."`. You'll also want to change the path of the `<StyleSheet / >` component in the root component to point towards the CSS file in the root. This tells leptos that the WASM/JS files generated by wasm-pack are available at `./pkg` and that the CSS files are no longer processed by cargo-leptos. Building to alternative folders is not supported at this time. You'll also want to edit the call to `get_configuration()` to pass in `Some(Cargo.toml)`, so that Leptos will read the settings instead of cargo-leptos. If you do so, your file/folder names cannot include dashes..
|
||||
1. Install wasm-pack
|
||||
```bash
|
||||
cargo install wasm-pack
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<link data-trunk rel="rust" data-wasm-opt="z"/>
|
||||
<link data-trunk rel="rust" data-wasm-opt="z" data-cargo-features="csr"/>
|
||||
<link data-trunk rel="css" href="./style.css"/>
|
||||
</head>
|
||||
<body></body>
|
||||
|
||||
BIN
examples/hackernews/public/favicon.ico
Normal file
|
After Width: | Height: | Size: 15 KiB |
@@ -1,4 +1,4 @@
|
||||
use leptos::{on_cleanup, Scope, Serializable};
|
||||
use leptos::{Scope, Serializable};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
pub fn story(path: &str) -> String {
|
||||
@@ -29,7 +29,7 @@ where
|
||||
|
||||
// abort in-flight requests if the Scope is disposed
|
||||
// i.e., if we've navigated away from this page
|
||||
on_cleanup(cx, move || {
|
||||
leptos::on_cleanup(cx, move || {
|
||||
if let Some(abort_controller) = abort_controller {
|
||||
abort_controller.abort()
|
||||
}
|
||||
@@ -38,7 +38,7 @@ where
|
||||
}
|
||||
|
||||
#[cfg(feature = "ssr")]
|
||||
pub async fn fetch_api<T>(cx: Scope, path: &str) -> Option<T>
|
||||
pub async fn fetch_api<T>(_cx: Scope, path: &str) -> Option<T>
|
||||
where
|
||||
T: Serializable,
|
||||
{
|
||||
|
||||
@@ -15,7 +15,8 @@ pub fn App(cx: Scope) -> impl IntoView {
|
||||
view! {
|
||||
cx,
|
||||
<>
|
||||
<Stylesheet id="leptos" href="./target/site/pkg/hackernews.css"/>
|
||||
<Stylesheet id="leptos" href="/pkg/hackernews.css"/>
|
||||
<Link rel="shortcut icon" type_="image/ico" href="/favicon.ico"/>
|
||||
<Meta name="description" content="Leptos implementation of a HackerNews demo."/>
|
||||
<Router>
|
||||
<Nav />
|
||||
@@ -23,7 +24,7 @@ pub fn App(cx: Scope) -> impl IntoView {
|
||||
<Routes>
|
||||
<Route path="users/:id" view=|cx| view! { cx, <User/> }/>
|
||||
<Route path="stories/:id" view=|cx| view! { cx, <Story/> }/>
|
||||
<Route path="*stories" view=|cx| view! { cx, <Stories/> }/>
|
||||
<Route path=":stories?" view=|cx| view! { cx, <Stories/> }/>
|
||||
</Routes>
|
||||
</main>
|
||||
</Router>
|
||||
|
||||
@@ -8,28 +8,36 @@ cfg_if! {
|
||||
use actix_files::{Files};
|
||||
use actix_web::*;
|
||||
use hackernews::{App,AppProps};
|
||||
use leptos_actix::{LeptosRoutes, generate_route_list};
|
||||
|
||||
#[get("/style.css")]
|
||||
async fn css() -> impl Responder {
|
||||
actix_files::NamedFile::open_async("./style.css").await
|
||||
}
|
||||
#[get("/favicon.ico")]
|
||||
async fn favicon() -> impl Responder {
|
||||
actix_files::NamedFile::open_async("./target/site//favicon.ico").await
|
||||
}
|
||||
|
||||
#[actix_web::main]
|
||||
async fn main() -> std::io::Result<()> {
|
||||
let conf = get_configuration(Some("Cargo.toml")).await.unwrap();
|
||||
// Setting this to None means we'll be using cargo-leptos and its env vars.
|
||||
let conf = get_configuration(None).await.unwrap();
|
||||
|
||||
let addr = conf.leptos_options.site_address.clone();
|
||||
// Generate the list of routes in your Leptos App
|
||||
let routes = generate_route_list(|cx| view! { cx, <App/> });
|
||||
|
||||
HttpServer::new(move || {
|
||||
let leptos_options = &conf.leptos_options;
|
||||
let site_root = &leptos_options.site_root;
|
||||
let pkg_dir = &leptos_options.site_pkg_dir;
|
||||
let bundle_path = format!("/{site_root}/{pkg_dir}");
|
||||
|
||||
App::new()
|
||||
.service(Files::new("/pkg", "./pkg")) // used by wasm-pack and cargo run. Can be removed if using cargo-leptos
|
||||
.service(Files::new(&bundle_path, format!("./{bundle_path}"))) // used by cargo-leptos. Can be removed if using wasm-pack and cargo run.
|
||||
.service(css)
|
||||
.service(favicon)
|
||||
.route("/api/{tail:.*}", leptos_actix::handle_server_fns())
|
||||
.route("/{tail:.*}", leptos_actix::render_app_to_stream(leptos_options.to_owned(), |cx| view! { cx, <App/> }))
|
||||
.leptos_routes(leptos_options.to_owned(), routes.to_owned(), |cx| view! { cx, <App/> })
|
||||
.service(Files::new("/", &site_root))
|
||||
//.wrap(middleware::Compress::default())
|
||||
})
|
||||
.bind(&addr)?
|
||||
@@ -38,7 +46,11 @@ cfg_if! {
|
||||
}
|
||||
} else {
|
||||
fn main() {
|
||||
// no client-side main function
|
||||
use hackernews::{App, AppProps};
|
||||
|
||||
_ = console_log::init_with_level(log::Level::Debug);
|
||||
console_error_panic_hook::set_once();
|
||||
mount_to_body(|cx| view! { cx, <App/> })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -134,7 +134,7 @@ fn Story(cx: Scope, story: api::Story) -> impl IntoView {
|
||||
view! { cx,
|
||||
<span>
|
||||
{"by "}
|
||||
{story.user.map(|user| view ! { cx, <A href=format!("/users/{}", user)>{user.clone()}</A>})}
|
||||
{story.user.map(|user| view ! { cx, <A href=format!("/users/{user}")>{user.clone()}</A>})}
|
||||
{format!(" {} | ", story.time_ago)}
|
||||
<A href=format!("/stories/{}", story.id)>
|
||||
{if story.comments_count.unwrap_or_default() > 0 {
|
||||
|
||||
@@ -17,7 +17,7 @@ pub fn Story(cx: Scope) -> impl IntoView {
|
||||
}
|
||||
},
|
||||
);
|
||||
let meta_description = move || story.read().and_then(|story| story.map(|story| story.title.clone())).unwrap_or_else(|| "Loading story...".to_string());
|
||||
let meta_description = move || story.read().and_then(|story| story.map(|story| story.title)).unwrap_or_else(|| "Loading story...".to_string());
|
||||
|
||||
view! { cx,
|
||||
<>
|
||||
@@ -37,7 +37,7 @@ pub fn Story(cx: Scope) -> impl IntoView {
|
||||
{story.user.map(|user| view! { cx, <p class="meta">
|
||||
{story.points}
|
||||
" points | by "
|
||||
<A href=format!("/users/{}", user)>{user.clone()}</A>
|
||||
<A href=format!("/users/{user}")>{user.clone()}</A>
|
||||
{format!(" {}", story.time_ago)}
|
||||
</p>})}
|
||||
</div>
|
||||
|
||||
@@ -64,9 +64,9 @@ 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.css"
|
||||
# [Optional] Files in the asset-dir will be copied to the site-root directory
|
||||
# assets-dir = "static/assets"
|
||||
assets-dir = "public"
|
||||
# The IP and port (ex: 127.0.0.1:3000) where the server serves the content. Use it in your server setup.
|
||||
site-address = "127.0.0.1:3000"
|
||||
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.
|
||||
|
||||
4
examples/hackernews_axum/Makefile.toml
Normal file
@@ -0,0 +1,4 @@
|
||||
[tasks.build]
|
||||
command = "cargo"
|
||||
args = ["+nightly", "build-all-features"]
|
||||
install_crate = "cargo-all-features"
|
||||
@@ -17,6 +17,9 @@ cargo install --locked cargo-leptos
|
||||
```bash
|
||||
cargo leptos watch
|
||||
```
|
||||
|
||||
Open browser on [http://localhost:3000/](http://localhost:3000/)
|
||||
|
||||
3. When ready to deploy, run
|
||||
```bash
|
||||
cargo leptos build --release
|
||||
@@ -25,7 +28,7 @@ cargo leptos build --release
|
||||
## Server Side Rendering without cargo-leptos
|
||||
To run it as a server side app with hydration, you'll need to have wasm-pack installed.
|
||||
|
||||
0. Edit the `[package.metadata.leptos]` section and set `site-root` to `"pkg"`. You'll also want to change the path of the `<StyleSheet / >` component in the root component to point towards the CSS file in the root. This tells leptos that the WASM/JS files generated by wasm-pack are available at `./pkg` and that the CSS files are no longer processed by cargo-leptos. Building to alternative folders is not supported at this time.
|
||||
0. Edit the `[package.metadata.leptos]` section and set `site-root` to `"."`. You'll also want to change the path of the `<StyleSheet / >` component in the root component to point towards the CSS file in the root. This tells leptos that the WASM/JS files generated by wasm-pack are available at `./pkg` and that the CSS files are no longer processed by cargo-leptos. Building to alternative folders is not supported at this time. You'll also want to edit the call to `get_configuration()` to pass in `Some(Cargo.toml)`, so that Leptos will read the settings instead of cargo-leptos. If you do so, your file/folder names cannot include dashes..
|
||||
1. Install wasm-pack
|
||||
```bash
|
||||
cargo install wasm-pack
|
||||
|
||||
BIN
examples/hackernews_axum/public/favicon.ico
Normal file
|
After Width: | Height: | Size: 15 KiB |
28
examples/hackernews_axum/src/error_template.rs
Normal file
@@ -0,0 +1,28 @@
|
||||
use leptos::Errors;
|
||||
use leptos::{view, For, ForProps, IntoView, RwSignal, Scope, View};
|
||||
|
||||
// A basic function to display errors served by the error boundaries. Feel free to do more complicated things
|
||||
// here than just displaying them
|
||||
pub fn error_template(cx: Scope, errors: Option<RwSignal<Errors>>) -> View {
|
||||
let Some(errors) = errors else {
|
||||
panic!("No Errors found and we expected errors!");
|
||||
};
|
||||
view! {cx,
|
||||
<h1>"Errors"</h1>
|
||||
<For
|
||||
// a function that returns the items we're iterating over; a signal is fine
|
||||
each= move || {errors.get().0.into_iter()}
|
||||
// a unique key for each item as a reference
|
||||
key=|error| error.0.clone()
|
||||
// renders each item to a view
|
||||
view= move |error| {
|
||||
let error_string = error.1.to_string();
|
||||
view! {
|
||||
cx,
|
||||
<p>"Error: " {error_string}</p>
|
||||
}
|
||||
}
|
||||
/>
|
||||
}
|
||||
.into_view(cx)
|
||||
}
|
||||
47
examples/hackernews_axum/src/fallback.rs
Normal file
@@ -0,0 +1,47 @@
|
||||
use cfg_if::cfg_if;
|
||||
|
||||
cfg_if! {
|
||||
if #[cfg(feature = "ssr")] {
|
||||
use axum::{
|
||||
body::{boxed, Body, BoxBody},
|
||||
extract::Extension,
|
||||
response::IntoResponse,
|
||||
http::{Request, Response, StatusCode, Uri},
|
||||
};
|
||||
use axum::response::Response as AxumResponse;
|
||||
use tower::ServiceExt;
|
||||
use tower_http::services::ServeDir;
|
||||
use std::sync::Arc;
|
||||
use leptos::{LeptosOptions};
|
||||
use crate::error_template::error_template;
|
||||
|
||||
pub async fn file_and_error_handler(uri: Uri, Extension(options): Extension<Arc<LeptosOptions>>, req: Request<Body>) -> AxumResponse {
|
||||
let options = &*options;
|
||||
let root = options.site_root.clone();
|
||||
let res = get_static_file(uri.clone(), &root).await.unwrap();
|
||||
|
||||
if res.status() == StatusCode::OK {
|
||||
res.into_response()
|
||||
} else{
|
||||
let handler = leptos_axum::render_app_to_stream(options.to_owned(), |cx| error_template(cx, None));
|
||||
handler(req).await.into_response()
|
||||
}
|
||||
}
|
||||
|
||||
async fn get_static_file(uri: Uri, root: &str) -> Result<Response<BoxBody>, (StatusCode, String)> {
|
||||
let req = Request::builder().uri(uri.clone()).body(Body::empty()).unwrap();
|
||||
let root_path = format!("{root}");
|
||||
// `ServeDir` implements `tower::Service` so we can call it with `tower::ServiceExt::oneshot`
|
||||
// This path is relative to the cargo root
|
||||
match ServeDir::new(&root_path).oneshot(req).await {
|
||||
Ok(res) => Ok(res.map(boxed)),
|
||||
Err(err) => Err((
|
||||
StatusCode::INTERNAL_SERVER_ERROR,
|
||||
format!("Something went wrong: {}", err),
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -11,7 +11,6 @@ if #[cfg(feature = "ssr")] {
|
||||
|
||||
pub async fn file_handler(uri: Uri) -> Result<Response<BoxBody>, (StatusCode, String)> {
|
||||
let res = get_static_file(uri.clone(), "/pkg").await?;
|
||||
println!("FIRST URI{:?}", uri);
|
||||
|
||||
if res.status() == StatusCode::NOT_FOUND {
|
||||
// try with `.html`
|
||||
@@ -27,7 +26,6 @@ if #[cfg(feature = "ssr")] {
|
||||
|
||||
pub async fn get_static_file_handler(uri: Uri) -> Result<Response<BoxBody>, (StatusCode, String)> {
|
||||
let res = get_static_file(uri.clone(), "/static").await?;
|
||||
println!("FIRST URI{:?}", uri);
|
||||
|
||||
if res.status() == StatusCode::NOT_FOUND {
|
||||
Err((StatusCode::INTERNAL_SERVER_ERROR, "Invalid URI".to_string()))
|
||||
@@ -41,7 +39,6 @@ if #[cfg(feature = "ssr")] {
|
||||
|
||||
// `ServeDir` implements `tower::Service` so we can call it with `tower::ServiceExt::oneshot`
|
||||
// When run normally, the root should be the crate root
|
||||
println!("Base: {:#?}", base);
|
||||
if base == "/static" {
|
||||
match ServeDir::new("./static").oneshot(req).await {
|
||||
Ok(res) => Ok(res.map(boxed)),
|
||||
|
||||
@@ -3,6 +3,8 @@ use leptos::{component, view, IntoView, Scope};
|
||||
use leptos_meta::*;
|
||||
use leptos_router::*;
|
||||
mod api;
|
||||
pub mod error_template;
|
||||
pub mod fallback;
|
||||
pub mod handlers;
|
||||
mod routes;
|
||||
use routes::nav::*;
|
||||
@@ -16,7 +18,8 @@ pub fn App(cx: Scope) -> impl IntoView {
|
||||
view! {
|
||||
cx,
|
||||
<>
|
||||
<Stylesheet id="leptos" href="./target/site/pkg/hackernews_axum.css"/>
|
||||
<Link rel="shortcut icon" type_="image/ico" href="/favicon.ico"/>
|
||||
<Stylesheet id="leptos" href="/pkg/hackernews_axum.css"/>
|
||||
<Meta name="description" content="Leptos implementation of a HackerNews demo."/>
|
||||
<Router>
|
||||
<Nav />
|
||||
@@ -24,7 +27,7 @@ pub fn App(cx: Scope) -> impl IntoView {
|
||||
<Routes>
|
||||
<Route path="users/:id" view=|cx| view! { cx, <User/> }/>
|
||||
<Route path="stories/:id" view=|cx| view! { cx, <Story/> }/>
|
||||
<Route path="*stories" view=|cx| view! { cx, <Stories/> }/>
|
||||
<Route path=":stories?" view=|cx| view! { cx, <Stories/> }/>
|
||||
</Routes>
|
||||
</main>
|
||||
</Router>
|
||||
|
||||
@@ -6,10 +6,12 @@ cfg_if! {
|
||||
if #[cfg(feature = "ssr")] {
|
||||
use axum::{
|
||||
Router,
|
||||
error_handling::HandleError,
|
||||
routing::get,
|
||||
extract::Extension,
|
||||
};
|
||||
use http::StatusCode;
|
||||
use tower_http::services::ServeDir;
|
||||
use leptos_axum::{generate_route_list, LeptosRoutes};
|
||||
use std::sync::Arc;
|
||||
use hackernews_axum::fallback::file_and_error_handler;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
@@ -17,40 +19,17 @@ if #[cfg(feature = "ssr")] {
|
||||
|
||||
let conf = get_configuration(Some("Cargo.toml")).await.unwrap();
|
||||
let leptos_options = conf.leptos_options;
|
||||
let site_root = &leptos_options.site_root;
|
||||
let pkg_dir = &leptos_options.site_pkg_dir;
|
||||
|
||||
// The URL path of the generated JS/WASM bundle from cargo-leptos
|
||||
let bundle_path = format!("/{site_root}/{pkg_dir}");
|
||||
// The filesystem path of the generated JS/WASM bundle from cargo-leptos
|
||||
let bundle_filepath = format!("./{site_root}/{pkg_dir}");
|
||||
let addr = leptos_options.site_address.clone();
|
||||
log::debug!("serving at {addr}");
|
||||
let routes = generate_route_list(|cx| view! { cx, <App/> }).await;
|
||||
|
||||
simple_logger::init_with_level(log::Level::Debug).expect("couldn't initialize logging");
|
||||
|
||||
// These are Tower Services that will serve files from the static and pkg repos.
|
||||
// HandleError is needed as Axum requires services to implement Infallible Errors
|
||||
// because all Errors are converted into Responses
|
||||
let static_service = HandleError::new( ServeDir::new("./static"), handle_file_error);
|
||||
let pkg_service =HandleError::new( ServeDir::new("./pkg"), handle_file_error);
|
||||
let cargo_leptos_service = HandleError::new( ServeDir::new(&bundle_filepath), handle_file_error);
|
||||
|
||||
/// Convert the Errors from ServeDir to a type that implements IntoResponse
|
||||
async fn handle_file_error(err: std::io::Error) -> (StatusCode, String) {
|
||||
(
|
||||
StatusCode::NOT_FOUND,
|
||||
format!("File Not Found: {}", err),
|
||||
)
|
||||
}
|
||||
|
||||
// build our application with a route
|
||||
let app = Router::new()
|
||||
// `GET /` goes to `root`
|
||||
.nest_service("/pkg", pkg_service) // Only need if using wasm-pack. Can be deleted if using cargo-leptos
|
||||
.nest_service(&bundle_path, cargo_leptos_service) // Only needed if using cargo-leptos. Can be deleted if using wasm-pack and cargo-run
|
||||
.nest_service("/static", static_service)
|
||||
.fallback(leptos_axum::render_app_to_stream(leptos_options, |cx| view! { cx, <App/> }));
|
||||
.route("/favicon.ico", get(file_and_error_handler))
|
||||
.leptos_routes(leptos_options.clone(), routes, |cx| view! { cx, <App/> } )
|
||||
.fallback(file_and_error_handler)
|
||||
.layer(Extension(Arc::new(leptos_options)));
|
||||
|
||||
// run our app with hyper
|
||||
// `axum::Server` is a re-export of `hyper::Server`
|
||||
|
||||
@@ -134,7 +134,7 @@ fn Story(cx: Scope, story: api::Story) -> impl IntoView {
|
||||
view! { cx,
|
||||
<span>
|
||||
{"by "}
|
||||
{story.user.map(|user| view ! { cx, <A href=format!("/users/{}", user)>{user.clone()}</A>})}
|
||||
{story.user.map(|user| view ! { cx, <A href=format!("/users/{user}")>{user.clone()}</A>})}
|
||||
{format!(" {} | ", story.time_ago)}
|
||||
<A href=format!("/stories/{}", story.id)>
|
||||
{if story.comments_count.unwrap_or_default() > 0 {
|
||||
|
||||
@@ -17,7 +17,7 @@ pub fn Story(cx: Scope) -> impl IntoView {
|
||||
}
|
||||
},
|
||||
);
|
||||
let meta_description = move || story.read().and_then(|story| story.map(|story| story.title.clone())).unwrap_or_else(|| "Loading story...".to_string());
|
||||
let meta_description = move || story.read().and_then(|story| story.map(|story| story.title)).unwrap_or_else(|| "Loading story...".to_string());
|
||||
|
||||
view! { cx,
|
||||
<>
|
||||
@@ -37,7 +37,7 @@ pub fn Story(cx: Scope) -> impl IntoView {
|
||||
{story.user.map(|user| view! { cx, <p class="meta">
|
||||
{story.points}
|
||||
" points | by "
|
||||
<A href=format!("/users/{}", user)>{user.clone()}</A>
|
||||
<A href=format!("/users/{user}")>{user.clone()}</A>
|
||||
{format!(" {}", story.time_ago)}
|
||||
</p>})}
|
||||
</div>
|
||||
|
||||
@@ -1,326 +0,0 @@
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif;
|
||||
font-size: 15px;
|
||||
background-color: #f2f3f5;
|
||||
margin: 0;
|
||||
padding-top: 55px;
|
||||
color: #34495e;
|
||||
overflow-y: scroll
|
||||
}
|
||||
|
||||
a {
|
||||
color: #34495e;
|
||||
text-decoration: none
|
||||
}
|
||||
|
||||
.header {
|
||||
background-color: #335d92;
|
||||
position: fixed;
|
||||
z-index: 999;
|
||||
height: 55px;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0
|
||||
}
|
||||
|
||||
.header .inner {
|
||||
max-width: 800px;
|
||||
box-sizing: border-box;
|
||||
margin: 0 auto;
|
||||
padding: 15px 5px
|
||||
}
|
||||
|
||||
.header a {
|
||||
color: rgba(255, 255, 255, .8);
|
||||
line-height: 24px;
|
||||
transition: color .15s ease;
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
font-weight: 300;
|
||||
letter-spacing: .075em;
|
||||
margin-right: 1.8em
|
||||
}
|
||||
|
||||
.header a:hover {
|
||||
color: #fff
|
||||
}
|
||||
|
||||
.header a.active {
|
||||
color: #fff;
|
||||
font-weight: 400
|
||||
}
|
||||
|
||||
.header a:nth-child(6) {
|
||||
margin-right: 0
|
||||
}
|
||||
|
||||
.header .github {
|
||||
color: #fff;
|
||||
font-size: .9em;
|
||||
margin: 0;
|
||||
float: right
|
||||
}
|
||||
|
||||
.logo {
|
||||
width: 24px;
|
||||
margin-right: 10px;
|
||||
display: inline-block;
|
||||
vertical-align: middle
|
||||
}
|
||||
|
||||
.view {
|
||||
max-width: 800px;
|
||||
margin: 0 auto;
|
||||
position: relative
|
||||
}
|
||||
|
||||
.fade-enter-active,
|
||||
.fade-exit-active {
|
||||
transition: all .2s ease
|
||||
}
|
||||
|
||||
.fade-enter,
|
||||
.fade-exit-active {
|
||||
opacity: 0
|
||||
}
|
||||
|
||||
@media (max-width:860px) {
|
||||
.header .inner {
|
||||
padding: 15px 30px
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width:600px) {
|
||||
.header .inner {
|
||||
padding: 15px
|
||||
}
|
||||
|
||||
.header a {
|
||||
margin-right: 1em
|
||||
}
|
||||
|
||||
.header .github {
|
||||
display: none
|
||||
}
|
||||
}
|
||||
|
||||
.news-view {
|
||||
padding-top: 45px
|
||||
}
|
||||
|
||||
.news-list,
|
||||
.news-list-nav {
|
||||
background-color: #fff;
|
||||
border-radius: 2px
|
||||
}
|
||||
|
||||
.news-list-nav {
|
||||
padding: 15px 30px;
|
||||
position: fixed;
|
||||
text-align: center;
|
||||
top: 55px;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 998;
|
||||
box-shadow: 0 1px 2px rgba(0, 0, 0, .1)
|
||||
}
|
||||
|
||||
.news-list-nav .page-link {
|
||||
margin: 0 1em
|
||||
}
|
||||
|
||||
.news-list-nav .disabled {
|
||||
color: #aaa
|
||||
}
|
||||
|
||||
.news-list {
|
||||
position: absolute;
|
||||
margin: 30px 0;
|
||||
width: 100%;
|
||||
transition: all .5s cubic-bezier(.55, 0, .1, 1)
|
||||
}
|
||||
|
||||
.news-list ul {
|
||||
list-style-type: none;
|
||||
padding: 0;
|
||||
margin: 0
|
||||
}
|
||||
|
||||
@media (max-width:600px) {
|
||||
.news-list {
|
||||
margin: 10px 0
|
||||
}
|
||||
}
|
||||
|
||||
.news-item {
|
||||
background-color: #fff;
|
||||
padding: 20px 30px 20px 80px;
|
||||
border-bottom: 1px solid #eee;
|
||||
position: relative;
|
||||
line-height: 20px
|
||||
}
|
||||
|
||||
.news-item .score {
|
||||
color: #335d92;
|
||||
font-size: 1.1em;
|
||||
font-weight: 700;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 0;
|
||||
width: 80px;
|
||||
text-align: center;
|
||||
margin-top: -10px
|
||||
}
|
||||
|
||||
.news-item .host,
|
||||
.news-item .meta {
|
||||
font-size: .85em;
|
||||
color: #626262
|
||||
}
|
||||
|
||||
.news-item .host a,
|
||||
.news-item .meta a {
|
||||
color: #626262;
|
||||
text-decoration: underline
|
||||
}
|
||||
|
||||
.news-item .host a:hover,
|
||||
.news-item .meta a:hover {
|
||||
color: #335d92
|
||||
}
|
||||
|
||||
.item-view-header {
|
||||
background-color: #fff;
|
||||
padding: 1.8em 2em 1em;
|
||||
box-shadow: 0 1px 2px rgba(0, 0, 0, .1)
|
||||
}
|
||||
|
||||
.item-view-header h1 {
|
||||
display: inline;
|
||||
font-size: 1.5em;
|
||||
margin: 0;
|
||||
margin-right: .5em
|
||||
}
|
||||
|
||||
.item-view-header .host,
|
||||
.item-view-header .meta,
|
||||
.item-view-header .meta a {
|
||||
color: #626262
|
||||
}
|
||||
|
||||
.item-view-header .meta a {
|
||||
text-decoration: underline
|
||||
}
|
||||
|
||||
.item-view-comments {
|
||||
background-color: #fff;
|
||||
margin-top: 10px;
|
||||
padding: 0 2em .5em
|
||||
}
|
||||
|
||||
.item-view-comments-header {
|
||||
margin: 0;
|
||||
font-size: 1.1em;
|
||||
padding: 1em 0;
|
||||
position: relative
|
||||
}
|
||||
|
||||
.item-view-comments-header .spinner {
|
||||
display: inline-block;
|
||||
margin: -15px 0
|
||||
}
|
||||
|
||||
.comment-children {
|
||||
list-style-type: none;
|
||||
padding: 0;
|
||||
margin: 0
|
||||
}
|
||||
|
||||
@media (max-width:600px) {
|
||||
.item-view-header h1 {
|
||||
font-size: 1.25em
|
||||
}
|
||||
}
|
||||
|
||||
.comment-children .comment-children {
|
||||
margin-left: 1.5em
|
||||
}
|
||||
|
||||
.comment {
|
||||
border-top: 1px solid #eee;
|
||||
position: relative
|
||||
}
|
||||
|
||||
.comment .by,
|
||||
.comment .text,
|
||||
.comment .toggle {
|
||||
font-size: .9em;
|
||||
margin: 1em 0
|
||||
}
|
||||
|
||||
.comment .by {
|
||||
color: #626262
|
||||
}
|
||||
|
||||
.comment .by a {
|
||||
color: #626262;
|
||||
text-decoration: underline
|
||||
}
|
||||
|
||||
.comment .text {
|
||||
overflow-wrap: break-word
|
||||
}
|
||||
|
||||
.comment .text a:hover {
|
||||
color: #335d92
|
||||
}
|
||||
|
||||
.comment .text pre {
|
||||
white-space: pre-wrap
|
||||
}
|
||||
|
||||
.comment .toggle {
|
||||
background-color: #fffbf2;
|
||||
padding: .3em .5em;
|
||||
border-radius: 4px
|
||||
}
|
||||
|
||||
.comment .toggle a {
|
||||
color: #626262;
|
||||
cursor: pointer
|
||||
}
|
||||
|
||||
.comment .toggle.open {
|
||||
padding: 0;
|
||||
background-color: transparent;
|
||||
margin-bottom: -.5em
|
||||
}
|
||||
|
||||
.user-view {
|
||||
background-color: #fff;
|
||||
box-sizing: border-box;
|
||||
padding: 2em 3em
|
||||
}
|
||||
|
||||
.user-view h1 {
|
||||
margin: 0;
|
||||
font-size: 1.5em
|
||||
}
|
||||
|
||||
.user-view .meta {
|
||||
list-style-type: none;
|
||||
padding: 0
|
||||
}
|
||||
|
||||
.user-view .label {
|
||||
display: inline-block;
|
||||
min-width: 4em
|
||||
}
|
||||
|
||||
.user-view .about {
|
||||
margin: 1em 0
|
||||
}
|
||||
|
||||
.user-view .links a {
|
||||
text-decoration: underline
|
||||
}
|
||||
4
examples/parent_child/Makefile.toml
Normal file
@@ -0,0 +1,4 @@
|
||||
[tasks.build]
|
||||
command = "cargo"
|
||||
args = ["+nightly", "build-all-features"]
|
||||
install_crate = "cargo-all-features"
|
||||
17
examples/parent_child/README.md
Normal file
@@ -0,0 +1,17 @@
|
||||
# Parent Child Example
|
||||
|
||||
This example highlights four different ways that child components can communicate with their parent:
|
||||
|
||||
1. <ButtonA/>: passing a WriteSignal as one of the child component props,
|
||||
for the child component to write into and the parent to read
|
||||
2. <ButtonB/>: passing a closure as one of the child component props, for
|
||||
the child component to call
|
||||
3. <ButtonC/>: adding a simple event listener on the child component itself
|
||||
4. <ButtonD/>: providing a context that is used in the component (rather than prop drilling)
|
||||
|
||||
## Client Side Rendering
|
||||
|
||||
To run it as a Client Side App, you can issue `trunk serve --open` in the root. This will build the entire
|
||||
app into one CSR bundle
|
||||
|
||||
> If you don't have `trunk` installed, [click here for install instructions.](https://trunkrs.dev/)
|
||||
@@ -2,6 +2,7 @@
|
||||
<html>
|
||||
<head>
|
||||
<link data-trunk rel="rust" data-wasm-opt="z"/>
|
||||
<link data-trunk rel="icon" type="image/ico" href="/public/favicon.ico"/>
|
||||
<style>
|
||||
.red {
|
||||
color: red;
|
||||
|
||||
BIN
examples/parent_child/public/favicon.ico
Normal file
|
After Width: | Height: | Size: 15 KiB |
@@ -7,11 +7,11 @@ edition = "2021"
|
||||
console_log = "0.2"
|
||||
log = "0.4"
|
||||
leptos = { path = "../../leptos" }
|
||||
leptos_router = { path = "../../router", features=["csr"] }
|
||||
leptos_router = { path = "../../router", features = ["csr"] }
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
futures = "0.3"
|
||||
console_error_panic_hook = "0.1.7"
|
||||
leptos_meta = { path = "../../meta", default-features = false }
|
||||
leptos_meta = { path = "../../meta", features = ["csr"] }
|
||||
|
||||
[dev-dependencies]
|
||||
wasm-bindgen-test = "0.3.0"
|
||||
|
||||
4
examples/router/Makefile.toml
Normal file
@@ -0,0 +1,4 @@
|
||||
[tasks.build]
|
||||
command = "cargo"
|
||||
args = ["+nightly", "build-all-features"]
|
||||
install_crate = "cargo-all-features"
|
||||
@@ -1,8 +1,11 @@
|
||||
# Leptos Router Example
|
||||
|
||||
This example demonstrates how Leptos' router works
|
||||
This example demonstrates how Leptos’s router works for client side routing.
|
||||
|
||||
## Build and Run it
|
||||
|
||||
## Run it
|
||||
```bash
|
||||
trunk serve --open
|
||||
```
|
||||
|
||||
> If you don't have `trunk` installed, [click here for install instructions.](https://trunkrs.dev/)
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
<html>
|
||||
<head>
|
||||
<link data-trunk rel="rust" data-wasm-opt="z"/>
|
||||
<link data-trunk rel="icon" type="image/ico" href="/public/favicon.ico"/>
|
||||
<style>
|
||||
a[aria-current] {
|
||||
font-weight: bold;
|
||||
|
||||
BIN
examples/router/public/favicon.ico
Normal file
|
After Width: | Height: | Size: 15 KiB |
@@ -12,6 +12,11 @@ pub fn RouterExample(cx: Scope) -> impl IntoView {
|
||||
view! { cx,
|
||||
<Router>
|
||||
<nav>
|
||||
// ordinary <a> elements can be used for client-side navigation
|
||||
// using <A> has two effects:
|
||||
// 1) ensuring that relative routing works properly for nested routes
|
||||
// 2) setting the `aria-current` attribute on the current link,
|
||||
// for a11y and styling purposes
|
||||
<A exact=true href="/">"Contacts"</A>
|
||||
<A href="about">"About"</A>
|
||||
<A href="settings">"Settings"</A>
|
||||
@@ -105,12 +110,15 @@ pub fn Contact(cx: Scope) -> impl IntoView {
|
||||
// Some(None) => has loaded and found no contact
|
||||
Some(None) => Some(view! { cx, <p>"No contact with this ID was found."</p> }.into_any()),
|
||||
// Some(Some) => has loaded and found a contact
|
||||
Some(Some(contact)) => Some(view! { cx,
|
||||
<section class="card">
|
||||
<h1>{contact.first_name} " " {contact.last_name}</h1>
|
||||
<p>{contact.address_1}<br/>{contact.address_2}</p>
|
||||
</section>
|
||||
}.into_any()),
|
||||
Some(Some(contact)) => Some(
|
||||
view! { cx,
|
||||
<section class="card">
|
||||
<h1>{contact.first_name} " " {contact.last_name}</h1>
|
||||
<p>{contact.address_1}<br/>{contact.address_2}</p>
|
||||
</section>
|
||||
}
|
||||
.into_any(),
|
||||
),
|
||||
};
|
||||
|
||||
view! { cx,
|
||||
@@ -125,9 +133,18 @@ pub fn Contact(cx: Scope) -> impl IntoView {
|
||||
#[component]
|
||||
pub fn About(cx: Scope) -> impl IntoView {
|
||||
log::debug!("rendering <About/>");
|
||||
// use_navigate allows you to navigate programmatically by calling a function
|
||||
let navigate = use_navigate(cx);
|
||||
|
||||
view! { cx,
|
||||
<>
|
||||
// note: this is just an illustration of how to use `use_navigate`
|
||||
// <button on:click> to navigate is an *anti-pattern*
|
||||
// you should ordinarily use a link instead,
|
||||
// both semantically and so your link will work before WASM loads
|
||||
<button on:click=move |_| { _ = navigate("/", Default::default()); }>
|
||||
"Home"
|
||||
</button>
|
||||
<h1>"About"</h1>
|
||||
<p>"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."</p>
|
||||
</>
|
||||
|
||||
@@ -11,7 +11,7 @@ crate-type = ["cdylib", "rlib"]
|
||||
|
||||
[dependencies]
|
||||
leptos = { path = "../../leptos", default-features = false, features = [
|
||||
"serde",
|
||||
"serde",
|
||||
] }
|
||||
leptos_actix = { path = "../../integrations/actix", optional = true }
|
||||
leptos_meta = { path = "../../meta", default-features = false }
|
||||
@@ -30,10 +30,6 @@ actix-files = { version = "0.6", optional = true }
|
||||
actix-web = { version = "4", features = ["macros"], optional = true }
|
||||
futures = { version = "0.3", optional = true }
|
||||
simple_logger = { version = "4.0", optional = true }
|
||||
serde_json = { version = "1.0", optional = true }
|
||||
reqwest = { version = "0.11", features = ["json"], optional = true }
|
||||
|
||||
|
||||
|
||||
[features]
|
||||
default = ["csr"]
|
||||
@@ -57,17 +53,24 @@ ssr = [
|
||||
"leptos/ssr",
|
||||
"leptos_meta/ssr",
|
||||
"leptos_router/ssr",
|
||||
"dep:reqwest",
|
||||
"dep:leptos_actix",
|
||||
"dep:actix-web",
|
||||
"dep:actix-files",
|
||||
"dep:futures",
|
||||
"dep:simple_logger",
|
||||
"dep:serde_json",
|
||||
]
|
||||
|
||||
[package.metadata.cargo-all-features]
|
||||
denylist = ["actix-files", "actix-web", "leptos_actix"]
|
||||
denylist = [
|
||||
"actix-files",
|
||||
"actix-web",
|
||||
"console_error_panic_hook",
|
||||
"console_log",
|
||||
"futures",
|
||||
"leptos_actix",
|
||||
"simple_logger",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
skip_feature_sets = [["csr", "ssr"], ["csr", "hydrate"], ["ssr", "hydrate"]]
|
||||
|
||||
[profile.release]
|
||||
@@ -77,26 +80,26 @@ opt-level = 'z'
|
||||
|
||||
[package.metadata.leptos]
|
||||
# The name used by wasm-bindgen/cargo-leptos for the JS/WASM bundle. Defaults to the crate name
|
||||
output-name = "tailwind"
|
||||
output-name = "tailwind"
|
||||
# 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"
|
||||
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"
|
||||
style-file = "style/output.css"
|
||||
# [Optional] Files in the asset-dir will be copied to the site-root directory
|
||||
assets-dir = "assets"
|
||||
assets-dir = "public"
|
||||
# The IP and port (ex: 127.0.0.1:3000) where the server serves the content. Use it in your server setup.
|
||||
site-address = "127.0.0.1:3000"
|
||||
site-addr = "127.0.0.1:3000"
|
||||
# The port to use for automatic reload monitoring
|
||||
reload-port = 3001
|
||||
reload-port = 3001
|
||||
# [Optional] Command to use when running end2end tests. It will run in the end2end dir.
|
||||
end2end-cmd = "npx playwright test"
|
||||
# The browserlist query used for optimizing the CSS.
|
||||
browserquery = "defaults"
|
||||
browserquery = "defaults"
|
||||
# Set by cargo-leptos watch when building with tha tool. Controls whether autoreload JS will be included in the head
|
||||
watch = false
|
||||
watch = false
|
||||
# The environment Leptos will run in, usually either "DEV" or "PROD"
|
||||
env = "DEV"
|
||||
# The features to use when compiling the bin target
|
||||
|
||||
4
examples/tailwind/Makefile.toml
Normal file
@@ -0,0 +1,4 @@
|
||||
[tasks.build]
|
||||
command = "cargo"
|
||||
args = ["+nightly", "build-all-features"]
|
||||
install_crate = "cargo-all-features"
|
||||
@@ -1,6 +1,6 @@
|
||||
# Leptos Starter Template
|
||||
|
||||
This is a template demonstrating how to integrate [TailwindCSS](https://tailwindcss.com/) with the [Leptos](https://github.com/gbj/leptos) web framework and the [cargo-leptos](https://github.com/akesson/cargo-leptos) tool.
|
||||
This is a template demonstrating how to integrate [TailwindCSS](https://tailwindcss.com/) with the [Leptos](https://github.com/leptos-rs/leptos) web framework and the [cargo-leptos](https://github.com/akesson/cargo-leptos) tool.
|
||||
|
||||
If you don't have `cargo-leptos` installed you can install it with
|
||||
|
||||
@@ -16,6 +16,8 @@ and
|
||||
|
||||
in this directory.
|
||||
|
||||
Open browser on [http://localhost:3000/](http://localhost:3000/)
|
||||
|
||||
You can begin editing your app at `src/app.rs`.
|
||||
|
||||
## Installing Tailwind
|
||||
@@ -52,13 +54,11 @@ If you're using VS Code, add the following to your `settings.json`
|
||||
"css.validate": false,
|
||||
```
|
||||
|
||||
|
||||
Install [Tailwind CSS Intellisense](https://marketplace.visualstudio.com/items?itemName=bradlc.vscode-tailwindcss).
|
||||
|
||||
Install "VS Browser" extension, a browser at the right window.
|
||||
Allow vscode Ports forward: 3000, 3001.
|
||||
|
||||
|
||||
## Notes about Tooling
|
||||
|
||||
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.
|
||||
@@ -72,8 +72,8 @@ By default, `cargo-leptos` uses `nightly` Rust, `cargo-generate`, and `sass`. If
|
||||
## Alternatives to cargo-leptos
|
||||
|
||||
This crate can be run without `cargo-leptos`, using `wasm-pack` and `cargo`. To do so, you'll need to install some other tools.
|
||||
|
||||
1. `cargo install wasm-pack`
|
||||
0. `cargo install wasm-pack`
|
||||
1. Edit the `[package.metadata.leptos]` section and set `site-root` to `"."`. You'll also want to change the path of the `<StyleSheet / >` component in the root component to point towards the CSS file in the root. This tells leptos that the WASM/JS files generated by wasm-pack are available at `./pkg` and that the CSS files are no longer processed by cargo-leptos. Building to alternative folders is not supported at this time. You'll also want to edit the call to `get_configuration()` to pass in `Some(Cargo.toml)`, so that Leptos will read the settings instead of cargo-leptos. If you do so, your file/folder names cannot include dashes.
|
||||
|
||||
### Server Side Rendering With Hydration
|
||||
|
||||
@@ -91,15 +91,16 @@ Then run the server with `cargo run` to serve the server side rendered HTML and
|
||||
cargo run --no-default-features --features=ssr
|
||||
```
|
||||
|
||||
> Note that if your hydration code changes, you will have to rerun the wasm-pack command above before running
|
||||
> Note that if your hydration code changes, you will have to rerun the wasm-pack command above before running
|
||||
> `cargo run`
|
||||
|
||||
### Client Side Rendering
|
||||
|
||||
You'll need to install trunk to client side render this bundle.
|
||||
|
||||
1. `cargo install trunk`
|
||||
Then the site can be served with `trunk serve --open`
|
||||
Then the site can be served with `trunk serve --open`
|
||||
|
||||
## Attribution
|
||||
|
||||
Many thanks to GreatGreg for putting together this guide. You can find the original, with added details, [here](https://github.com/gbj/leptos/discussions/125).
|
||||
Many thanks to GreatGreg for putting together this guide. You can find the original, with added details, [here](https://github.com/leptos-rs/leptos/discussions/125).
|
||||
|
||||
|
Before Width: | Height: | Size: 101 KiB |
BIN
examples/tailwind/public/favicon.ico
Normal file
|
After Width: | Height: | Size: 15 KiB |
@@ -1,28 +1,37 @@
|
||||
use leptos::*;
|
||||
use leptos_meta::*;
|
||||
use leptos_router::*;
|
||||
|
||||
#[component]
|
||||
pub fn App(cx: Scope) -> impl IntoView {
|
||||
provide_meta_context(cx);
|
||||
|
||||
let (count, set_count) = create_signal(cx, 0);
|
||||
|
||||
|
||||
view! {
|
||||
cx,
|
||||
<main class="my-0 mx-auto max-w-3xl text-center">
|
||||
<Stylesheet id="leptos" href="/style.css"/>
|
||||
<h2 class="p-6 text-4xl">"Welcome to Leptos with Tailwind"</h2>
|
||||
<p class="px-10 pb-10 text-left">"Tailwind will scan your Rust files for Tailwind class names and compile them into a CSS file."</p>
|
||||
<button
|
||||
class="bg-sky-600 hover:bg-sky-700 px-5 py-3 text-white rounded-lg"
|
||||
on:click=move |_| set_count.update(|count| *count += 1)
|
||||
>
|
||||
{move || if count() == 0 {
|
||||
"Click me!".to_string()
|
||||
} else {
|
||||
count().to_string()
|
||||
}}
|
||||
</button>
|
||||
</main>
|
||||
<Stylesheet id="leptos" href="/pkg/tailwind.css"/>
|
||||
<Link rel="shortcut icon" type_="image/ico" href="/favicon.ico"/>
|
||||
<Router>
|
||||
<Routes>
|
||||
<Route path="" view= move |cx| view! {
|
||||
cx,
|
||||
<main class="my-0 mx-auto max-w-3xl text-center">
|
||||
<h2 class="p-6 text-4xl">"Welcome to Leptos with Tailwind"</h2>
|
||||
<p class="px-10 pb-10 text-left">"Tailwind will scan your Rust files for Tailwind class names and compile them into a CSS file."</p>
|
||||
<button
|
||||
class="bg-sky-600 hover:bg-sky-700 px-5 py-3 text-white rounded-lg"
|
||||
on:click=move |_| set_count.update(|count| *count += 1)
|
||||
>
|
||||
{move || if count() == 0 {
|
||||
"Click me!".to_string()
|
||||
} else {
|
||||
count().to_string()
|
||||
}}
|
||||
</button>
|
||||
</main>
|
||||
}/>
|
||||
</Routes>
|
||||
</Router>
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
mod app;
|
||||
#[cfg(feature = "ssr")]
|
||||
use cfg_if::cfg_if;
|
||||
|
||||
cfg_if! {
|
||||
@@ -8,6 +7,7 @@ cfg_if! {
|
||||
use actix_web::*;
|
||||
use leptos::*;
|
||||
use crate::app::*;
|
||||
use leptos_actix::{generate_route_list, LeptosRoutes};
|
||||
|
||||
#[get("/style.css")]
|
||||
async fn css() -> impl Responder {
|
||||
@@ -16,20 +16,23 @@ cfg_if! {
|
||||
|
||||
#[actix_web::main]
|
||||
async fn main() -> std::io::Result<()> {
|
||||
let conf = get_configuration(Some("Cargo.toml")).await.unwrap();
|
||||
|
||||
// Setting this to None means we'll be using cargo-leptos and its env vars.
|
||||
let conf = get_configuration(None).await.unwrap();
|
||||
|
||||
let addr = conf.leptos_options.site_address.clone();
|
||||
let leptos_options = &conf.leptos_options;
|
||||
let site_root = &leptos_options.site_root;
|
||||
let pkg_dir = &leptos_options.site_pkg_dir;
|
||||
let bundle_path = format!("/{site_root}/{pkg_dir}");
|
||||
|
||||
// Generate the list of routes in your Leptos App
|
||||
let routes = generate_route_list(|cx| view! { cx, <App/> });
|
||||
|
||||
HttpServer::new(move || {
|
||||
let leptos_options = &conf.leptos_options;
|
||||
let site_root = &leptos_options.site_root;
|
||||
let routes = &routes;
|
||||
App::new()
|
||||
.service(css)
|
||||
.service(Files::new("/pkg", "./pkg")) // used by wasm-pack and cargo run. Can be removed if using cargo-leptos
|
||||
.service(Files::new(&bundle_path, format!("./{bundle_path}"))) // used by cargo-leptos. Can be removed if using wasm-pack and cargo run.
|
||||
.route("/{tail:.*}", leptos_actix::render_app_to_stream(leptos_options.to_owned(), |cx| view! { cx, <App/> }))
|
||||
.leptos_routes(leptos_options.to_owned(), routes.to_owned(), |cx| view! { cx, <App/> })
|
||||
.service(Files::new("/", &site_root))
|
||||
.wrap(middleware::Compress::default())
|
||||
})
|
||||
.bind(&addr)?
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
! tailwindcss v3.2.4 | MIT License | https://tailwindcss.com
|
||||
! tailwindcss v3.1.8 | MIT License | https://tailwindcss.com
|
||||
*/
|
||||
|
||||
/*
|
||||
@@ -30,7 +30,6 @@
|
||||
2. Prevent adjustments of font size after orientation changes in iOS.
|
||||
3. Use a more readable tab size.
|
||||
4. Use the user's configured `sans` font-family by default.
|
||||
5. Use the user's configured `sans` font-feature-settings by default.
|
||||
*/
|
||||
|
||||
html {
|
||||
@@ -45,8 +44,6 @@ html {
|
||||
/* 3 */
|
||||
font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
|
||||
/* 4 */
|
||||
font-feature-settings: normal;
|
||||
/* 5 */
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -413,13 +410,54 @@ video {
|
||||
height: auto;
|
||||
}
|
||||
|
||||
/* Make elements with the HTML hidden attribute stay hidden by default */
|
||||
|
||||
[hidden] {
|
||||
display: none;
|
||||
*, ::before, ::after {
|
||||
--tw-border-spacing-x: 0;
|
||||
--tw-border-spacing-y: 0;
|
||||
--tw-translate-x: 0;
|
||||
--tw-translate-y: 0;
|
||||
--tw-rotate: 0;
|
||||
--tw-skew-x: 0;
|
||||
--tw-skew-y: 0;
|
||||
--tw-scale-x: 1;
|
||||
--tw-scale-y: 1;
|
||||
--tw-pan-x: ;
|
||||
--tw-pan-y: ;
|
||||
--tw-pinch-zoom: ;
|
||||
--tw-scroll-snap-strictness: proximity;
|
||||
--tw-ordinal: ;
|
||||
--tw-slashed-zero: ;
|
||||
--tw-numeric-figure: ;
|
||||
--tw-numeric-spacing: ;
|
||||
--tw-numeric-fraction: ;
|
||||
--tw-ring-inset: ;
|
||||
--tw-ring-offset-width: 0px;
|
||||
--tw-ring-offset-color: #fff;
|
||||
--tw-ring-color: rgb(59 130 246 / 0.5);
|
||||
--tw-ring-offset-shadow: 0 0 #0000;
|
||||
--tw-ring-shadow: 0 0 #0000;
|
||||
--tw-shadow: 0 0 #0000;
|
||||
--tw-shadow-colored: 0 0 #0000;
|
||||
--tw-blur: ;
|
||||
--tw-brightness: ;
|
||||
--tw-contrast: ;
|
||||
--tw-grayscale: ;
|
||||
--tw-hue-rotate: ;
|
||||
--tw-invert: ;
|
||||
--tw-saturate: ;
|
||||
--tw-sepia: ;
|
||||
--tw-drop-shadow: ;
|
||||
--tw-backdrop-blur: ;
|
||||
--tw-backdrop-brightness: ;
|
||||
--tw-backdrop-contrast: ;
|
||||
--tw-backdrop-grayscale: ;
|
||||
--tw-backdrop-hue-rotate: ;
|
||||
--tw-backdrop-invert: ;
|
||||
--tw-backdrop-opacity: ;
|
||||
--tw-backdrop-saturate: ;
|
||||
--tw-backdrop-sepia: ;
|
||||
}
|
||||
|
||||
*, ::before, ::after {
|
||||
::-webkit-backdrop {
|
||||
--tw-border-spacing-x: 0;
|
||||
--tw-border-spacing-y: 0;
|
||||
--tw-translate-x: 0;
|
||||
|
||||
@@ -58,9 +58,9 @@ 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.css"
|
||||
# [Optional] Files in the asset-dir will be copied to the site-root directory
|
||||
# assets-dir = "static/assets"
|
||||
assets-dir = "public"
|
||||
# The IP and port (ex: 127.0.0.1:3000) where the server serves the content. Use it in your server setup.
|
||||
site-address = "127.0.0.1:3000"
|
||||
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.
|
||||
|
||||
4
examples/todo_app_sqlite/Makefile.toml
Normal file
@@ -0,0 +1,4 @@
|
||||
[tasks.build]
|
||||
command = "cargo"
|
||||
args = ["+nightly", "build-all-features"]
|
||||
install_crate = "cargo-all-features"
|
||||
@@ -17,6 +17,9 @@ cargo install --locked cargo-leptos
|
||||
```bash
|
||||
cargo leptos watch
|
||||
```
|
||||
|
||||
Open browser on [http://localhost:3000/](http://localhost:3000/)
|
||||
|
||||
3. When ready to deploy, run
|
||||
```bash
|
||||
cargo leptos build --release
|
||||
@@ -25,7 +28,7 @@ cargo leptos build --release
|
||||
## Server Side Rendering without cargo-leptos
|
||||
To run it as a server side app with hydration, you'll need to have wasm-pack installed.
|
||||
|
||||
0. Edit the `[package.metadata.leptos]` section and set `site-root` to `"pkg"`. You'll also want to change the path of the `<StyleSheet / >` component in the root component to point towards the CSS file in the root. This tells leptos that the WASM/JS files generated by wasm-pack are available at `./pkg` and that the CSS file is no longer processed by cargo-leptos. Building to alternative folders is not supported at this time
|
||||
0. Edit the `[package.metadata.leptos]` section and set `site-root` to `"."`. You'll also want to change the path of the `<StyleSheet / >` component in the root component to point towards the CSS file in the root. This tells leptos that the WASM/JS files generated by wasm-pack are available at `./pkg` and that the CSS files are no longer processed by cargo-leptos. Building to alternative folders is not supported at this time. You'll also want to edit the call to `get_configuration()` to pass in `Some(Cargo.toml)`, so that Leptos will read the settings instead of cargo-leptos. If you do so, your file/folder names cannot include dashes.
|
||||
1. Install wasm-pack
|
||||
```bash
|
||||
cargo install wasm-pack
|
||||
|
||||
BIN
examples/todo_app_sqlite/public/favicon.ico
Normal file
|
After Width: | Height: | Size: 15 KiB |
@@ -9,6 +9,7 @@ cfg_if! {
|
||||
use actix_files::{Files};
|
||||
use actix_web::*;
|
||||
use crate::todo::*;
|
||||
use leptos_actix::{generate_route_list, LeptosRoutes};
|
||||
|
||||
#[get("/style.css")]
|
||||
async fn css() -> impl Responder {
|
||||
@@ -25,23 +26,25 @@ cfg_if! {
|
||||
|
||||
crate::todo::register_server_functions();
|
||||
|
||||
// Setting this to None means we'll be using cargo-leptos and its env vars.
|
||||
let conf = get_configuration(None).await.unwrap();
|
||||
|
||||
let conf = get_configuration(Some("Cargo.toml")).await.unwrap();
|
||||
let addr = conf.leptos_options.site_address.clone();
|
||||
|
||||
// Generate the list of routes in your Leptos App
|
||||
let routes = generate_route_list(|cx| view! { cx, <TodoApp/> });
|
||||
|
||||
HttpServer::new(move || {
|
||||
let leptos_options = &conf.leptos_options;
|
||||
let site_root = &leptos_options.site_root;
|
||||
let pkg_dir = &leptos_options.site_pkg_dir;
|
||||
let bundle_path = format!("/{site_root}/{pkg_dir}");
|
||||
let routes = &routes;
|
||||
|
||||
App::new()
|
||||
.service(Files::new("/pkg", "./pkg")) // used by wasm-pack and cargo run. Can be removed if using cargo-leptos
|
||||
.service(Files::new(&bundle_path, format!("./{bundle_path}"))) // used by cargo-leptos. Can be removed if using wasm-pack and cargo run.
|
||||
.service(css)
|
||||
.route("/api/{tail:.*}", leptos_actix::handle_server_fns())
|
||||
.route("/{tail:.*}", leptos_actix::render_app_to_stream(leptos_options.to_owned(), |cx| view! { cx, <TodoApp/> }))
|
||||
//.wrap(middleware::Compress::default())
|
||||
.leptos_routes(leptos_options.to_owned(), routes.to_owned(), |cx| view! { cx, <TodoApp/> })
|
||||
.service(Files::new("/", &site_root))
|
||||
//.wrap(middleware::Compress::default())
|
||||
})
|
||||
.bind(addr)?
|
||||
.run()
|
||||
|
||||
@@ -38,9 +38,11 @@ cfg_if! {
|
||||
pub async fn get_todos(cx: Scope) -> Result<Vec<Todo>, ServerFnError> {
|
||||
// this is just an example of how to access server context injected in the handlers
|
||||
let req =
|
||||
use_context::<actix_web::HttpRequest>(cx).expect("couldn't get HttpRequest from context");
|
||||
println!("req.path = {:?}", req.path());
|
||||
|
||||
use_context::<actix_web::HttpRequest>(cx);
|
||||
|
||||
if let Some(req) = req{
|
||||
println!("req.path = {:#?}", req.path());
|
||||
}
|
||||
use futures::TryStreamExt;
|
||||
|
||||
let mut conn = db().await?;
|
||||
@@ -90,9 +92,11 @@ pub async fn delete_todo(id: u16) -> Result<(), ServerFnError> {
|
||||
|
||||
#[component]
|
||||
pub fn TodoApp(cx: Scope) -> impl IntoView {
|
||||
provide_meta_context(cx);
|
||||
view! {
|
||||
cx,
|
||||
<Stylesheet id="leptos" href="./target/site/pkg/todo_app_sqlite.css"/>
|
||||
<Link rel="shortcut icon" type_="image/ico" href="/favicon.ico"/>
|
||||
<Stylesheet id="leptos" href="/pkg/todo_app_sqlite.css"/>
|
||||
<Router>
|
||||
<header>
|
||||
<h1>"My Tasks"</h1>
|
||||
|
||||
@@ -18,6 +18,7 @@ leptos = { path = "../../../leptos/leptos", default-features = false, features =
|
||||
leptos_axum = { path = "../../../leptos/integrations/axum", default-features = false, optional = true }
|
||||
leptos_meta = { path = "../../../leptos/meta", default-features = false }
|
||||
leptos_router = { path = "../../../leptos/router", default-features = false }
|
||||
leptos_reactive = { path = "../../../leptos/leptos_reactive", default-features = false }
|
||||
log = "0.4.17"
|
||||
simple_logger = "4.0.0"
|
||||
serde = { version = "1.0.148", features = ["derive"] }
|
||||
@@ -38,17 +39,7 @@ sqlx = { version = "0.6.2", features = [
|
||||
default = ["csr"]
|
||||
csr = ["leptos/csr", "leptos_meta/csr", "leptos_router/csr"]
|
||||
hydrate = ["leptos/hydrate", "leptos_meta/hydrate", "leptos_router/hydrate"]
|
||||
ssr = [
|
||||
"dep:axum",
|
||||
"dep:tower",
|
||||
"dep:tower-http",
|
||||
"dep:tokio",
|
||||
"dep:sqlx",
|
||||
"leptos/ssr",
|
||||
"leptos_meta/ssr",
|
||||
"leptos_router/ssr",
|
||||
"leptos_axum",
|
||||
]
|
||||
ssr = ["dep:axum", "dep:tower", "dep:tower-http", "dep:tokio", "dep:sqlx", "leptos/ssr", "leptos_meta/ssr", "leptos_router/ssr", "leptos_axum"]
|
||||
|
||||
[package.metadata.cargo-all-features]
|
||||
denylist = [
|
||||
@@ -72,9 +63,9 @@ 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.css"
|
||||
# [Optional] Files in the asset-dir will be copied to the site-root directory
|
||||
# assets-dir = "static/assets"
|
||||
assets-dir = "public"
|
||||
# The IP and port (ex: 127.0.0.1:3000) where the server serves the content. Use it in your server setup.
|
||||
site-address = "127.0.0.1:3000"
|
||||
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.
|
||||
@@ -103,4 +94,4 @@ 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-default-features = false
|
||||
|
||||
4
examples/todo_app_sqlite_axum/Makefile.toml
Normal file
@@ -0,0 +1,4 @@
|
||||
[tasks.build]
|
||||
command = "cargo"
|
||||
args = ["+nightly", "build-all-features"]
|
||||
install_crate = "cargo-all-features"
|
||||
@@ -17,6 +17,9 @@ cargo install --locked cargo-leptos
|
||||
```bash
|
||||
cargo leptos watch
|
||||
```
|
||||
|
||||
Open browser on [http://localhost:3000/](http://localhost:3000/)
|
||||
|
||||
3. When ready to deploy, run
|
||||
```bash
|
||||
cargo leptos build --release
|
||||
@@ -25,7 +28,7 @@ cargo leptos build --release
|
||||
## Server Side Rendering without cargo-leptos
|
||||
To run it as a server side app with hydration, you'll need to have wasm-pack installed.
|
||||
|
||||
0. Edit the `[package.metadata.leptos]` section and set `site-root` to `"pkg"`. You'll also want to change the path of the `<StyleSheet / >` component in the root component to point towards the CSS file in the root. This tells leptos that the WASM/JS files generated by wasm-pack are available at `./pkg` and that the CSS files are no longer processed by cargo-leptos. Building to alternative folders is not supported at this time
|
||||
0. Edit the `[package.metadata.leptos]` section and set `site-root` to `"."`. You'll also want to change the path of the `<StyleSheet / >` component in the root component to point towards the CSS file in the root. This tells leptos that the WASM/JS files generated by wasm-pack are available at `./pkg` and that the CSS files are no longer processed by cargo-leptos. Building to alternative folders is not supported at this time. You'll also want to edit the call to `get_configuration()` to pass in `Some(Cargo.toml)`, so that Leptos will read the settings instead of cargo-leptos. If you do so, your file/folder names cannot include dashes.
|
||||
1. Install wasm-pack
|
||||
```bash
|
||||
cargo install wasm-pack
|
||||
|
||||
BIN
examples/todo_app_sqlite_axum/public/favicon.ico
Normal file
|
After Width: | Height: | Size: 15 KiB |