Compare commits

..

10 commits

Author SHA1 Message Date
Adam
4125708354 formatting 2024-01-09 19:28:11 -05:00
Adam
a3687c62ff tidy 2024-01-06 04:35:02 -05:00
Adam
b9c37e1678 pain 2024-01-06 04:26:09 -05:00
Adam
8c39278e90 use workspaces 2024-01-05 08:30:48 -05:00
Adam
4e5d0d6560 split routes and components 2024-01-05 05:19:12 -05:00
Adam
44b90c184b whitespace 2023-12-16 19:16:48 -05:00
Adam
cd7ceca486 update deps 2023-12-16 19:16:29 -05:00
Adam
6c018420ac not needed 2023-12-16 19:16:15 -05:00
Adam
c66d40f804 point to live 2023-12-16 18:18:44 -05:00
Adam
bf1c142ae0 update deps 2023-12-16 18:18:00 -05:00
48 changed files with 4248 additions and 1208 deletions

View file

@ -1,58 +0,0 @@
# doordesk-rs
## Dev Server
```bash
cargo install cargo-leptos
```
```bash
cargo leptos watch
```
By default, `cargo-leptos` uses `nightly` Rust, `cargo-generate`, and `sass`. If you run into any trouble, you may need to install one or more of these tools.
1. `rustup toolchain install nightly --allow-downgrade` - make sure you have Rust nightly
2. `rustup target add wasm32-unknown-unknown` - add the ability to compile Rust to WebAssembly
3. `cargo install cargo-generate` - install `cargo-generate` binary (should be installed automatically in future)
4. `npm install -g sass` - install `dart-sass` (should be optional in future
## Compiling for Release
```bash
cargo leptos build --release
```
Will generate your server binary in target/server/release and your site package in target/site
## Testing Your Project
```bash
cargo leptos end-to-end
```
```bash
cargo leptos end-to-end --release
```
Cargo-leptos uses Playwright as the end-to-end test tool.
Tests are located in end2end/tests directory.
## Executing a Server on a Remote Machine Without the Toolchain
After running a `cargo leptos build --release` the minimum files needed are:
1. The server binary located in `target/server/release`
2. The `site` directory and all files within located in `target/site`
Copy these files to your remote server. The directory structure should be:
```text
start-axum
site/
```
Set the following environment variables (updating for your project as needed):
```text
LEPTOS_OUTPUT_NAME="start-axum"
LEPTOS_SITE_ROOT="site"
LEPTOS_SITE_PKG_DIR="pkg"
LEPTOS_SITE_ADDR="127.0.0.1:3000"
LEPTOS_RELOAD_PORT="3001"
```
Finally, run the server binary.

View file

@ -1,3 +0,0 @@
[toolchain]
channel = "nightly"

View file

@ -1,95 +0,0 @@
use crate::error_template::{AppError, ErrorTemplate};
use leptos::*;
use leptos_meta::*;
use leptos_router::*;
#[component]
pub fn App(cx: Scope) -> impl IntoView {
// Provides context that manages stylesheets, titles, meta tags, etc.
provide_meta_context(cx);
view! {
cx,
// injects a stylesheet into the document <head>
// id=leptos means cargo-leptos will hot-reload this stylesheet
<Stylesheet id="leptos" href="/pkg/doordesk.css"/>
// sets the document title
<Title text="DoorDesk"/>
// content for this welcome page
<Router fallback=|cx| {
let mut outside_errors = Errors::default();
outside_errors.insert_with_default_key(AppError::NotFound);
view! { cx,
<ErrorTemplate outside_errors/>
}
.into_view(cx)
}>
<nav class="bg-gradient-to-b from-zinc-800 to-zinc-900 shadow-lg sticky top-0">
<ul class="container flex items-center p-3">
<li class="mx-1.5 sm:mx-6">
"DoorDesk"
</li>
<li class="mx-1.5 sm:mx-6">
<A href="" exact=true>"Home"</A>
</li>
<li class="mx-1.5 sm:mx-6">
<A href="/blog">"Blog"</A>
</li>
<li class="mx-1.5 sm:mx-6">
<A href="/projects">"Projects"</A>
</li>
</ul>
</nav>
<main>
<Routes>
<Route path="/" view=|cx| view! { cx, <Home /> }/>
<Route path="/blog" view=|cx| view! { cx, <Blog /> }/>
<Route path="/projects" view=|cx| view! { cx, <Projects /> }/>
</Routes>
</main>
<p class="text-center hover:rotate-180 duration-200 w-8 m-auto"><a href="https://open.spotify.com/playlist/3JRNw9gpt1w5ptsw8uDeYc?si=8f7e4191113f41f9">":)"</a></p><br />
</Router>
}
}
/// Renders the home page of your application.
#[component]
fn Article(cx: Scope) -> impl IntoView {
let (count, set_count) = create_signal(cx, 0);
let on_click = move |_| set_count.update(|count| *count += 1);
view! { cx,
<article class="bg-zinc-700 mx-auto p-7 my-5 w-11/12 max-w-screen-xl rounded-md shadow-1g bg-opacity-10">
<h1 class="max-6-xs text-3xl text-orange-600 font-light capitalize">"ayo"</h1>
<hr class="opacity-50" />
<span class="opacity-50 text-xs pt-0 m-t pb-3.5">"today"</span>
<div>
<button on:click=on_click>"Click Me: " {count}</button>
</div>
</article>
}
}
#[component]
fn Home(cx: Scope) -> impl IntoView {
view! { cx,
<Article />
}
}
#[component]
fn Blog(cx: Scope) -> impl IntoView {
view! { cx,
<Article />
}
}
#[component]
fn Projects(cx: Scope) -> impl IntoView {
view! { cx,
<Article />
}
}

View file

@ -1,40 +0,0 @@
use cfg_if::cfg_if;
cfg_if! { if #[cfg(feature = "ssr")] {
use axum::{
body::{boxed, Body, BoxBody},
extract::State,
response::IntoResponse,
http::{Request, Response, StatusCode, Uri},
};
use axum::response::Response as AxumResponse;
use tower::ServiceExt;
use tower_http::services::ServeDir;
use leptos::*;
use crate::app::App;
pub async fn file_and_error_handler(uri: Uri, State(options): State<LeptosOptions>, req: Request<Body>) -> AxumResponse {
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(), move |cx| view!{cx, <App/>});
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();
// `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).oneshot(req).await {
Ok(res) => Ok(res.map(boxed)),
Err(err) => Err((
StatusCode::INTERNAL_SERVER_ERROR,
format!("Something went wrong: {err}"),
)),
}
}
}}

