Ajouter des fichiers et des modifications existants

This commit is contained in:
Pierre Berthe 2024-02-29 11:24:22 +01:00
commit 4ea514650d
13 changed files with 1481 additions and 0 deletions

4
.gitignore vendored Normal file
View file

@ -0,0 +1,4 @@
/target
/node_modules
pnpm-lock.yaml
/assets

1234
Cargo.lock generated Normal file

File diff suppressed because it is too large Load diff

17
Cargo.toml Normal file
View file

@ -0,0 +1,17 @@
[package]
name = "fastmx"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
askama = { version = "0.12.1", features = ["with-axum"] }
askama_axum = "0.4.0"
axum = { version = "0.7.4", features = ["macros", "form"] }
serde = { version = "1.0.197", features = ["derive"] }
tokio = { version = "1.36.0", features = ["full"] }
tower = "0.4.13"
tower-http = { version = "0.5.2", features = ["fs"] }
tracing = "0.1.40"
tracing-subscriber = { version = "0.3.18", features = ["env-filter"] }

11
README.md Normal file
View file

@ -0,0 +1,11 @@
## To generate the stylesheet, run the following command:
```bash
pnpm dlx tailwindcss -i styles/tailwind.css -o assets/main.css
```
## To launch the server, run the following command:
```bash
cargo run --release
```

13
package.json Normal file
View file

@ -0,0 +1,13 @@
{
"name": "fastmx",
"version": "1.0.0",
"license": "ISC",
"devDependencies": {
"prettier": "^2.8.8",
"prettier-plugin-tailwindcss": "^0.3.0",
"tailwindcss": "^3.4.1"
},
"dependencies": {
"@tailwindcss/forms": "^0.5.7"
}
}

108
src/main.rs Normal file
View file

@ -0,0 +1,108 @@
use std::sync::Arc;
use askama::Template;
use axum::{
debug_handler,
extract::State,
response::IntoResponse,
routing::{get, post},
Form, Router,
};
use serde::Deserialize;
use tokio::{net::TcpListener, sync::Mutex};
use tower_http::services::ServeDir;
use tracing::info;
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
#[warn(clippy::all)]
#[warn(clippy::pedantic)]
#[tokio::main]
async fn main() {
tracing_subscriber::registry()
.with(
tracing_subscriber::EnvFilter::try_from_default_env()
.unwrap_or_else(|_| "fastmx=info".into()),
)
.with(tracing_subscriber::fmt::layer())
.init();
let pwd = std::env::current_dir().unwrap();
let todo_state = Arc::new(TodoState {
todos: Mutex::new(Vec::new()),
});
let api_router = Router::new()
.route("/hello", get(hello_from_the_server))
.route("/todos", post(add_todo))
.with_state(todo_state);
let router = Router::new()
.nest("/api", api_router)
.route("/", get(hello))
.route("/another-page", get(another_page))
.nest_service(
"/assets",
ServeDir::new(format!("{}/assets", pwd.to_str().unwrap())),
);
let listener = get_listener().await;
info!("listening on http://{}", listener.local_addr().unwrap());
axum::serve(listener, router).await.unwrap();
}
async fn get_listener() -> TcpListener {
let mut port = 3000;
loop {
match TcpListener::bind(format!("0.0.0.0:{port}")).await {
Ok(listener) => return listener,
Err(_) => port += 1,
}
}
}
async fn hello() -> impl IntoResponse {
HelloTemplate {}
}
async fn another_page() -> impl IntoResponse {
AnotherPageTemplate {}
}
async fn hello_from_the_server() -> impl IntoResponse {
"Hello from the server"
}
#[debug_handler]
async fn add_todo(
State(todo_state): State<Arc<TodoState>>,
Form(todo): Form<TodoRequest>,
) -> impl IntoResponse {
todo_state.todos.lock().await.push(todo.name);
TodoListTemplate {
todos: todo_state.todos.lock().await.clone(),
}
}
#[derive(Deserialize, Debug)]
struct TodoRequest {
name: String,
}
#[derive(Template)]
#[template(path = "hello.html")]
struct HelloTemplate {}
#[derive(Template)]
#[template(path = "another-page.html")]
struct AnotherPageTemplate {}
#[derive(Template)]
#[template(path = "todo-list.html")]
struct TodoListTemplate {
todos: Vec<String>,
}
struct TodoState {
todos: Mutex<Vec<String>>,
}

3
styles/tailwind.css Normal file
View file

@ -0,0 +1,3 @@
@tailwind base;
@tailwind components;
@tailwind utilities;

14
tailwind.config.cjs Normal file
View file

@ -0,0 +1,14 @@
const { fontFamily } = require("tailwindcss/defaultTheme");
/** @type {import('tailwindcss').Config} */
module.exports = {
content: ["./templates/*.html"],
theme: {
extend: {
fontFamily: {
sans: ["Inter var", ...fontFamily.sans],
},
},
},
plugins: [require("@tailwindcss/forms")],
};

View file

@ -0,0 +1,9 @@
<!-- prettier-ignore -->
{% extends "base.html" %}
{% block title %}Another page!{% endblock %}
{% block content %}
<a href="/"> Main page </a>
<h1 class="font-bold text-indigo-500">Another page</h1>
{% endblock %}

21
templates/base.html Normal file
View file

@ -0,0 +1,21 @@
<!DOCTYPE html>
<html lang="en">
<head>
<link href="/assets/main.css" rel="stylesheet" />
<link href="https://rsms.me/inter/inter.css" rel="stylesheet" />
<!-- Allow any inheriting page to set it's own title -->
<title>{% block title %}{{ title }}{% endblock %}</title>
<!-- htmx from the unpkg CDN - your mileage may vary -->
<script src="https://unpkg.com/htmx.org@1.9.10"></script>
<!-- Allow any inheriting page to extend head with additional assets -->
{% block head %}{% endblock %}
</head>
<body hx-boost="true">
<div id="content">
<!-- Inheriting pages will have their content rendered here, similar to app root in React, Angular, etc. -->
{% block content %}{% endblock %}
</div>
</body>
</html>

24
templates/hello.html Normal file
View file

@ -0,0 +1,24 @@
<!-- prettier-ignore -->
{% extends "base.html" %}
{% block title %}Hello!{% endblock %}
{% block content %}
<div class="inline-flex flex-row space-x-2">
<h1 class="text-green-500">Howdy!</h1>
<a
href="/another-page"
class="text-indigo-500 underline hover:text-indigo-300"
>Another page</a
>
<button
type="button"
hx-get="/api/hello"
hx-swap="innerHtml"
class="rounded-md bg-indigo-600 px-2.5 py-1.5 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600"
>
Say hello
</button>
</div>
{% include "todo-form.html" %} {% endblock %}

20
templates/todo-form.html Normal file
View file

@ -0,0 +1,20 @@
<form hx-post="/api/todos" hx-target="#todos" class="max-w-md">
<label for="todo" class="block text-sm font-medium leading-6 text-gray-900"
>Todo</label
>
<div class="mt-2 inline-flex flex-row space-x-2">
<input
type="text"
name="name"
class="block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
placeholder="Replace frontend with htmx"
/>
<button
type="submit"
class="rounded-md bg-indigo-600 px-2.5 py-1.5 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600"
>
Add
</button>
</div>
</form>
<div id="todos"></div>

3
templates/todo-list.html Normal file
View file

@ -0,0 +1,3 @@
{% for todo in todos %}
<p class="text-lg">{{ todo }}</p>
{% endfor %}