View file

@ -1,21 +0,0 @@
use cfg_if::cfg_if;
pub mod app;
pub mod error_template;
pub mod fileserv;
cfg_if! { if #[cfg(feature = "hydrate")] {
use leptos::*;
use wasm_bindgen::prelude::wasm_bindgen;
use crate::app::*;
#[wasm_bindgen]
pub fn hydrate() {
// initializes logging using the `log` crate
_ = console_log::init_with_level(log::Level::Debug);
console_error_panic_hook::set_once();
leptos::mount_to_body(move |cx| {
view! { cx, <App/> }
});
}
}}

View file

@ -1,8 +0,0 @@
use leptos::{component, view, IntoView, Scope};
#[component]
pub fn Home(cx: Scope) -> impl IntoView {
view! { cx,
<Article />
}
}

View file

@ -1,4 +0,0 @@
body {
font-family: sans-serif;
text-align: center;
}

View file

@ -2,7 +2,6 @@
# will have compiled files and executables # will have compiled files and executables
/target/ /target/
pkg pkg
Cargo.lock
# These are backup files generated by rustfmt # These are backup files generated by rustfmt
**/*.rs.bk **/*.rs.bk
@ -12,4 +11,3 @@ node_modules/
test-results/ test-results/
end2end/playwright-report/ end2end/playwright-report/
playwright/.cache/ playwright/.cache/
.sass-cache

2754
doordesk/Cargo.lock generated Normal file

File diff suppressed because it is too large Load diff

View file

@ -1,51 +1,45 @@
[package] [workspace]
name = "doordesk" resolver = "2"
version = "0.1.0" members = ["app", "frontend", "server"]
edition = "2021"
[lib] # need to be applied only to wasm build
crate-type = ["cdylib", "rlib"] [profile.release]
codegen-units = 1
lto = true
opt-level = 'z'
[dependencies] [workspace.dependencies]
axum = { version = "0.6.4", optional = true } leptos = { version = "0.5", features = ["nightly"] }
console_error_panic_hook = "0.1" leptos_meta = { version = "0.5", features = ["nightly"] }
console_log = "1" leptos_router = { version = "0.5", features = ["nightly"] }
leptos_axum = { version = "0.5" }
axum = "0.6.20"
cfg-if = "1" cfg-if = "1"
leptos = { version = "0.4", features = ["nightly"] } console_error_panic_hook = "0.1.7"
leptos_axum = { version = "0.4", optional = true } console_log = "1"
leptos_meta = { version = "0.4", features = ["nightly"] } http = "0.2.9"
leptos_router = { version = "0.4", features = ["nightly"] } log = "0.4.20"
log = "0.4" simple_logger = "4.2.0"
simple_logger = "4" thiserror = "1"
tokio = { version = "1.25.0", optional = true } tokio = { version = "1.33.0", features = ["full"] }
tower = { version = "0.4.13", optional = true } tower = { version = "0.4.13", features = ["full"] }
tower-http = { version = "0.4", features = ["fs"], optional = true } tower-http = { version = "0.4", features = ["full"] }
wasm-bindgen = "=0.2.87" wasm-bindgen = "=0.2.89"
thiserror = "1.0.38"
tracing = { version = "0.1.37", optional = true }
http = "0.2.8"
[features] # See https://github.com/akesson/cargo-leptos for documentation of all the parameters.
hydrate = ["leptos/hydrate", "leptos_meta/hydrate", "leptos_router/hydrate"]
ssr = [
"dep:axum",
"dep:tokio",
"dep:tower",
"dep:tower-http",
"dep:leptos_axum",
"leptos/ssr",
"leptos_meta/ssr",
"leptos_router/ssr",
"dep:tracing",
]
[package.metadata.cargo-all-features] # A leptos project defines which workspace members
denylist = ["axum", "tokio", "tower", "tower-http", "leptos_axum"] # that are used together frontend (lib) & server (bin)
skip_feature_sets = [["ssr", "hydrate"]] [[workspace.metadata.leptos]]
# this name is used for the wasm, js and css file names
name = "doordesk"
[package.metadata.leptos] # the package in the workspace that contains the server binary (binary crate)
# The name used by wasm-bindgen/cargo-leptos for the JS/WASM bundle. Defaults to the crate name bin-package = "server"
output-name = "doordesk"
# the package in the workspace that contains the frontend wasm binary (library crate)
lib-package = "frontend"
# 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. # 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" site-root = "target/site"
@ -55,7 +49,7 @@ site-root = "target/site"
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 # [Optional] The source CSS file. If it ends with .sass or .scss then it will be compiled by dart-sass into CSS. The CSS is optimized by Lightning CSS before being written to <site-root>/<site-pkg>/app.css
style-file = "style/main.scss" # style-file = "style/main.scss"
# The tailwind input file. # The tailwind input file.
# #
@ -98,7 +92,7 @@ env = "DEV"
# The features to use when compiling the bin target # The features to use when compiling the bin target
# #
# Optional. Can be over-ridden with the command line parameter --bin-features # Optional. Can be over-ridden with the command line parameter --bin-features
bin-features = ["ssr"] bin-features = []
# If the --no-default-features flag should be used when compiling the bin target # If the --no-default-features flag should be used when compiling the bin target
# #
@ -108,7 +102,7 @@ bin-default-features = false
# The features to use when compiling the lib target # The features to use when compiling the lib target
# #
# Optional. Can be over-ridden with the command line parameter --lib-features # Optional. Can be over-ridden with the command line parameter --lib-features
lib-features = ["hydrate"] lib-features = []
# If the --no-default-features flag should be used when compiling the lib target # If the --no-default-features flag should be used when compiling the lib target
# #

87
doordesk/README.md Normal file
View file

@ -0,0 +1,87 @@
<picture>
<source srcset="https://raw.githubusercontent.com/leptos-rs/leptos/main/docs/logos/Leptos_logo_Solid_White.svg" media="(prefers-color-scheme: dark)">
<img src="https://raw.githubusercontent.com/leptos-rs/leptos/main/docs/logos/Leptos_logo_RGB.svg" alt="Leptos Logo">
</picture>
# Leptos Axum Starter Template
This is a template for use with the [Leptos](https://github.com/leptos-rs/leptos) web framework and the [cargo-leptos](https://github.com/akesson/cargo-leptos) tool using [Axum](https://github.com/tokio-rs/axum).
## Creating your template repo
If you don't have `cargo-leptos` installed you can install it with
```bash
cargo install cargo-leptos
```
Then run
```bash
cargo leptos new --git https://github.com/leptos-rs/start-axum-workspace/
```
to generate a new project template.
```bash
cd {projectname}
```
to go to your newly created project.
Feel free to explore the project structure, but the best place to start with your application code is in `src/app.rs`.
Addtionally, Cargo.toml may need updating as new versions of the dependencies are released, especially if things are not working after a `cargo update`.
## Running your project
```bash
cargo leptos watch
```
## Installing Additional Tools
By default, `cargo-leptos` uses `nightly` Rust, `cargo-generate`, and `sass`. If you run into any trouble, you may need to install one or more of these tools.
1. `rustup toolchain install nightly --allow-downgrade` - make sure you have Rust nightly
2. `rustup default nightly` - setup nightly as default, or you can use rust-toolchain file later on
3. `rustup target add wasm32-unknown-unknown` - add the ability to compile Rust to WebAssembly
4. `cargo install cargo-generate` - install `cargo-generate` binary (should be installed automatically in future)
5. `npm install -g sass` - install `dart-sass` (should be optional in future
## Compiling for Release
```bash
cargo leptos build --release
```
Will generate your server binary in target/server/release and your site package in target/site
## Testing Your Project
```bash
cargo leptos end-to-end
```
```bash
cargo leptos end-to-end --release
```
Cargo-leptos uses Playwright as the end-to-end test tool.
Tests are located in end2end/tests directory.
## Executing a Server on a Remote Machine Without the Toolchain
After running a `cargo leptos build --release` the minimum files needed are:
1. The server binary located in `target/server/release`
2. The `site` directory and all files within located in `target/site`
Copy these files to your remote server. The directory structure should be:
```text
start-axum
site/
```
Set the following enviornment variables (updating for your project as needed):
```text
LEPTOS_OUTPUT_NAME="start-axum"
LEPTOS_SITE_ROOT="site"
LEPTOS_SITE_PKG_DIR="pkg"
LEPTOS_SITE_ADDR="127.0.0.1:3000"
LEPTOS_RELOAD_PORT="3001"
```
Finally, run the server binary.

23
doordesk/app/Cargo.toml Normal file
View file

@ -0,0 +1,23 @@
[package]
name = "app"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
leptos.workspace = true
leptos_meta.workspace = true
leptos_router.workspace = true
leptos_axum = { workspace = true, optional = true }
http.workspace = true
cfg-if.workspace = true
thiserror.workspace = true
serde = "1.0.195"
[features]
default = []
hydrate = ["leptos/hydrate", "leptos_meta/hydrate", "leptos_router/hydrate"]
ssr = ["leptos/ssr", "leptos_meta/ssr", "leptos_router/ssr", "dep:leptos_axum"]

View file

@ -0,0 +1,2 @@
pub mod article;
pub mod slingshot;

View file

@ -0,0 +1,42 @@
use crate::components::slingshot::*;
use leptos::*;
#[component]
pub fn Article() -> impl IntoView {
let data = create_resource(
|| (),
|_| async move {
logging::log!("loading data from slingshot");
slingshot().await
},
);
view! {
<Transition>
<article class="p-7 my-5 mx-auto w-11/12 max-w-screen-xl bg-opacity-10 rounded-md bg-zinc-700 shadow-1g">
<h1 class="text-3xl font-light text-orange-600 capitalize max-6-xs">
{move || match data.get() {
None => "Loading...".to_string(),
Some(data) => data.unwrap().title,
}}
</h1>
<hr class="opacity-50"/>
<span class="pt-0 pb-3.5 text-xs opacity-50 m-t">
{move || match data.get() {
None => "Loading...".to_string(),
Some(data) => data.unwrap().date,
}}
</span>
<div>
{move || match data.get() {
None => "Loading...".to_string(),
Some(data) => data.unwrap().content,
}}
</div>
</article>
</Transition>
}
}

View file

@ -0,0 +1,22 @@
use leptos::*;
use serde::{Serialize, Deserialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ArticleData {
pub content_type: String,
pub title: String,
pub date: String, // make datetime?
pub content: String,
}
#[server(Slingshot)]
pub async fn slingshot() -> Result<ArticleData, ServerFnError> {
let data = ArticleData {
content_type: String::from("Blog"),
title: String::from("Test article"),
date: String::from("12/21/2022"),
content: String::from("Testicles"),
};
Ok(data)
}

View file

@ -24,19 +24,18 @@ impl AppError {
// Feel free to do more complicated things here than just displaying the error. // Feel free to do more complicated things here than just displaying the error.
#[component] #[component]
pub fn ErrorTemplate( pub fn ErrorTemplate(
cx: Scope,
#[prop(optional)] outside_errors: Option<Errors>, #[prop(optional)] outside_errors: Option<Errors>,
#[prop(optional)] errors: Option<RwSignal<Errors>>, #[prop(optional)] errors: Option<RwSignal<Errors>>,
) -> impl IntoView { ) -> impl IntoView {
let errors = match outside_errors { let errors = match outside_errors {
Some(e) => create_rw_signal(cx, e), Some(e) => create_rw_signal(e),
None => match errors { None => match errors {
Some(e) => e, Some(e) => e,
None => panic!("No Errors found and we expected errors!"), None => panic!("No Errors found and we expected errors!"),
}, },
}; };
// Get Errors from Signal // Get Errors from Signal
let errors = errors.get(); let errors = errors.get_untracked();
// Downcast lets us take a type that implements `std::error::Error` // Downcast lets us take a type that implements `std::error::Error`
let errors: Vec<AppError> = errors let errors: Vec<AppError> = errors
@ -48,32 +47,26 @@ pub fn ErrorTemplate(
// Only the response code for the first error is actually sent from the server // Only the response code for the first error is actually sent from the server
// this may be customized by the specific application // this may be customized by the specific application
cfg_if! { if #[cfg(feature="ssr")] { cfg_if! { if #[cfg(feature="ssr")] {
let response = use_context::<ResponseOptions>(cx); let response = use_context::<ResponseOptions>();
if let Some(response) = response { if let Some(response) = response {
response.set_status(errors[0].status_code()); response.set_status(errors[0].status_code());
} }
}} }}
view! {cx, view! {
<h1>{if errors.len() > 1 {"Errors"} else {"Error"}}</h1> <h1>{if errors.len() > 1 { "Errors" } else { "Error" }}</h1>
<For <For
// a function that returns the items we're iterating over; a signal is fine // a function that returns the items we're iterating over; a signal is fine
each= move || {errors.clone().into_iter().enumerate()} each=move || { errors.clone().into_iter().enumerate() }
// a unique key for each item as a reference // a unique key for each item as a reference
key=|(index, _error)| *index key=|(index, _error)| *index
// renders each item to a view // renders each item to a view
view= move |cx, error| { children=move |error| {
let error_string = error.1.to_string(); let error_string = error.1.to_string();
let error_code= error.1.status_code(); let error_code = error.1.status_code();
view! { view! {
cx, <h2>{error_code.to_string()}</h2>
<article class="bg-zinc-700 mx-auto p-7 my-5 w-11/12 max-w-screen-xl rounded-md shadow-1g bg-opacity-10"> <p>"Error: " {error_string}</p>
<h1 class="max-6-xs text-3xl text-orange-600 font-light capitalize">
{error_code.to_string()}
</h1>
<hr class="opacity-50" />
<p>"Error: " {error_string}</p>
</article>
} }
} }
/> />

62
doordesk/app/src/lib.rs Normal file
View file

@ -0,0 +1,62 @@
use crate::error_template::{AppError, ErrorTemplate};
//use crate::routes::{blog::*, home::*, projects::*};
use leptos::*;
use leptos_meta::*;
use leptos_router::*;
pub mod error_template;
pub mod components;
pub mod routes;
use crate::routes::{home::*, blog::*, projects::*};
#[component]
pub fn App() -> impl IntoView {
// Provides context that manages stylesheets, titles, meta tags, etc.
provide_meta_context();
view! {
<Stylesheet id="leptos" href="/pkg/doordesk.css"/>
// sets the document title
<Title text="doordesk"/>
// content for this welcome page
<Router fallback=|| {
let mut outside_errors = Errors::default();
outside_errors.insert_with_default_key(AppError::NotFound);
view! { <ErrorTemplate outside_errors/> }.into_view()
}>
<nav class="bg-gradient-to-b from-zinc-800 to-zinc-900 shadow-lg sticky top-0">
<ul class="container flex items-center p-3">
<li class="mx-1.5 sm:mx-6">"DoorDesk"</li>
<li class="mx-1.5 sm:mx-6">
<A href="" exact=true>
"Home"
</A>
</li>
<li class="mx-1.5 sm:mx-6">
<A href="/blog">"Blog"</A>
</li>
<li class="mx-1.5 sm:mx-6">
<A href="/projects">"Projects"</A>
</li>
</ul>
</nav>
<main>
<Routes>
<Route path="" view=Home/>
<Route path="blog" view=Blog/>
<Route path="projects" view=Projects/>
</Routes>
</main>
<p class="text-center hover:rotate-180 duration-200 w-8 m-auto">
<a href="https://open.spotify.com/playlist/3JRNw9gpt1w5ptsw8uDeYc?si=8f7e4191113f41f9">
":)"
</a>
</p>
<br/>
</Router>
}
}

View file

@ -0,0 +1,3 @@
pub mod home;
pub mod blog;
pub mod projects;

View file

@ -0,0 +1,7 @@
use crate::components::article::*;
use leptos::*;
#[component]
pub fn Blog() -> impl IntoView {
view! { <Article/> }
}

View file

@ -0,0 +1,7 @@
use crate::components::article::*;
use leptos::*;
#[component]
pub fn Home() -> impl IntoView {
view! { <Article/> }
}

View file

@ -0,0 +1,7 @@
use crate::components::article::*;
use leptos::*;
#[component]
pub fn Projects() -> impl IntoView {
view! { <Article/> }
}

View file

@ -0,0 +1,18 @@
[package]
name = "frontend"
version = "0.1.0"
edition = "2021"
[lib]
crate-type = ["cdylib", "rlib"]
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
app = { path = "../app", default-features = false, features = ["hydrate"] }
leptos = { workspace = true, features = [ "hydrate" ] }
console_error_panic_hook.workspace = true
console_log.workspace = true
log.workspace = true
wasm-bindgen.workspace = true

View file

@ -0,0 +1,12 @@
use app::*;
use leptos::*;
use wasm_bindgen::prelude::wasm_bindgen;
#[wasm_bindgen]
pub fn hydrate() {
// initializes logging using the `log` crate
_ = console_log::init_with_level(log::Level::Debug);
console_error_panic_hook::set_once();
leptos::mount_to_body(App);
}

View file

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

View file

Before

Width:  |  Height:  |  Size: 38 KiB

After

Width:  |  Height:  |  Size: 38 KiB

View file

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 10 KiB

View file

Before

Width:  |  Height:  |  Size: 685 B

After

Width:  |  Height:  |  Size: 685 B

View file

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

View file

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

View file

@ -0,0 +1,2 @@
[toolchain]
channel = "nightly"

1
doordesk/rustfmt.toml Normal file
View file

@ -0,0 +1 @@
edition = "2021"

View file

@ -0,0 +1,18 @@
[package]
name = "server"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
app = { path = "../app", default-features = false, features = ["ssr"] }
leptos = { workspace = true, features = [ "ssr" ]}
leptos_axum.workspace = true
axum.workspace = true
simple_logger.workspace = true
tokio.workspace = true
tower.workspace = true
tower-http.workspace = true
log.workspace = true

View file

@ -0,0 +1,46 @@
use app::error_template::AppError;
use app::error_template::ErrorTemplate;
use app::App;
use axum::response::Response as AxumResponse;
use axum::{
body::{boxed, Body, BoxBody},
extract::State,
http::{Request, Response, StatusCode, Uri},
response::IntoResponse,
};
use leptos::*;
use tower::ServiceExt;
use tower_http::services::ServeDir;
pub async fn file_and_error_handler(
uri: Uri,
State(options): State<LeptosOptions>,
req: Request<Body>,
) -> AxumResponse {
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(), move || view! { <App/> });
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();
// `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).oneshot(req).await {
Ok(res) => Ok(res.map(boxed)),
Err(err) => Err((
StatusCode::INTERNAL_SERVER_ERROR,
format!("Something went wrong: {err}"),
)),
}
}

View file

@ -1,12 +1,13 @@
#[cfg(feature = "ssr")] use app::*;
use axum::{routing::post, Router};
use fileserv::file_and_error_handler;
use leptos::*;
use leptos_axum::{generate_route_list, LeptosRoutes};
pub mod fileserv;
#[tokio::main] #[tokio::main]
async fn main() { async fn main() {
use axum::{routing::post, Router};
use leptos::*;
use leptos_axum::{generate_route_list, LeptosRoutes};
use doordesk::app::*;
use doordesk::fileserv::file_and_error_handler;
simple_logger::init_with_level(log::Level::Debug).expect("couldn't initialize logging"); simple_logger::init_with_level(log::Level::Debug).expect("couldn't initialize logging");
// Setting get_configuration(None) means we'll be using cargo-leptos's env values // Setting get_configuration(None) means we'll be using cargo-leptos's env values
@ -17,27 +18,20 @@ async fn main() {
let conf = get_configuration(None).await.unwrap(); let conf = get_configuration(None).await.unwrap();
let leptos_options = conf.leptos_options; let leptos_options = conf.leptos_options;
let addr = leptos_options.site_addr; let addr = leptos_options.site_addr;
let routes = generate_route_list(|cx| view! { cx, <App/> }).await; let routes = generate_route_list(App);
// build our application with a route // build our application with a route
let app = Router::new() let app = Router::new()
.route("/api/*fn_name", post(leptos_axum::handle_server_fns)) .route("/api/*fn_name", post(leptos_axum::handle_server_fns))
.leptos_routes(&leptos_options, routes, |cx| view! { cx, <App/> }) .leptos_routes(&leptos_options, routes, App)
.fallback(file_and_error_handler) .fallback(file_and_error_handler)
.with_state(leptos_options); .with_state(leptos_options);
// run our app with hyper // run our app with hyper
// `axum::Server` is a re-export of `hyper::Server` // `axum::Server` is a re-export of `hyper::Server`
log!("listening on http://{}", &addr); log::info!("listening on http://{}", &addr);
axum::Server::bind(&addr) axum::Server::bind(&addr)
.serve(app.into_make_service()) .serve(app.into_make_service())
.await .await
.unwrap(); .unwrap();
} }
#[cfg(not(feature = "ssr"))]
pub fn main() {
// no client-side main function
// unless we want this to work with e.g., Trunk for a purely client-side app
// see lib.rs for hydration function instead
}

View file

@ -2,11 +2,11 @@
module.exports = { module.exports = {
content: { content: {
relative: true, relative: true,
files: ["*.html", "./src/**/*.rs"], files: ["*.html", "./app/**/*.rs"],
}, },
theme: { theme: {
extend: {}, extend: {},
}, },
plugins: [], plugins: [],
} }

View file

@ -7,19 +7,19 @@
}, },
"type": "module", "type": "module",
"devDependencies": { "devDependencies": {
"autoprefixer": "^10.4.14", "autoprefixer": "^10.4.16",
"postcss": "^8.4.24", "postcss": "^8.4.32",
"solid-start-node": "^0.2.26", "solid-start-node": "^0.2.32",
"tailwindcss": "^3.3.2", "tailwindcss": "^3.3.6",
"typescript": "^4.9.5", "typescript": "^4.9.5",
"vite": "^4.3.9" "vite": "^4.5.1"
}, },
"dependencies": { "dependencies": {
"@solidjs/meta": "^0.28.5", "@solidjs/meta": "^0.28.7",
"@solidjs/router": "^0.8.2", "@solidjs/router": "^0.8.4",
"solid-js": "^1.7.7", "solid-js": "^1.8.7",
"solid-start": "^0.2.26", "solid-start": "^0.2.32",
"undici": "^5.22.1" "undici": "^5.28.2"
}, },
"engines": { "engines": {
"node": ">=16" "node": ">=16"

1947
frontend/pnpm-lock.yaml generated

File diff suppressed because it is too large Load diff

View file

@ -16,7 +16,7 @@ import {
import "./root.css"; import "./root.css";
export const DENNIS = "http://localhost:9696"; export const DENNIS = "https://dennis.doordesk.net";
export default function Root() { export default function Root() {